summaryrefslogtreecommitdiff
path: root/libopie/pim/odatebookaccessbackend_xml.cpp
Unidiff
Diffstat (limited to 'libopie/pim/odatebookaccessbackend_xml.cpp') (more/less context) (show whitespace changes)
-rw-r--r--libopie/pim/odatebookaccessbackend_xml.cpp612
1 files changed, 0 insertions, 612 deletions
diff --git a/libopie/pim/odatebookaccessbackend_xml.cpp b/libopie/pim/odatebookaccessbackend_xml.cpp
deleted file mode 100644
index 929d004..0000000
--- a/libopie/pim/odatebookaccessbackend_xml.cpp
+++ b/dev/null
@@ -1,612 +0,0 @@
1#include <errno.h>
2#include <fcntl.h>
3
4#include <stdio.h>
5#include <stdlib.h>
6
7#include <sys/types.h>
8#include <sys/mman.h>
9#include <sys/stat.h>
10
11#include <unistd.h>
12
13#include <qasciidict.h>
14#include <qfile.h>
15
16#include <qtopia/global.h>
17#include <qtopia/stringutil.h>
18#include <qtopia/timeconversion.h>
19
20#include "opimnotifymanager.h"
21#include "orecur.h"
22#include "otimezone.h"
23#include "odatebookaccessbackend_xml.h"
24
25namespace {
26 // FROM TT again
27char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
28{
29 char needleChar;
30 char haystackChar;
31 if (!needle || !haystack || !hLen || !nLen)
32 return 0;
33
34 const char* hsearch = haystack;
35
36 if ((needleChar = *needle++) != 0) {
37 nLen--; //(to make up for needle++)
38 do {
39 do {
40 if ((haystackChar = *hsearch++) == 0)
41 return (0);
42 if (hsearch >= haystack + hLen)
43 return (0);
44 } while (haystackChar != needleChar);
45 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
46 hsearch--;
47 }
48 return ((char *)hsearch);
49}
50}
51
52namespace {
53 time_t start, end, created, rp_end;
54 ORecur* rec;
55 ORecur* recur() {
56 if (!rec)
57 rec = new ORecur;
58
59 return rec;
60 }
61 int alarmTime;
62 int snd;
63 enum Attribute{
64 FDescription = 0,
65 FLocation,
66 FCategories,
67 FUid,
68 FType,
69 FAlarm,
70 FSound,
71 FRType,
72 FRWeekdays,
73 FRPosition,
74 FRFreq,
75 FRHasEndDate,
76 FREndDate,
77 FRStart,
78 FREnd,
79 FNote,
80 FCreated, // Should't this be called FRCreated ?
81 FTimeZone,
82 FRecParent,
83 FRecChildren,
84 FExceptions
85 };
86
87 // FIXME: Use OEvent::toMap() here !! (eilers)
88 inline void save( const OEvent& ev, QString& buf ) {
89 qWarning("Saving %d %s", ev.uid(), ev.description().latin1() );
90 buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\"";
91 if (!ev.location().isEmpty() )
92 buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\"";
93
94 buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\"";
95 buf += " uid=\"" + QString::number( ev.uid() ) + "\"";
96
97 if (ev.isAllDay() )
98 buf += " type=\"AllDay\""; // is that all ?? (eilers)
99
100 if (ev.hasNotifiers() ) {
101 OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first
102 int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60;
103 buf += " alarm=\"" + QString::number(minutes) + "\" sound=\"";
104 if ( alarm.sound() == OPimAlarm::Loud )
105 buf += "loud";
106 else
107 buf += "silent";
108 buf += "\"";
109 }
110 if ( ev.hasRecurrence() ) {
111 buf += ev.recurrence().toString();
112 }
113
114 /*
115 * fscking timezones :) well, we'll first convert
116 * the QDateTime to a QDateTime in UTC time
117 * and then we'll create a nice time_t
118 */
119 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
120 buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\"";
121 buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\"";
122 if (!ev.note().isEmpty() ) {
123 buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\"";
124 }
125
126 buf += " timezone=\"";
127 if ( ev.timeZone().isEmpty() )
128 buf += "None";
129 else
130 buf += ev.timeZone();
131 buf += "\"";
132
133 if (ev.parent() != 0 ) {
134 buf += " recparent=\""+QString::number(ev.parent() )+"\"";
135 }
136
137 if (ev.children().count() != 0 ) {
138 QArray<int> children = ev.children();
139 buf += " recchildren=\"";
140 for ( uint i = 0; i < children.count(); i++ ) {
141 if ( i != 0 ) buf += " ";
142 buf += QString::number( children[i] );
143 }
144 buf+= "\"";
145 }
146
147 // skip custom writing
148 }
149
150 inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) {
151 QMap<int, OEvent>::ConstIterator it;
152 QString buf;
153 QCString str;
154 int total_written;
155 for ( it = list.begin(); it != list.end(); ++it ) {
156 buf = "<event";
157 save( it.data(), buf );
158 buf += " />\n";
159 str = buf.utf8();
160
161 total_written = file.writeBlock(str.data(), str.length() );
162 if ( total_written != int(str.length() ) )
163 return false;
164 }
165 return true;
166 }
167}
168
169ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& ,
170 const QString& fileName )
171 : ODateBookAccessBackend() {
172 m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName;
173 m_changed = false;
174}
175ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() {
176}
177bool ODateBookAccessBackend_XML::load() {
178 return loadFile();
179}
180bool ODateBookAccessBackend_XML::reload() {
181 clear();
182 return load();
183}
184bool ODateBookAccessBackend_XML::save() {
185 if (!m_changed) return true;
186
187 int total_written;
188 QString strFileNew = m_name + ".new";
189
190 QFile f( strFileNew );
191 if (!f.open( IO_WriteOnly | IO_Raw ) ) return false;
192
193 QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
194 buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n";
195 buf += "<events>\n";
196 QCString str = buf.utf8();
197 total_written = f.writeBlock( str.data(), str.length() );
198 if ( total_written != int(str.length() ) ) {
199 f.close();
200 QFile::remove( strFileNew );
201 return false;
202 }
203
204 if (!forAll( m_raw, f ) ) {
205 f.close();
206 QFile::remove( strFileNew );
207 return false;
208 }
209 if (!forAll( m_rep, f ) ) {
210 f.close();
211 QFile::remove( strFileNew );
212 return false;
213 }
214
215 buf = "</events>\n</DATEBOOK>\n";
216 str = buf.utf8();
217 total_written = f.writeBlock( str.data(), str.length() );
218 if ( total_written != int(str.length() ) ) {
219 f.close();
220 QFile::remove( strFileNew );
221 return false;
222 }
223 f.close();
224
225 if ( ::rename( strFileNew, m_name ) < 0 ) {
226 QFile::remove( strFileNew );
227 return false;
228 }
229
230 m_changed = false;
231 return true;
232}
233QArray<int> ODateBookAccessBackend_XML::allRecords()const {
234 QArray<int> ints( m_raw.count()+ m_rep.count() );
235 uint i = 0;
236 QMap<int, OEvent>::ConstIterator it;
237
238 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
239 ints[i] = it.key();
240 i++;
241 }
242 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
243 ints[i] = it.key();
244 i++;
245 }
246
247 return ints;
248}
249QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) {
250 return QArray<int>();
251}
252void ODateBookAccessBackend_XML::clear() {
253 m_changed = true;
254 m_raw.clear();
255 m_rep.clear();
256}
257OEvent ODateBookAccessBackend_XML::find( int uid ) const{
258 if ( m_raw.contains( uid ) )
259 return m_raw[uid];
260 else
261 return m_rep[uid];
262}
263bool ODateBookAccessBackend_XML::add( const OEvent& ev ) {
264 m_changed = true;
265 if (ev.hasRecurrence() )
266 m_rep.insert( ev.uid(), ev );
267 else
268 m_raw.insert( ev.uid(), ev );
269
270 return true;
271}
272bool ODateBookAccessBackend_XML::remove( int uid ) {
273 m_changed = true;
274 m_rep.remove( uid );
275 m_rep.remove( uid );
276
277 return true;
278}
279bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) {
280 replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers)
281 return add( ev );
282}
283QArray<int> ODateBookAccessBackend_XML::rawEvents()const {
284 return allRecords();
285}
286QArray<int> ODateBookAccessBackend_XML::rawRepeats()const {
287 QArray<int> ints( m_rep.count() );
288 uint i = 0;
289 QMap<int, OEvent>::ConstIterator it;
290
291 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
292 ints[i] = it.key();
293 i++;
294 }
295
296 return ints;
297}
298QArray<int> ODateBookAccessBackend_XML::nonRepeats()const {
299 QArray<int> ints( m_raw.count() );
300 uint i = 0;
301 QMap<int, OEvent>::ConstIterator it;
302
303 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
304 ints[i] = it.key();
305 i++;
306 }
307
308 return ints;
309}
310OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() {
311 OEvent::ValueList list;
312 QMap<int, OEvent>::ConstIterator it;
313 for (it = m_raw.begin(); it != m_raw.end(); ++it )
314 list.append( it.data() );
315
316 return list;
317}
318OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() {
319 OEvent::ValueList list;
320 QMap<int, OEvent>::ConstIterator it;
321 for (it = m_rep.begin(); it != m_rep.end(); ++it )
322 list.append( it.data() );
323
324 return list;
325}
326
327// FIXME: Use OEvent::fromMap() (eilers)
328bool ODateBookAccessBackend_XML::loadFile() {
329 m_changed = false;
330
331 int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY );
332 if ( fd < 0 ) return false;
333
334 struct stat attribute;
335 if ( ::fstat(fd, &attribute ) == -1 ) {
336 ::close( fd );
337 return false;
338 }
339 void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 );
340 if ( map_addr == ( (caddr_t)-1) ) {
341 ::close( fd );
342 return false;
343 }
344
345 ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL );
346 ::close( fd );
347
348 QAsciiDict<int> dict(FExceptions+1);
349 dict.setAutoDelete( true );
350 dict.insert( "description", new int(FDescription) );
351 dict.insert( "location", new int(FLocation) );
352 dict.insert( "categories", new int(FCategories) );
353 dict.insert( "uid", new int(FUid) );
354 dict.insert( "type", new int(FType) );
355 dict.insert( "alarm", new int(FAlarm) );
356 dict.insert( "sound", new int(FSound) );
357 dict.insert( "rtype", new int(FRType) );
358 dict.insert( "rweekdays", new int(FRWeekdays) );
359 dict.insert( "rposition", new int(FRPosition) );
360 dict.insert( "rfreq", new int(FRFreq) );
361 dict.insert( "rhasenddate", new int(FRHasEndDate) );
362 dict.insert( "enddt", new int(FREndDate) );
363 dict.insert( "start", new int(FRStart) );
364 dict.insert( "end", new int(FREnd) );
365 dict.insert( "note", new int(FNote) );
366 dict.insert( "created", new int(FCreated) ); // Shouldn't this be FRCreated ??
367 dict.insert( "recparent", new int(FRecParent) );
368 dict.insert( "recchildren", new int(FRecChildren) );
369 dict.insert( "exceptions", new int(FExceptions) );
370 dict.insert( "timezone", new int(FTimeZone) );
371
372 char* dt = (char*)map_addr;
373 int len = attribute.st_size;
374 int i = 0;
375 char* point;
376 const char* collectionString = "<event ";
377 int strLen = ::strlen(collectionString);
378 int *find;
379 while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) {
380 i = point -dt;
381 i+= strLen;
382
383 alarmTime = -1;
384 snd = 0; // silent
385
386 OEvent ev;
387 rec = 0;
388
389 while ( TRUE ) {
390 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
391 ++i;
392 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
393 break;
394
395
396 // we have another attribute, read it.
397 int j = i;
398 while ( j < len && dt[j] != '=' )
399 ++j;
400 QCString attr( dt+i, j-i+1);
401
402 i = ++j; // skip =
403
404 // find the start of quotes
405 while ( i < len && dt[i] != '"' )
406 ++i;
407 j = ++i;
408
409 bool haveUtf = FALSE;
410 bool haveEnt = FALSE;
411 while ( j < len && dt[j] != '"' ) {
412 if ( ((unsigned char)dt[j]) > 0x7f )
413 haveUtf = TRUE;
414 if ( dt[j] == '&' )
415 haveEnt = TRUE;
416 ++j;
417 }
418 if ( i == j ) {
419 // empty value
420 i = j + 1;
421 continue;
422 }
423
424 QCString value( dt+i, j-i+1 );
425 i = j + 1;
426
427 QString str = (haveUtf ? QString::fromUtf8( value )
428 : QString::fromLatin1( value ) );
429 if ( haveEnt )
430 str = Qtopia::plainString( str );
431
432 /*
433 * add key + value
434 */
435 find = dict[attr.data()];
436 if (!find)
437 ev.setCustomField( attr, str );
438 else {
439 setField( ev, *find, str );
440 }
441 }
442 /* time to finalize */
443 finalizeRecord( ev );
444 delete rec;
445 }
446 ::munmap(map_addr, attribute.st_size );
447 m_changed = false; // changed during add
448
449 return true;
450}
451
452// FIXME: Use OEvent::fromMap() which makes this obsolete.. (eilers)
453void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) {
454 /* AllDay is alway in UTC */
455 if ( ev.isAllDay() ) {
456 OTimeZone utc = OTimeZone::utc();
457 ev.setStartDateTime( utc.fromUTCDateTime( start ) );
458 ev.setEndDateTime ( utc.fromUTCDateTime( end ) );
459 ev.setTimeZone( "UTC"); // make sure it is really utc
460 }else {
461 /* to current date time */
462 // qWarning(" Start is %d", start );
463 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
464 QDateTime date = zone.toDateTime( start );
465 qWarning(" Start is %s", date.toString().latin1() );
466 ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) );
467
468 date = zone.toDateTime( end );
469 ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) );
470 }
471 if ( rec && rec->doesRecur() ) {
472 OTimeZone utc = OTimeZone::utc();
473 ORecur recu( *rec ); // call copy c'tor;
474 recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() );
475 recu.setCreatedDateTime( utc.fromUTCDateTime( created ) );
476 recu.setStart( ev.startDateTime().date() );
477 ev.setRecurrence( recu );
478 }
479
480 if (alarmTime != -1 ) {
481 QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 );
482 OPimAlarm al( snd , dt );
483 ev.notifiers().add( al );
484 }
485 if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) {
486 qWarning("already contains assign uid");
487 ev.setUid( 1 );
488 }
489 qWarning("addind %d %s", ev.uid(), ev.description().latin1() );
490 if ( ev.hasRecurrence() )
491 m_rep.insert( ev.uid(), ev );
492 else
493 m_raw.insert( ev.uid(), ev );
494
495}
496void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) {
497// qWarning(" setting %s", value.latin1() );
498 switch( id ) {
499 case FDescription:
500 e.setDescription( value );
501 break;
502 case FLocation:
503 e.setLocation( value );
504 break;
505 case FCategories:
506 e.setCategories( e.idsFromString( value ) );
507 break;
508 case FUid:
509 e.setUid( value.toInt() );
510 break;
511 case FType:
512 if ( value == "AllDay" ) {
513 e.setAllDay( true );
514 e.setTimeZone( "UTC" );
515 }
516 break;
517 case FAlarm:
518 alarmTime = value.toInt();
519 break;
520 case FSound:
521 snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent;
522 break;
523 // recurrence stuff
524 case FRType:
525 if ( value == "Daily" )
526 recur()->setType( ORecur::Daily );
527 else if ( value == "Weekly" )
528 recur()->setType( ORecur::Weekly);
529 else if ( value == "MonthlyDay" )
530 recur()->setType( ORecur::MonthlyDay );
531 else if ( value == "MonthlyDate" )
532 recur()->setType( ORecur::MonthlyDate );
533 else if ( value == "Yearly" )
534 recur()->setType( ORecur::Yearly );
535 else
536 recur()->setType( ORecur::NoRepeat );
537 break;
538 case FRWeekdays:
539 recur()->setDays( value.toInt() );
540 break;
541 case FRPosition:
542 recur()->setPosition( value.toInt() );
543 break;
544 case FRFreq:
545 recur()->setFrequency( value.toInt() );
546 break;
547 case FRHasEndDate:
548 recur()->setHasEndDate( value.toInt() );
549 break;
550 case FREndDate: {
551 rp_end = (time_t) value.toLong();
552 break;
553 }
554 case FRStart: {
555 start = (time_t) value.toLong();
556 break;
557 }
558 case FREnd: {
559 end = ( (time_t) value.toLong() );
560 break;
561 }
562 case FNote:
563 e.setNote( value );
564 break;
565 case FCreated:
566 created = value.toInt();
567 break;
568 case FRecParent:
569 e.setParent( value.toInt() );
570 break;
571 case FRecChildren:{
572 QStringList list = QStringList::split(' ', value );
573 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
574 e.addChild( (*it).toInt() );
575 }
576 }
577 break;
578 case FExceptions:{
579 QStringList list = QStringList::split(' ', value );
580 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
581 QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() );
582 qWarning("adding exception %s", date.toString().latin1() );
583 recur()->exceptions().append( date );
584 }
585 }
586 break;
587 case FTimeZone:
588 if ( value != "None" )
589 e.setTimeZone( value );
590 break;
591 default:
592 break;
593 }
594}
595QArray<int> ODateBookAccessBackend_XML::matchRegexp( const QRegExp &r ) const
596{
597 QArray<int> m_currentQuery( m_raw.count()+ m_rep.count() );
598 uint arraycounter = 0;
599 QMap<int, OEvent>::ConstIterator it;
600
601 for ( it = m_raw.begin(); it != m_raw.end(); ++it )
602 if ( it.data().match( r ) )
603 m_currentQuery[arraycounter++] = it.data().uid();
604 for ( it = m_rep.begin(); it != m_rep.end(); ++it )
605 if ( it.data().match( r ) )
606 m_currentQuery[arraycounter++] = it.data().uid();
607
608 // Shrink to fit..
609 m_currentQuery.resize(arraycounter);
610
611 return m_currentQuery;
612}