Diffstat (limited to 'libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp | 184 |
1 files changed, 173 insertions, 11 deletions
diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp index a4c514b..5239d84 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp | |||
@@ -1,83 +1,213 @@ | |||
1 | #include <errno.h> | 1 | #include <errno.h> |
2 | #include <fcntl.h> | 2 | #include <fcntl.h> |
3 | 3 | ||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | |||
4 | #include <sys/types.h> | 7 | #include <sys/types.h> |
5 | #include <sys/mman.h> | 8 | #include <sys/mman.h> |
6 | #include <sys/stat.h> | 9 | #include <sys/stat.h> |
7 | 10 | ||
8 | #include <unistd.h> | 11 | #include <unistd.h> |
9 | 12 | ||
10 | #include <qasciidict.h> | 13 | #include <qasciidict.h> |
11 | #include <qfile.h> | 14 | #include <qfile.h> |
12 | 15 | ||
13 | #include <qtopia/global.h> | 16 | #include <qtopia/global.h> |
14 | #include <qtopia/stringutil.h> | 17 | #include <qtopia/stringutil.h> |
18 | #include <qtopia/timeconversion.h> | ||
15 | 19 | ||
16 | #include "opimnotifymanager.h" | 20 | #include "opimnotifymanager.h" |
17 | #include "orecur.h" | 21 | #include "orecur.h" |
18 | #include "otimezone.h" | 22 | #include "otimezone.h" |
19 | #include "odatebookaccessbackend_xml.h" | 23 | #include "odatebookaccessbackend_xml.h" |
20 | 24 | ||
21 | namespace { | 25 | namespace { |
22 | time_t start, end, created, rp_end; | 26 | time_t start, end, created, rp_end; |
23 | ORecur* rec; | 27 | ORecur* rec; |
24 | ORecur* recur() { | 28 | ORecur* recur() { |
25 | if (!rec) | 29 | if (!rec) |
26 | rec = new ORecur; | 30 | rec = new ORecur; |
27 | 31 | ||
28 | return rec; | 32 | return rec; |
29 | } | 33 | } |
30 | int alarmTime; | 34 | int alarmTime; |
31 | int snd; | 35 | int snd; |
32 | enum Attribute{ | 36 | enum Attribute{ |
33 | FDescription = 0, | 37 | FDescription = 0, |
34 | FLocation, | 38 | FLocation, |
35 | FCategories, | 39 | FCategories, |
36 | FUid, | 40 | FUid, |
37 | FType, | 41 | FType, |
38 | FAlarm, | 42 | FAlarm, |
39 | FSound, | 43 | FSound, |
40 | FRType, | 44 | FRType, |
41 | FRWeekdays, | 45 | FRWeekdays, |
42 | FRPosition, | 46 | FRPosition, |
43 | FRFreq, | 47 | FRFreq, |
44 | FRHasEndDate, | 48 | FRHasEndDate, |
45 | FREndDate, | 49 | FREndDate, |
46 | FRStart, | 50 | FRStart, |
47 | FREnd, | 51 | FREnd, |
48 | FNote, | 52 | FNote, |
49 | FCreated | 53 | FCreated, |
54 | FTimeZone, | ||
55 | FRecParent, | ||
56 | FRecChildren, | ||
57 | FExceptions | ||
50 | }; | 58 | }; |
59 | inline void save( const OEvent& ev, QString& buf ) { | ||
60 | buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; | ||
61 | if (!ev.location().isEmpty() ) | ||
62 | buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; | ||
63 | |||
64 | buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; | ||
65 | buf += " uid=\"" + QString::number( ev.uid() ) + "\""; | ||
66 | |||
67 | if (ev.isAllDay() ) | ||
68 | buf += " type=\"AllDay\""; | ||
69 | |||
70 | if (ev.hasNotifiers() ) { | ||
71 | OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first | ||
72 | int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; | ||
73 | buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; | ||
74 | if ( alarm.sound() == OPimAlarm::Loud ) | ||
75 | buf += "loud"; | ||
76 | else | ||
77 | buf += "silent"; | ||
78 | buf += "\""; | ||
79 | } | ||
80 | if ( ev.hasRecurrence() ) { | ||
81 | buf += ev.recurrence().toString(); | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * fscking timezones :) well, we'll first convert | ||
86 | * the QDateTime to a QDateTime in UTC time | ||
87 | * and then we'll create a nice time_t | ||
88 | */ | ||
89 | OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); | ||
90 | buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\""; | ||
91 | buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\""; | ||
92 | if (!ev.note().isEmpty() ) { | ||
93 | buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\""; | ||
94 | } | ||
95 | |||
96 | buf += " timezone=\""; | ||
97 | if ( ev.timeZone().isEmpty() ) | ||
98 | buf += "None"; | ||
99 | else | ||
100 | buf += ev.timeZone(); | ||
101 | |||
102 | if (ev.parent() != 0 ) { | ||
103 | buf += " recparent=\""+QString::number(ev.parent() )+"\""; | ||
104 | } | ||
105 | |||
106 | if (ev.children().count() != 0 ) { | ||
107 | QArray<int> children = ev.children(); | ||
108 | buf += " recchildren=\""; | ||
109 | for ( uint i = 0; i < children.count(); i++ ) { | ||
110 | if ( i != 0 ) buf += " "; | ||
111 | buf += QString::number( children[i] ); | ||
112 | } | ||
113 | buf+= "\""; | ||
114 | } | ||
115 | |||
116 | // skip custom writing | ||
117 | } | ||
118 | |||
119 | inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) { | ||
120 | QMap<int, OEvent>::ConstIterator it; | ||
121 | QString buf; | ||
122 | QCString str; | ||
123 | int total_written; | ||
124 | for ( it = list.begin(); it != list.end(); ++it ) { | ||
125 | buf = "<event"; | ||
126 | save( it.data(), buf ); | ||
127 | buf += " />\n"; | ||
128 | str = buf.utf8(); | ||
129 | |||
130 | total_written = file.writeBlock(str.data(), str.length() ); | ||
131 | if ( total_written != int(str.length() ) ) | ||
132 | return false; | ||
133 | } | ||
134 | return true; | ||
135 | } | ||
51 | } | 136 | } |
52 | 137 | ||
53 | ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , | 138 | ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , |
54 | const QString& fileName ) | 139 | const QString& fileName ) |
55 | : ODateBookAccessBackend() { | 140 | : ODateBookAccessBackend() { |
56 | m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; | 141 | m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; |
57 | m_changed = false; | 142 | m_changed = false; |
58 | } | 143 | } |
59 | ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() { | 144 | ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() { |
60 | } | 145 | } |
61 | bool ODateBookAccessBackend_XML::load() { | 146 | bool ODateBookAccessBackend_XML::load() { |
62 | return loadFile(); | 147 | return loadFile(); |
63 | } | 148 | } |
64 | bool ODateBookAccessBackend_XML::reload() { | 149 | bool ODateBookAccessBackend_XML::reload() { |
65 | clear(); | 150 | clear(); |
66 | return load(); | 151 | return load(); |
67 | } | 152 | } |
68 | bool ODateBookAccessBackend_XML::save() { | 153 | bool ODateBookAccessBackend_XML::save() { |
69 | if (!m_changed) return true; | 154 | qWarning("going to save now"); |
70 | m_changed = false; | 155 | // if (!m_changed) return true; |
156 | |||
157 | int total_written; | ||
158 | QString strFileNew = m_name + ".new"; | ||
159 | |||
160 | QFile f( strFileNew ); | ||
161 | if (!f.open( IO_WriteOnly | IO_Raw ) ) return false; | ||
162 | |||
163 | QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); | ||
164 | buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n"; | ||
165 | buf += "<events>\n"; | ||
166 | QCString str = buf.utf8(); | ||
167 | total_written = f.writeBlock( str.data(), str.length() ); | ||
168 | if ( total_written != int(str.length() ) ) { | ||
169 | f.close(); | ||
170 | QFile::remove( strFileNew ); | ||
171 | return false; | ||
172 | } | ||
71 | 173 | ||
174 | if (!forAll( m_raw, f ) ) { | ||
175 | f.close(); | ||
176 | QFile::remove( strFileNew ); | ||
177 | return false; | ||
178 | } | ||
179 | if (!forAll( m_rep, f ) ) { | ||
180 | f.close(); | ||
181 | QFile::remove( strFileNew ); | ||
182 | return false; | ||
183 | } | ||
184 | |||
185 | buf = "</events>\n</DATEBOOK>\n"; | ||
186 | str = buf.utf8(); | ||
187 | total_written = f.writeBlock( str.data(), str.length() ); | ||
188 | if ( total_written != int(str.length() ) ) { | ||
189 | f.close(); | ||
190 | QFile::remove( strFileNew ); | ||
191 | return false; | ||
192 | } | ||
193 | f.close(); | ||
194 | |||
195 | exit(0); | ||
196 | if ( ::rename( strFileNew, m_name ) < 0 ) { | ||
197 | QFile::remove( strFileNew ); | ||
198 | return false; | ||
199 | } | ||
200 | |||
201 | m_changed = false; | ||
72 | return true; | 202 | return true; |
73 | } | 203 | } |
74 | QArray<int> ODateBookAccessBackend_XML::allRecords()const { | 204 | QArray<int> ODateBookAccessBackend_XML::allRecords()const { |
75 | QArray<int> ints( m_raw.count()+ m_rep.count() ); | 205 | QArray<int> ints( m_raw.count()+ m_rep.count() ); |
76 | uint i = 0; | 206 | uint i = 0; |
77 | QMap<int, OEvent>::ConstIterator it; | 207 | QMap<int, OEvent>::ConstIterator it; |
78 | 208 | ||
79 | for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { | 209 | for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { |
80 | ints[i] = it.key(); | 210 | ints[i] = it.key(); |
81 | i++; | 211 | i++; |
82 | } | 212 | } |
83 | for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { | 213 | for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { |
@@ -174,43 +304,47 @@ bool ODateBookAccessBackend_XML::loadFile() { | |||
174 | ::close( fd ); | 304 | ::close( fd ); |
175 | return false; | 305 | return false; |
176 | } | 306 | } |
177 | void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); | 307 | void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); |
178 | if ( map_addr == ( (caddr_t)-1) ) { | 308 | if ( map_addr == ( (caddr_t)-1) ) { |
179 | ::close( fd ); | 309 | ::close( fd ); |
180 | return false; | 310 | return false; |
181 | } | 311 | } |
182 | 312 | ||
183 | ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); | 313 | ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); |
184 | ::close( fd ); | 314 | ::close( fd ); |
185 | 315 | ||
186 | QAsciiDict<int> dict(FCreated+1); | 316 | QAsciiDict<int> dict(FExceptions+1); |
187 | dict.setAutoDelete( true ); | 317 | dict.setAutoDelete( true ); |
188 | dict.insert( "description", new int(FDescription) ); | 318 | dict.insert( "description", new int(FDescription) ); |
189 | dict.insert( "location", new int(FLocation) ); | 319 | dict.insert( "location", new int(FLocation) ); |
190 | dict.insert( "categories", new int(FCategories) ); | 320 | dict.insert( "categories", new int(FCategories) ); |
191 | dict.insert( "uid", new int(FUid) ); | 321 | dict.insert( "uid", new int(FUid) ); |
192 | dict.insert( "type", new int(FType) ); | 322 | dict.insert( "type", new int(FType) ); |
193 | dict.insert( "alarm", new int(FAlarm) ); | 323 | dict.insert( "alarm", new int(FAlarm) ); |
194 | dict.insert( "sound", new int(FSound) ); | 324 | dict.insert( "sound", new int(FSound) ); |
195 | dict.insert( "rtype", new int(FRType) ); | 325 | dict.insert( "rtype", new int(FRType) ); |
196 | dict.insert( "rweekdays", new int(FRWeekdays) ); | 326 | dict.insert( "rweekdays", new int(FRWeekdays) ); |
197 | dict.insert( "rposition", new int(FRPosition) ); | 327 | dict.insert( "rposition", new int(FRPosition) ); |
198 | dict.insert( "rfreq", new int(FRFreq) ); | 328 | dict.insert( "rfreq", new int(FRFreq) ); |
199 | dict.insert( "rhasenddate", new int(FRHasEndDate) ); | 329 | dict.insert( "rhasenddate", new int(FRHasEndDate) ); |
200 | dict.insert( "enddt", new int(FREndDate) ); | 330 | dict.insert( "enddt", new int(FREndDate) ); |
201 | dict.insert( "start", new int(FRStart) ); | 331 | dict.insert( "start", new int(FRStart) ); |
202 | dict.insert( "end", new int(FREnd) ); | 332 | dict.insert( "end", new int(FREnd) ); |
203 | dict.insert( "note", new int(FNote) ); | 333 | dict.insert( "note", new int(FNote) ); |
204 | dict.insert( "created", new int(FCreated) ); | 334 | dict.insert( "created", new int(FCreated) ); |
335 | dict.insert( "recparent", new int(FRecParent) ); | ||
336 | dict.insert( "recchildren", new int(FRecChildren) ); | ||
337 | dict.insert( "exceptions", new int(FExceptions) ); | ||
338 | dict.insert( "timezone", new int(FTimeZone) ); | ||
205 | 339 | ||
206 | char* dt = (char*)map_addr; | 340 | char* dt = (char*)map_addr; |
207 | int len = attribute.st_size; | 341 | int len = attribute.st_size; |
208 | int i = 0; | 342 | int i = 0; |
209 | char* point; | 343 | char* point; |
210 | const char* collectionString = "<event "; | 344 | const char* collectionString = "<event "; |
211 | int strLen = ::strlen(collectionString); | 345 | int strLen = ::strlen(collectionString); |
212 | int *find; | 346 | int *find; |
213 | while ( dt + 1 != 0 && (( point = ::strstr( dt+i, collectionString ) ) != 0 ) ) { | 347 | while ( dt + 1 != 0 && (( point = ::strstr( dt+i, collectionString ) ) != 0 ) ) { |
214 | i = point -dt; | 348 | i = point -dt; |
215 | i+= strLen; | 349 | i+= strLen; |
216 | 350 | ||
@@ -280,28 +414,33 @@ bool ODateBookAccessBackend_XML::loadFile() { | |||
280 | } | 414 | } |
281 | ::munmap(map_addr, attribute.st_size ); | 415 | ::munmap(map_addr, attribute.st_size ); |
282 | m_changed = false; // changed during add | 416 | m_changed = false; // changed during add |
283 | 417 | ||
284 | return true; | 418 | return true; |
285 | } | 419 | } |
286 | void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { | 420 | void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { |
287 | /* AllDay is alway in UTC */ | 421 | /* AllDay is alway in UTC */ |
288 | if ( ev.isAllDay() ) { | 422 | if ( ev.isAllDay() ) { |
289 | OTimeZone utc = OTimeZone::utc(); | 423 | OTimeZone utc = OTimeZone::utc(); |
290 | ev.setStartDateTime( utc.fromUTCDateTime( start ) ); | 424 | ev.setStartDateTime( utc.fromUTCDateTime( start ) ); |
291 | ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); | 425 | ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); |
426 | ev.setTimeZone( "UTC"); // make sure it is really utc | ||
292 | }else { | 427 | }else { |
428 | /* to current date time */ | ||
293 | OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); | 429 | OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); |
294 | ev.setStartDateTime( zone.toDateTime( start ) ); | 430 | QDateTime date = zone.toDateTime( start ); |
295 | ev.setEndDateTime ( zone.toDateTime( end ) ); | 431 | ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); |
432 | |||
433 | date = zone.toDateTime( end ); | ||
434 | ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); | ||
296 | } | 435 | } |
297 | if ( rec && rec->doesRecur() ) { | 436 | if ( rec && rec->doesRecur() ) { |
298 | OTimeZone utc = OTimeZone::utc(); | 437 | OTimeZone utc = OTimeZone::utc(); |
299 | ORecur recu( *rec ); // call copy c'tor; | 438 | ORecur recu( *rec ); // call copy c'tor; |
300 | recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() ); | 439 | recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() ); |
301 | recu.setCreatedDateTime( utc.fromUTCDateTime( created ) ); | 440 | recu.setCreatedDateTime( utc.fromUTCDateTime( created ) ); |
302 | recu.setStart( ev.startDateTime().date() ); | 441 | recu.setStart( ev.startDateTime().date() ); |
303 | ev.setRecurrence( recu ); | 442 | ev.setRecurrence( recu ); |
304 | } | 443 | } |
305 | 444 | ||
306 | if (alarmTime != -1 ) { | 445 | if (alarmTime != -1 ) { |
307 | QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 ); | 446 | QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 ); |
@@ -380,16 +519,39 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val | |||
380 | break; | 519 | break; |
381 | } | 520 | } |
382 | case FREnd: { | 521 | case FREnd: { |
383 | end = ( (time_t) value.toLong() ); | 522 | end = ( (time_t) value.toLong() ); |
384 | break; | 523 | break; |
385 | } | 524 | } |
386 | case FNote: | 525 | case FNote: |
387 | e.setNote( value ); | 526 | e.setNote( value ); |
388 | break; | 527 | break; |
389 | case FCreated: | 528 | case FCreated: |
390 | created = value.toInt(); | 529 | created = value.toInt(); |
391 | break; | 530 | break; |
531 | case FRecParent: | ||
532 | e.setParent( value.toInt() ); | ||
533 | break; | ||
534 | case FRecChildren:{ | ||
535 | QStringList list = QStringList::split(' ', value ); | ||
536 | for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { | ||
537 | e.addChild( (*it).toInt() ); | ||
538 | } | ||
539 | } | ||
540 | break; | ||
541 | case FExceptions:{ | ||
542 | QStringList list = QStringList::split(' ', value ); | ||
543 | for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { | ||
544 | QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() ); | ||
545 | qWarning("adding exception %s", date.toString().latin1() ); | ||
546 | recur()->exceptions().append( date ); | ||
547 | } | ||
548 | } | ||
549 | break; | ||
550 | case FTimeZone: | ||
551 | if ( value != "None" ) | ||
552 | e.setTimeZone( value ); | ||
553 | break; | ||
392 | default: | 554 | default: |
393 | break; | 555 | break; |
394 | } | 556 | } |
395 | } | 557 | } |