ncal2gcal 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +75 -0
- data/bin/ncal2gcal +66 -0
- data/lib/ncal2gcal/google_calendar.rb +33 -0
- data/lib/ncal2gcal/lotus_notes_calendar.rb +136 -0
- data/lib/ncal2gcal/sync.rb +262 -0
- data/ncal2gcal.gemspec +31 -0
- metadata +100 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009, 2010 Elias Kugler
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
=ncal2gcal
|
2
|
+
|
3
|
+
This lib/tool syncs your IBM Lotus Notes calendar with your (private) Google calendar. The synchronisation is only one-way: Lotus Notes events are pushed to your Google Calendar. All types of events (including recurring events like anniversaries) are supported.
|
4
|
+
|
5
|
+
== Installation Instructions
|
6
|
+
|
7
|
+
gem install ncal2gcal
|
8
|
+
|
9
|
+
==Usage
|
10
|
+
|
11
|
+
Usage: ncal2gcal <command> <opts>
|
12
|
+
|
13
|
+
Commands: sync
|
14
|
+
|
15
|
+
Specific options:
|
16
|
+
-u, --notes-username USERNAME Lotus Notes user name
|
17
|
+
-p, --notes-password PASSWORD Lotus Notes password
|
18
|
+
-d, --notes-database DATABASE Lotus Notes database (.nsf file)
|
19
|
+
-U, --gmail-username USERNAME Google user name
|
20
|
+
-P, --gmail-password PASSWORD Google user password
|
21
|
+
-C, --gmail-calendar CALENDAR Google calendar (default: 'LotusNotes')
|
22
|
+
-D, --days DAYS Do not sync events older then DAYS days
|
23
|
+
--sync-desc Do sync the event description (default: no)
|
24
|
+
|
25
|
+
Example:
|
26
|
+
ncal2gcal sync -u user123 -p secret123 -d mail123.nsf -U username@gmail.com -P 123secret -C LotusNotes -D 14
|
27
|
+
|
28
|
+
Common options:
|
29
|
+
-?, --help Show this message
|
30
|
+
|
31
|
+
== Prerequisites
|
32
|
+
|
33
|
+
1. Ruby 1.8.6 or later
|
34
|
+
2. Lotus Notes
|
35
|
+
* your .nsf file must be a local copy (replica) of your mail database stored in the data-folder
|
36
|
+
of your lotus notes installation.
|
37
|
+
3. Google Account
|
38
|
+
* use your gmail-account or create a new one
|
39
|
+
* create an additional calendar for your LotusNotes Calender entries. Name it as you like
|
40
|
+
(i.e. LotusNotes) but do not use whitespaces or any other special characters.
|
41
|
+
|
42
|
+
== Supported Platforms
|
43
|
+
|
44
|
+
This library is supported on Windows 2000 or later.
|
45
|
+
|
46
|
+
==Used libs:
|
47
|
+
* gcal4ruby
|
48
|
+
* win32ole
|
49
|
+
* datamapper
|
50
|
+
* do_sqlite3
|
51
|
+
* log4r
|
52
|
+
...
|
53
|
+
|
54
|
+
== Licence/Copyright
|
55
|
+
|
56
|
+
Copyright (c) 2009, 2010 Elias Kugler
|
57
|
+
|
58
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
59
|
+
a copy of this software and associated documentation files (the
|
60
|
+
"Software"), to deal in the Software without restriction, including
|
61
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
62
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
63
|
+
permit persons to whom the Software is furnished to do so, subject to
|
64
|
+
the following conditions:
|
65
|
+
|
66
|
+
The above copyright notice and this permission notice shall be
|
67
|
+
included in all copies or substantial portions of the Software.
|
68
|
+
|
69
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
70
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
71
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
72
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
73
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
74
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
75
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/bin/ncal2gcal
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#$:.unshift '../test/mock/win32ole','../test/mock/gcal4ruby','../lib' #<< '../lib'
|
2
|
+
#$:.unshift '../test/mock/win32ole','../lib' #<< '../lib'
|
3
|
+
#$:.unshift '../lib' #<< '../lib'
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'optparse'
|
7
|
+
require 'ncal2gcal/sync'
|
8
|
+
|
9
|
+
conf = {}
|
10
|
+
opts = OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: ncal2gcal <command> <opts> "
|
12
|
+
opts.separator ""
|
13
|
+
opts.separator "Commands: sync"
|
14
|
+
opts.separator ""
|
15
|
+
opts.separator "Specific options:"
|
16
|
+
opts.on("-u", "--notes-username USERNAME", "Lotus Notes user name") { |conf[:notes_user]| }
|
17
|
+
opts.on("-p", "--notes-password PASSWORD", "Lotus Notes password") { |conf[:notes_password]| }
|
18
|
+
opts.on("-d", "--notes-database DATABASE", "Lotus Notes database (.nsf file)") { |conf[:notes_db]| }
|
19
|
+
opts.on("-U", "--gmail-username USERNAME", "Google mail user name") { |conf[:gmail_user]| }
|
20
|
+
opts.on("-P", "--gmail-password PASSWORD", "Google mail password") { |conf[:gmail_password]| }
|
21
|
+
opts.on("-C", "--gmail-calendar CALENDAR", "Google calendar (default: 'LotusNotes')") { |conf[:gmail_calendar]| }
|
22
|
+
opts.on("-D", "--days DAYS", "Do not sync events older then DAYS days (default: no limit)") { |days| conf[:days]=days.to_i }
|
23
|
+
opts.on("--sync-desc", "Do sync event description (default: no)") { conf[:sync_desc] }
|
24
|
+
opts.separator ""
|
25
|
+
opts.separator "Example:"
|
26
|
+
opts.separator " ncal2gcal sync -u user123 -p secret123 -d mail123.nsf -U username@gmail.com -P top123secret -C LotusNotes -D 14"
|
27
|
+
opts.separator ""
|
28
|
+
opts.separator "Common options:"
|
29
|
+
|
30
|
+
# No argument, shows at tail. This will print an options summary.
|
31
|
+
opts.on_tail("-?", "--help", "Show this message") do
|
32
|
+
puts opts
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on_tail("-v", "--version", "Show version") do
|
37
|
+
puts "ncal2gcal 0.1.0"
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on_tail "\n(c) 2009, 2010 Elias Kugler"
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.parse! ARGV
|
46
|
+
|
47
|
+
if defined?Ocra
|
48
|
+
exit
|
49
|
+
else
|
50
|
+
if ARGV.length != 1
|
51
|
+
puts opts
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
conf[:command] = ARGV[0]
|
55
|
+
end
|
56
|
+
|
57
|
+
# --------------------------------------------------
|
58
|
+
#
|
59
|
+
# --------------------------------------------------
|
60
|
+
if conf[:command] == 'sync'
|
61
|
+
ngsync = NCal2GCal::NotesGoogleSync.new(conf)
|
62
|
+
ngsync.sync_events
|
63
|
+
else
|
64
|
+
puts opts
|
65
|
+
exit
|
66
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'gcal4ruby'
|
3
|
+
|
4
|
+
module NCal2GCal
|
5
|
+
|
6
|
+
class GoogleCalendar
|
7
|
+
attr_accessor :user, :password, :calendar
|
8
|
+
attr_reader :events
|
9
|
+
def initialize(params)
|
10
|
+
@user = params[:gmail_user]
|
11
|
+
@password = params[:gmail_password]
|
12
|
+
@calendar = params[:gmail_calendar] || "LotusNotes"
|
13
|
+
|
14
|
+
service = GCal4Ruby::Service.new
|
15
|
+
service.authenticate(@user, @password )
|
16
|
+
@cal = GCal4Ruby::Calendar.find(service, @calendar, {:scope => :first})
|
17
|
+
end
|
18
|
+
def find_event(id)
|
19
|
+
return GCal4Ruby::Event.find(@cal, id)
|
20
|
+
end
|
21
|
+
def new_event
|
22
|
+
return GCal4Ruby::Event.new(@cal)
|
23
|
+
end
|
24
|
+
def del_event(id)
|
25
|
+
event = find_event(id)
|
26
|
+
if event
|
27
|
+
return event.delete unless event == []
|
28
|
+
end
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'win32ole'
|
2
|
+
|
3
|
+
module NCal2GCal
|
4
|
+
class EventRepeat
|
5
|
+
attr_accessor :start_time, :end_time
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
end
|
9
|
+
class LotusNotesCalendar
|
10
|
+
attr_accessor :server, :user, :password, :db
|
11
|
+
attr_reader :events
|
12
|
+
def initialize(params)
|
13
|
+
@server = params[:notes_server] || '' # local
|
14
|
+
@user = params[:notes_user]
|
15
|
+
@password = params[:notes_password]
|
16
|
+
@db = params[:notes_db]
|
17
|
+
|
18
|
+
session = WIN32OLE.new 'Lotus.NotesSession'
|
19
|
+
session.Initialize(@password)
|
20
|
+
db = session.GetDatabase(@server, @db)
|
21
|
+
raise "unable to open database: #{db}" unless db.isOpen
|
22
|
+
|
23
|
+
@events = LotusNotesEvents.new(db.GetView("$Calendar"))
|
24
|
+
raise "$Calendar View not found" unless @events
|
25
|
+
end
|
26
|
+
end
|
27
|
+
class LotusNotesEvents
|
28
|
+
def initialize(view)
|
29
|
+
@calendar_view = view
|
30
|
+
end
|
31
|
+
def each
|
32
|
+
max = 2000
|
33
|
+
count = 0
|
34
|
+
|
35
|
+
uid_list = {}
|
36
|
+
entry = @calendar_view.GetLastDocument
|
37
|
+
while entry #and count < max
|
38
|
+
begin
|
39
|
+
count +=1
|
40
|
+
if !entry.IsDeleted
|
41
|
+
event = LotusNotesEvent.new(entry)
|
42
|
+
if !uid_list[event.uid]
|
43
|
+
if event.supported?
|
44
|
+
yield(event)
|
45
|
+
else
|
46
|
+
$logger.warn "not supported appointmenttype: " + (event.appointmenttype.to_s || "appointmenttype missing")
|
47
|
+
end
|
48
|
+
uid_list[event.uid]=true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
rescue StandardError => e
|
52
|
+
print 'X'
|
53
|
+
$logger.error DateTime.now.to_s
|
54
|
+
$logger.error e
|
55
|
+
$logger.error entry
|
56
|
+
end
|
57
|
+
entry = @calendar_view.GetPrevDocument(entry)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
class LotusNotesEvent
|
62
|
+
APPOINTMENTTYPE = {'0' =>:appointment,
|
63
|
+
'1' => :anniversary,
|
64
|
+
'2' => :all_day_event,
|
65
|
+
'3' => :meeting,
|
66
|
+
'4' => :reminder}
|
67
|
+
attr_accessor :uid,
|
68
|
+
:subject,
|
69
|
+
:where,
|
70
|
+
:start_time, :end_time,
|
71
|
+
:last_modified, #
|
72
|
+
:appointmenttype,
|
73
|
+
:content,
|
74
|
+
:repeats
|
75
|
+
|
76
|
+
def initialize(notes_event)
|
77
|
+
@uid = notes_event.UniversalID
|
78
|
+
if notes_event.GetFirstItem("Subject")
|
79
|
+
@subject = notes_event.GetFirstItem("Subject").Values[0]
|
80
|
+
else
|
81
|
+
@subject = ''
|
82
|
+
$logger.warn 'no subject. uid: '+@uid
|
83
|
+
end
|
84
|
+
if notes_event.GetFirstItem("ROOM")
|
85
|
+
@where = notes_event.GetFirstItem("ROOM").Values[0]
|
86
|
+
elsif notes_event.GetFirstItem("Location")
|
87
|
+
@where = notes_event.GetFirstItem("Location").Values[0]
|
88
|
+
else
|
89
|
+
@where = ''
|
90
|
+
end
|
91
|
+
@start_time = notes_event.GetFirstItem("Startdatetime").Values[0] if notes_event.GetFirstItem("Startdatetime")
|
92
|
+
@end_time = notes_event.GetFirstItem("EndDatetime").Values[0] if notes_event.GetFirstItem("EndDatetime")
|
93
|
+
if notes_event.GetFirstItem("APPOINTMENTTYPE")
|
94
|
+
@appointmenttype = APPOINTMENTTYPE[notes_event.GetFirstItem("APPOINTMENTTYPE").Values[0]]
|
95
|
+
end
|
96
|
+
@last_modified = DateTime.parse(notes_event.LastModified)
|
97
|
+
@content = ''
|
98
|
+
body = notes_event.GetFirstItem("Body")
|
99
|
+
if body
|
100
|
+
@content = body.Values unless body.Values.is_a? Array
|
101
|
+
end
|
102
|
+
|
103
|
+
fill_repeats(notes_event)
|
104
|
+
end
|
105
|
+
def all_day?
|
106
|
+
@appointmenttype and (@appointmenttype == :all_day_event or @appointmenttype == :anniversary)
|
107
|
+
end
|
108
|
+
def supported?
|
109
|
+
# anniversaries are now (v.0.0.7) supported
|
110
|
+
@appointmenttype #and (@appointmenttype != :anniversary)
|
111
|
+
end
|
112
|
+
def repeats?
|
113
|
+
@repeats.size > 1
|
114
|
+
end
|
115
|
+
def fill_repeats(notes_event)
|
116
|
+
@repeats = []
|
117
|
+
sdts = notes_event.GetFirstItem("Startdatetime")
|
118
|
+
edts = notes_event.GetFirstItem("EndDatetime")
|
119
|
+
return unless sdts
|
120
|
+
sdts.Values.each_with_index do |val, idx |
|
121
|
+
r = EventRepeat.new
|
122
|
+
r.start_time = val
|
123
|
+
if edts
|
124
|
+
r.end_time = edts.Values[idx]
|
125
|
+
else
|
126
|
+
$logger.warn "EndDatetime default"
|
127
|
+
$logger.warn @subject
|
128
|
+
$logger.warn r.start_time
|
129
|
+
|
130
|
+
r.end_time = r.start_time
|
131
|
+
end
|
132
|
+
@repeats << r
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'log4r'
|
3
|
+
require 'uri'
|
4
|
+
require 'date'
|
5
|
+
require 'dm-core'
|
6
|
+
require 'fileutils'
|
7
|
+
require 'ncal2gcal/lotus_notes_calendar'
|
8
|
+
require 'ncal2gcal/google_calendar'
|
9
|
+
|
10
|
+
class String
|
11
|
+
def asciify()
|
12
|
+
str = self
|
13
|
+
# ----------------------------------------------------------------
|
14
|
+
# Sonderzeichenbehandlung
|
15
|
+
# ----------------------------------------------------------------
|
16
|
+
str = str.gsub(/\334/,"Ü") # �
|
17
|
+
str = str.gsub(/\374/,"ü") # �
|
18
|
+
str = str.gsub(/\326/,"Ö") # �
|
19
|
+
str = str.gsub(/\366/,"ö") # �
|
20
|
+
str = str.gsub(/\304/,"Ä") # �
|
21
|
+
str = str.gsub(/\344/,"ä") # �
|
22
|
+
str = str.gsub(/\337/,"ß") # �
|
23
|
+
# bez_neu = Iconv.conv('UTF-8','CP850', bez_neu)
|
24
|
+
#str = str.gsub(/([^\d\w\s\.\[\]-])/, '')
|
25
|
+
return str
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
module NCal2GCal
|
31
|
+
raise "environment variable %APPDATA% not set" unless ENV['APPDATA']
|
32
|
+
FileUtils::cd(ENV['APPDATA'])
|
33
|
+
FileUtils::mkdir_p('ncal2gcal')
|
34
|
+
|
35
|
+
db_file = "#{Dir.pwd}/ncal2gcal/ncal2gcal.sqlite"
|
36
|
+
DataMapper::setup(:default, "sqlite3://#{db_file}")
|
37
|
+
|
38
|
+
class Counter
|
39
|
+
attr_accessor :updates, :inserts, :deletes, :selects, :ignored, :t_start, :t_end
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@updates = 0
|
43
|
+
@inserts = 0
|
44
|
+
@deletes = 0
|
45
|
+
@selects = 0
|
46
|
+
@ignored = 0
|
47
|
+
start
|
48
|
+
end
|
49
|
+
def runtime
|
50
|
+
@t_end - @t_start
|
51
|
+
end
|
52
|
+
def start
|
53
|
+
@t_start = Time.now
|
54
|
+
end
|
55
|
+
def end
|
56
|
+
@t_end = Time.now
|
57
|
+
end
|
58
|
+
def show
|
59
|
+
puts "\nStatistics:"
|
60
|
+
puts "-"*20
|
61
|
+
puts sprintf("Inserts : %05d", @inserts)
|
62
|
+
puts sprintf("Updates : %05d", @updates)
|
63
|
+
puts sprintf("Deletes : %05d", @deletes)
|
64
|
+
puts sprintf("Ingored : %05d", @ignored)
|
65
|
+
puts "-"*20
|
66
|
+
puts sprintf("Total : %05d", @selects)
|
67
|
+
puts "Runtime : #{runtime} sec"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class NotesGoogleSync
|
72
|
+
def initialize(params)
|
73
|
+
@notes_calendar = NCal2GCal::LotusNotesCalendar.new(params)
|
74
|
+
@google_calendar = NCal2GCal::GoogleCalendar.new(params)
|
75
|
+
|
76
|
+
@sync_time = nil
|
77
|
+
if params[:days]
|
78
|
+
@min_sync_time = DateTime.now-params[:days] #*86400
|
79
|
+
end
|
80
|
+
if params[:days_max]
|
81
|
+
@max_sync_time = DateTime.now+params[:days_max] #*86400
|
82
|
+
else
|
83
|
+
@max_sync_time = DateTime.now+400 #*86400
|
84
|
+
end
|
85
|
+
@max_time = DateTime.parse("2038-01-18")
|
86
|
+
# do not sync the description unless the users wants to
|
87
|
+
@sync_desc = params[:sync_desc] # || true
|
88
|
+
|
89
|
+
init_logger
|
90
|
+
end
|
91
|
+
def init_logger
|
92
|
+
FileUtils::mkdir_p('ncal2gcal')
|
93
|
+
$logger = Log4r::Logger.new("sync_logger")
|
94
|
+
Log4r::FileOutputter.new('logfile',
|
95
|
+
:filename=>"#{Dir.pwd}/ncal2gcal/ncal2gcal.log",
|
96
|
+
:trunc=>false,
|
97
|
+
:level=>Log4r::WARN)
|
98
|
+
$logger.add('logfile')
|
99
|
+
end
|
100
|
+
def sync_events
|
101
|
+
@counter = Counter.new
|
102
|
+
@sync_time = DateTime.now
|
103
|
+
sleep(1)
|
104
|
+
|
105
|
+
@notes_calendar.events.each do |notes_event|
|
106
|
+
@counter.selects += 1
|
107
|
+
if notes_event.repeats?
|
108
|
+
notes_event.repeats.each do |r|
|
109
|
+
sync_event(notes_event, r.start_time, r.end_time, notes_event.uid+'_'+r.start_time)
|
110
|
+
end
|
111
|
+
else
|
112
|
+
#p notes_event.repeats
|
113
|
+
sync_event(notes_event, notes_event.start_time, notes_event.end_time, notes_event.uid)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
del_events()
|
117
|
+
@counter.end
|
118
|
+
return @counter
|
119
|
+
end
|
120
|
+
|
121
|
+
def sync_event(notes_event, start_time, end_time, key)
|
122
|
+
sdt = DateTime.parse(start_time)
|
123
|
+
return unless sdt < @max_time # workaround
|
124
|
+
|
125
|
+
if end_time
|
126
|
+
edt = DateTime.parse(end_time)
|
127
|
+
return unless edt < @max_time # workaround
|
128
|
+
end
|
129
|
+
|
130
|
+
#puts DateTime.parse(notes_event.end_time)
|
131
|
+
|
132
|
+
if (@min_sync_time and end_time and
|
133
|
+
@min_sync_time > DateTime.parse(end_time)) or
|
134
|
+
(@max_sync_time and start_time and
|
135
|
+
@max_sync_time < DateTime.parse(start_time))
|
136
|
+
then
|
137
|
+
@counter.ignored +=1
|
138
|
+
else
|
139
|
+
#p key
|
140
|
+
sync_entry = NCal2GCal::SyncEntry.first(:lotus_notes_uid => key)
|
141
|
+
if sync_entry
|
142
|
+
then
|
143
|
+
#puts DateTime.parse(notes_event.end_time)
|
144
|
+
#p sync_entry.lotus_notes_last_modified.to_s
|
145
|
+
#p notes_event.last_modified
|
146
|
+
if sync_entry.lotus_notes_last_modified < notes_event.last_modified
|
147
|
+
then
|
148
|
+
#!!insert_update(sync_entry,notes_event)
|
149
|
+
insert_update(sync_entry,notes_event, start_time, end_time, key)
|
150
|
+
else
|
151
|
+
print "."
|
152
|
+
@counter.ignored +=1
|
153
|
+
sync_entry.sync_time = @sync_time
|
154
|
+
sync_entry.sync_action = 'N' # none
|
155
|
+
sync_entry.save
|
156
|
+
end
|
157
|
+
else
|
158
|
+
add_event(notes_event, start_time, end_time, key)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def del_events
|
164
|
+
NCal2GCal::SyncEntry.all(:sync_time.lt => @sync_time).each do |sync_entry|
|
165
|
+
@counter.deletes += 1
|
166
|
+
if @google_calendar.del_event(sync_entry.gcal_id)
|
167
|
+
print "D"
|
168
|
+
sync_entry.destroy
|
169
|
+
else
|
170
|
+
sync_entry.sync_time = @sync_time
|
171
|
+
sync_entry.sync_action = 'E'
|
172
|
+
sync_entry.save
|
173
|
+
print "E"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
def init_google_event(notes_event,start_time,end_time)
|
178
|
+
event = @google_calendar.new_event
|
179
|
+
google_event= set_google_event_attrs(notes_event, event,start_time,end_time )
|
180
|
+
google_event.start = start_time
|
181
|
+
google_event.end = end_time
|
182
|
+
return google_event
|
183
|
+
end
|
184
|
+
def set_google_event_attrs(notes_event, google_event,start_time=nil,end_time=nil)
|
185
|
+
google_event.title = notes_event.subject.asciify if notes_event.subject
|
186
|
+
if start_time
|
187
|
+
google_event.start = start_time
|
188
|
+
else
|
189
|
+
google_event.start = notes_event.start_time
|
190
|
+
end
|
191
|
+
if end_time
|
192
|
+
google_event.end = end_time
|
193
|
+
else
|
194
|
+
google_event.end = notes_event.end_time
|
195
|
+
end
|
196
|
+
google_event.where = notes_event.where.asciify if notes_event.where
|
197
|
+
google_event.all_day = notes_event.all_day?
|
198
|
+
google_event.content = notes_event.content.asciify if @sync_desc
|
199
|
+
|
200
|
+
return google_event
|
201
|
+
end
|
202
|
+
def get_sync_entry_by_notes_uid(uid)
|
203
|
+
e1 = NCal2GCal::SyncEntry.first(:lotus_notes_uid => uid)
|
204
|
+
return e1
|
205
|
+
end
|
206
|
+
def insert_update(sync_entry,notes_event, start_time, end_time, key)
|
207
|
+
gcal_event = @google_calendar.find_event(sync_entry.gcal_id)
|
208
|
+
if gcal_event == []
|
209
|
+
$logger.warn "Event not found for update"
|
210
|
+
add_event(notes_event,start_time, end_time,key)
|
211
|
+
else
|
212
|
+
update_event(sync_entry, notes_event, gcal_event, start_time, end_time)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def add_event(notes_event, start_time, end_time, key)
|
217
|
+
print "I"
|
218
|
+
google_event=init_google_event(notes_event, start_time, end_time)
|
219
|
+
ret = google_event.save
|
220
|
+
$logger.fatal "insert: cannot save gcal event" unless ret
|
221
|
+
raise "cannot save gcal event" unless ret
|
222
|
+
@counter.inserts +=1
|
223
|
+
sync_entry = NCal2GCal::SyncEntry.new
|
224
|
+
sync_entry.lotus_notes_uid = key #notes_event.uid
|
225
|
+
sync_entry.sync_time = @sync_time
|
226
|
+
sync_entry.lotus_notes_last_modified = notes_event.last_modified
|
227
|
+
sync_entry.gcal_id = google_event.id
|
228
|
+
sync_entry.sync_action = 'I' # insert
|
229
|
+
sync_entry.save
|
230
|
+
end
|
231
|
+
def update_event(sync_entry, notes_event, gcal_event, start_time, end_time)
|
232
|
+
print "U"
|
233
|
+
@counter.updates +=1
|
234
|
+
set_google_event_attrs(notes_event, gcal_event, start_time, end_time)
|
235
|
+
ret = gcal_event.save
|
236
|
+
$logger.fatal "update: cannot save gcal event" unless ret
|
237
|
+
raise "cannot save gcal event" unless ret
|
238
|
+
sync_entry.sync_time = @sync_time
|
239
|
+
sync_entry.gcal_id = gcal_event.id
|
240
|
+
sync_entry.lotus_notes_last_modified = notes_event.last_modified
|
241
|
+
sync_entry.sync_action = 'U' # none
|
242
|
+
sync_entry.save
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
class SyncEntry
|
247
|
+
include DataMapper::Resource
|
248
|
+
#storage_names[:repo] = 'ncal2gal_sync_entries'
|
249
|
+
|
250
|
+
property :id, Serial
|
251
|
+
property :sync_time, DateTime
|
252
|
+
property :sync_action, String
|
253
|
+
|
254
|
+
property :lotus_notes_uid, Text, :index=>true
|
255
|
+
property :lotus_notes_last_modified, DateTime
|
256
|
+
property :gcal_id, Text
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
# automatically create the SyncEntry table
|
261
|
+
SyncEntry.auto_migrate! unless File.exists?(db_file) #SyncEntry.table_exists?
|
262
|
+
end
|
data/ncal2gcal.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
s.name = %q{ncal2gcal}
|
5
|
+
s.version = "0.1.3"
|
6
|
+
s.authors = ["Elias Kugler"]
|
7
|
+
s.email = %q{groesser3@gmail.com}
|
8
|
+
s.files = Dir["lib/**/*"] + Dir["bin/**/*"] + Dir["*.rb"] + ["MIT-LICENSE","ncal2gcal.gemspec"]
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.has_rdoc = true
|
11
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.summary = %q{Sync your Lotus Notes calendar with your Google calendar}
|
14
|
+
s.files.reject! { |fn| fn.include? "CVS" }
|
15
|
+
s.require_path = "lib"
|
16
|
+
s.default_executable = %q{ncal2gcal}
|
17
|
+
s.executables = ["ncal2gcal"]
|
18
|
+
s.homepage = %q{http://ncal2gcal.rubyforge.org}
|
19
|
+
s.rubyforge_project = %q{ncal2gcal}
|
20
|
+
s.add_dependency("dm-core", ">= 0.10.0")
|
21
|
+
s.add_dependency("do_sqlite3", ">= 0.10.0")
|
22
|
+
s.add_dependency("gcal4ruby", ">=0.2.8")
|
23
|
+
s.add_dependency("log4r", ">=1.0.5")
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
if $0 == __FILE__
|
29
|
+
Gem.manage_gems
|
30
|
+
Gem::Builder.new(spec).build
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ncal2gcal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elias Kugler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-29 00:00:00 +01:00
|
13
|
+
default_executable: ncal2gcal
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: dm-core
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.10.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: do_sqlite3
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.10.0
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: gcal4ruby
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.2.8
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: log4r
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.0.5
|
54
|
+
version:
|
55
|
+
description:
|
56
|
+
email: groesser3@gmail.com
|
57
|
+
executables:
|
58
|
+
- ncal2gcal
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
extra_rdoc_files:
|
62
|
+
- README.rdoc
|
63
|
+
files:
|
64
|
+
- lib/ncal2gcal/google_calendar.rb
|
65
|
+
- lib/ncal2gcal/lotus_notes_calendar.rb
|
66
|
+
- lib/ncal2gcal/sync.rb
|
67
|
+
- bin/ncal2gcal
|
68
|
+
- MIT-LICENSE
|
69
|
+
- ncal2gcal.gemspec
|
70
|
+
- README.rdoc
|
71
|
+
has_rdoc: true
|
72
|
+
homepage: http://ncal2gcal.rubyforge.org
|
73
|
+
licenses: []
|
74
|
+
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: "0"
|
85
|
+
version:
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: "0"
|
91
|
+
version:
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project: ncal2gcal
|
95
|
+
rubygems_version: 1.3.5
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: Sync your Lotus Notes calendar with your Google calendar
|
99
|
+
test_files: []
|
100
|
+
|