summaryrefslogtreecommitdiff
path: root/library/backend
Unidiff
Diffstat (limited to 'library/backend') (more/less context) (ignore whitespace changes)
-rw-r--r--library/backend/.cvsignore2
-rw-r--r--library/backend/categories.cpp701
-rw-r--r--library/backend/categories.h232
-rw-r--r--library/backend/contact.cpp909
-rw-r--r--library/backend/contact.h217
-rw-r--r--library/backend/event.cpp830
-rw-r--r--library/backend/event.h229
-rw-r--r--library/backend/palmtoprecord.cpp127
-rw-r--r--library/backend/palmtoprecord.h94
-rw-r--r--library/backend/palmtopuidgen.h83
-rw-r--r--library/backend/qfiledirect_p.h36
-rw-r--r--library/backend/qpcglobal.h50
-rw-r--r--library/backend/recordfields.h135
-rw-r--r--library/backend/stringutil.cpp415
-rw-r--r--library/backend/stringutil.h57
-rw-r--r--library/backend/task.cpp271
-rw-r--r--library/backend/task.h77
-rw-r--r--library/backend/timeconversion.cpp237
-rw-r--r--library/backend/timeconversion.h45
-rw-r--r--library/backend/vcc.y1199
-rw-r--r--library/backend/vobject.cpp1210
-rw-r--r--library/backend/vobject_p.h401
22 files changed, 7557 insertions, 0 deletions
diff --git a/library/backend/.cvsignore b/library/backend/.cvsignore
new file mode 100644
index 0000000..e047b1f
--- a/dev/null
+++ b/library/backend/.cvsignore
@@ -0,0 +1,2 @@
1moc_*
2*.moc
diff --git a/library/backend/categories.cpp b/library/backend/categories.cpp
new file mode 100644
index 0000000..91331db
--- a/dev/null
+++ b/library/backend/categories.cpp
@@ -0,0 +1,701 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free
8** Software Foundation and appearing in the file LICENSE.GPL included
9** in the packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
12** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
13** PARTICULAR PURPOSE.
14**
15** See http://www.trolltech.com/gpl/ for GPL licensing information.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21#include "categories.h"
22#include <qfile.h>
23#include <qcstring.h>
24#include <qtextstream.h>
25#include "stringutil.h"
26
27using namespace Qtopia;
28
29/***********************************************************
30 *
31 * CategoryGroup
32 *
33 **********************************************************/
34
35#ifdef PALMTOPCENTER
36UidGen CategoryGroup::sUidGen( UidGen::PalmtopCenter );
37#else
38UidGen CategoryGroup::sUidGen( UidGen::Qtopia );
39#endif
40
41int CategoryGroup::add( const QString &label )
42{
43 if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") )
44 return 0;
45
46 QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label );
47 if ( findIt != mLabelIdMap.end() )
48 return 0;
49 int newUid = uidGen().generate();
50 insert( newUid, label );
51 return newUid;
52}
53
54void CategoryGroup::insert( int uid, const QString &label )
55{
56 uidGen().store( uid );
57 mIdLabelMap[uid] = label;
58 mLabelIdMap[label] = uid;
59}
60
61bool CategoryGroup::add( int uid, const QString &label )
62{
63 if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") )
64 return FALSE;
65
66 QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label );
67 if ( labelIt != mLabelIdMap.end() )
68 return FALSE;
69 QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid );
70 if ( idIt != mIdLabelMap.end() )
71 return FALSE;
72 insert( uid, label );
73 return TRUE;
74}
75
76bool CategoryGroup::remove( const QString &label )
77{
78 QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label );
79 if ( findIt == mLabelIdMap.end() )
80 return FALSE;
81
82 mIdLabelMap.remove( *findIt );
83 mLabelIdMap.remove( findIt );
84
85 return TRUE;
86}
87
88bool CategoryGroup::remove( int uid )
89{
90 QMap<int,QString>::Iterator idIt = mIdLabelMap.find( uid );
91 if ( idIt == mIdLabelMap.end() )
92 return FALSE;
93
94 mLabelIdMap.remove( *idIt );
95 mIdLabelMap.remove( idIt );
96
97 return TRUE;
98}
99
100bool CategoryGroup::rename( int uid, const QString &newLabel )
101{
102 if ( newLabel == QObject::tr("All") || newLabel == QObject::tr("Unfiled") )
103 return FALSE;
104
105 QMap<int, QString>::Iterator idIt = mIdLabelMap.find( uid );
106 if ( idIt == mIdLabelMap.end() )
107 return FALSE;
108
109 mLabelIdMap.remove( *idIt );
110 mLabelIdMap[newLabel] = uid;
111 *idIt = newLabel;
112
113 return TRUE;
114}
115
116bool CategoryGroup::rename( const QString &oldLabel, const QString &newLabel )
117{
118 return rename( id(oldLabel), newLabel );
119}
120
121bool CategoryGroup::contains(int uid) const
122{
123 return ( mIdLabelMap.find( uid ) != mIdLabelMap.end() );
124}
125
126bool CategoryGroup::contains(const QString &label) const
127{
128 return ( mLabelIdMap.find( label ) != mLabelIdMap.end() );
129}
130
131/** Returns label associated with the uid or QString::null if
132 * not found
133 */
134const QString &CategoryGroup::label(int uid) const
135{
136 QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid );
137 if ( idIt == mIdLabelMap.end() )
138 return QString::null;
139 return *idIt;
140}
141
142/** Returns the uid associated with label or 0 if not found */
143int CategoryGroup::id(const QString &label) const
144{
145 QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label );
146 if ( labelIt == mLabelIdMap.end() )
147 return 0;
148 return *labelIt;
149}
150
151QStringList CategoryGroup::labels() const
152{
153 QStringList labels;
154 for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin();
155 it != mIdLabelMap.end(); ++it )
156 labels += *it;
157 // ### I don't think this is the place for this...
158// labels.sort();
159 return labels;
160}
161
162QStringList CategoryGroup::labels(const QArray<int> &catids ) const
163{
164 QStringList labels;
165 if ( catids.count() == 0 )
166 return labels;
167 for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin();
168 it != mIdLabelMap.end(); ++it )
169 if ( catids.find( it.key() ) != -1 )
170 labels += *it;
171 return labels;
172}
173
174QArray<int> CategoryGroup::ids( const QStringList &cats ) const
175{
176 QArray<int> results;
177
178 for ( QStringList::ConstIterator catIt = cats.begin();
179 catIt != cats.end(); ++catIt ) {
180 if ( *catIt == QObject::tr("All") || *catIt == QObject::tr("Unfiled") )
181 continue;
182 int value = id( *catIt );
183 if ( value != 0 ) {
184 int tmp = results.size();
185 results.resize( tmp + 1 );
186 results[ tmp ] = value;
187 }
188 }
189
190 return results;
191}
192
193QArray<int> CategoryGroup::ids() const
194{
195 QArray<int> results( mIdLabelMap.count() );
196 int i = 0;
197 for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin();
198 it != mIdLabelMap.end(); ++it )
199 results[i++] = it.key();
200
201 return results;
202}
203
204/***********************************************************
205 *
206 * Categories
207 *
208 **********************************************************/
209
210/** Add the category name as long as it doesn't already exist locally
211 * or globally. Return TRUE if added, FALSE if conflicts.
212 */
213int Categories::addCategory( const QString &appname,
214 const QString &catname,
215 int uid )
216{
217 if ( mGlobalCats.contains(catname) )
218 return 0;
219
220 QMap< QString, CategoryGroup >::Iterator
221 appIt = mAppCats.find( appname );
222
223 if ( appIt == mAppCats.end() ) {
224 CategoryGroup newgroup;
225 newgroup.add( uid, catname );
226 mAppCats.insert( appname, newgroup );
227 emit categoryAdded( *this, appname, uid );
228 return uid;
229 }
230
231 CategoryGroup &cats = *appIt;
232 cats.add( uid, catname );
233 emit categoryAdded( *this, appname, uid );
234 return uid;
235}
236
237int Categories::addCategory( const QString &appname,
238 const QString &catname )
239{
240 if ( mGlobalCats.contains(catname) )
241 return 0;
242
243 QMap< QString, CategoryGroup >::Iterator
244 appIt = mAppCats.find( appname );
245
246 if ( appIt == mAppCats.end() ) {
247 CategoryGroup newgroup;
248 int uid = newgroup.add( catname );
249 mAppCats.insert( appname, newgroup );
250 emit categoryAdded( *this, appname, uid );
251 return uid;
252 }
253
254 CategoryGroup &cats = *appIt;
255 int uid = cats.add( catname );
256 if ( !uid )
257 return 0;
258 emit categoryAdded( *this, appname, uid );
259 return uid;
260}
261
262int Categories::addGlobalCategory( const QString &catname, int uid )
263{
264 mGlobalCats.add( uid, catname );
265 emit categoryAdded( *this, QString::null, uid );
266 return uid;
267}
268
269int Categories::addGlobalCategory( const QString &catname )
270{
271 int uid = mGlobalCats.add( catname );
272 if ( !uid )
273 return 0;
274 emit categoryAdded( *this, QString::null, uid );
275 return uid;
276}
277
278/** Removes the category from the application; if it is not found
279 * in the application, then it attempts to remove it from
280 * the global list
281 */
282bool Categories::removeCategory( const QString &appname,
283 const QString &catname,
284 bool checkGlobal )
285{
286 QMap< QString, CategoryGroup >::Iterator
287 appIt = mAppCats.find( appname );
288 if ( appIt != mAppCats.end() ) {
289 CategoryGroup &cats = *appIt;
290 int uid = cats.id( catname );
291 if ( cats.remove( uid ) ) {
292 emit categoryRemoved( *this, appname, uid );
293 return TRUE;
294 }
295 }
296 if ( !checkGlobal )
297 return FALSE;
298 return removeGlobalCategory( catname );
299}
300
301bool Categories::removeCategory( const QString &appname, int uid )
302{
303 QMap< QString, CategoryGroup >::Iterator
304 appIt = mAppCats.find( appname );
305 if ( appIt != mAppCats.end() ) {
306 CategoryGroup &cats = *appIt;
307 if ( cats.remove( uid ) ) {
308 emit categoryRemoved( *this, appname, uid );
309 return TRUE;
310 }
311 }
312 return FALSE;
313}
314
315bool Categories::removeGlobalCategory( const QString &catname )
316{
317 int uid = mGlobalCats.id( catname );
318 if ( mGlobalCats.remove( uid ) ) {
319 emit categoryRemoved( *this, QString::null, uid );
320 return TRUE;
321 }
322 return FALSE;
323}
324
325
326bool Categories::removeGlobalCategory( int uid )
327{
328 if ( mGlobalCats.remove( uid ) ) {
329 emit categoryRemoved( *this, QString::null, uid );
330 return TRUE;
331 }
332 return FALSE;
333}
334
335/** Returns the sorted list of all categories that are associated with
336 * the app. If includeGlobal parameter is TRUE then the returned
337 * categories will include the global category items.
338 */
339QStringList Categories::labels( const QString &app,
340 bool includeGlobal,
341 ExtraLabels extra ) const
342{
343 QMap< QString, CategoryGroup >::ConstIterator
344 appIt = mAppCats.find( app );
345 QStringList cats;
346 switch ( extra ) {
347 case NoExtra: break;
348 case AllUnfiled:
349 cats.append( tr("All") );
350 cats.append( tr("Unfiled") );
351 break;
352 case AllLabel:
353 cats.append( tr("All") );
354 break;
355 case UnfiledLabel:
356 cats.append( tr("Unfiled") );
357 break;
358 }
359 if ( appIt != mAppCats.end() )
360 cats += (*appIt).labels();
361 else qDebug("Categories::labels didn't find app %s", app.latin1() );
362 if ( includeGlobal )
363 cats += mGlobalCats.labels();
364 // I don't think a sorted list is useful, the user might find prefer
365 // it in the original order.
366// cats.sort();
367 return cats;
368}
369
370QString Categories::label( const QString &app, int id ) const
371{
372 if ( mGlobalCats.contains( id ) )
373 return mGlobalCats.label( id );
374 QMap< QString, CategoryGroup >::ConstIterator
375 appIt = mAppCats.find( app );
376 if ( appIt == mAppCats.end() )
377 return QString::null;
378 return (*appIt).label( id );
379}
380
381QStringList Categories::labels( const QString & app,
382 const QArray<int> &catids ) const
383{
384 QStringList strs = mGlobalCats.labels( catids );
385 strs += mAppCats[app].labels( catids );
386 return strs;
387}
388
389/** Returns a single string associated with the cat ids for display in
390 * a combobox or any area that requires one string. If catids are empty
391 * then "Unfiled" will be returned. If multiple categories are assigned
392 * the first cat id is shown with " (multi)" appended to the string.
393 */
394QString Categories::displaySingle( const QString &app,
395 const QArray<int> &catids,
396 DisplaySingle display ) const
397{
398 QStringList strs = labels( app, catids );
399 if ( !strs.count() )
400 return tr("Unfiled");
401 strs.sort();
402 QString r;
403 if ( strs.count() > 1 ) {
404 switch ( display ) {
405 case ShowFirst:
406 r = strs.first();
407 break;
408 case ShowMulti:
409 r = strs.first() + tr(" (multi.)");
410 break;
411 case ShowAll:
412 r = strs.join(" ");
413 break;
414 }
415 }
416 else r = strs.first();
417 return r;
418}
419
420QArray<int> Categories::ids( const QString &app ) const
421{
422 QArray<int> allIds = mGlobalCats.ids();
423 QArray<int> appIds = mAppCats[app].ids();
424
425 // we should make the guarentee that the ids are in the
426 // same order as the labels, (i.e. app cats then global)
427 // otherwise there is no point in having these two separate functions.
428 uint appSize = appIds.size();
429 appIds.resize( appSize + allIds.size() );
430 for ( uint i = appSize; i < appIds.size(); ++i )
431 appIds[int(i)] = allIds[int(i - appSize)];
432
433 return appIds;
434}
435
436QArray<int> Categories::ids( const QString &app, const QStringList &cats ) const
437{
438 QArray<int> allIds = mGlobalCats.ids( cats );
439 QArray<int> appIds = mAppCats[app].ids( cats );
440
441 uint appSize = appIds.size();
442 appIds.resize( appSize + allIds.size() );
443 for ( uint i = appSize; i < appIds.size(); ++i )
444 appIds[int(i)] = allIds[int(i - appSize)];
445
446 return appIds;
447}
448
449int Categories::id( const QString &app, const QString &cat ) const
450{
451 if ( cat == tr("Unfiled") || cat.contains( tr(" (multi.)") ) )
452 return 0;
453 int uid = mGlobalCats.id( cat );
454 if ( uid != 0 )
455 return uid;
456 return mAppCats[app].id( cat );
457}
458
459
460/** Return TRUE if renaming succeeded; FALSE if app name not found,
461 * or if there was a name conflict
462 */
463bool Categories::renameCategory( const QString &appname,
464 const QString &oldName,
465 const QString &newName )
466{
467 QMap< QString, CategoryGroup >::Iterator
468 appIt = mAppCats.find( appname );
469
470 if ( appIt != mAppCats.end() ) {
471 CategoryGroup &cats = *appIt;
472 int id = cats.id( oldName );
473 if ( id != 0 && cats.rename( id, newName ) ) {
474 emit categoryRenamed( *this, appname, id );
475 return TRUE;
476 }
477 }
478 return renameGlobalCategory( oldName, newName );
479}
480
481bool Categories::renameGlobalCategory( const QString &oldName,
482 const QString &newName )
483{
484 int uid = mGlobalCats.id( oldName );
485 if ( uid != 0 && mGlobalCats.rename( uid, newName ) ) {
486 emit categoryRenamed( *this, QString::null, uid );
487 return TRUE;
488 }
489 return FALSE;
490}
491
492void Categories::setGlobal( const QString &appname,
493 const QString &catname,
494 bool global )
495{
496 // if in global and should be in app; then move it
497 if ( mGlobalCats.contains( catname ) && !global ) {
498 mGlobalCats.remove( catname );
499 addCategory( appname, catname );
500 return ;
501 }
502
503 // if in app and should be in global, then move it
504 if ( !global )
505 return;
506 if ( removeCategory( appname, catname, FALSE ) )
507 addGlobalCategory( catname );
508}
509
510bool Categories::isGlobal( const QString &catname ) const
511{
512 return mGlobalCats.contains( catname );
513}
514
515
516/** Returns true if the catname is associated with any application
517 */
518bool Categories::exists( const QString &catname ) const
519{
520 if ( isGlobal(catname) )
521 return TRUE;
522
523 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt )
524 if ( exists( appsIt.key(), catname ) )
525 return TRUE;
526
527 return FALSE;
528}
529
530bool Categories::exists( const QString &appname,
531 const QString &catname) const
532{
533 QMap< QString, CategoryGroup >::ConstIterator
534 appIt = mAppCats.find( appname );
535
536 if ( appIt == mAppCats.end() )
537 return FALSE;
538
539 return (*appIt).contains( catname );
540}
541
542bool Categories::save( const QString &fname ) const
543{
544 QFile file( fname );
545 if ( !file.open( IO_WriteOnly ) ) {
546 qWarning("Unable to write to %s", fname.latin1());
547 return FALSE;
548 }
549
550 QTextStream ts( &file );
551 ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
552 ts << "<!DOCTYPE CategoryList>" << endl;
553
554 ts << "<Categories>" << endl;
555 for ( QMap<int, QString>::ConstIterator git = mGlobalCats.idMap().begin();
556 git != mGlobalCats.idMap().end(); ++git )
557 ts << "<Category id=\"" << git.key() << "\""
558 << " name=\"" << escapeString(*git) << "\" />" << endl;
559
560 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt=mAppCats.begin();
561 appsIt != mAppCats.end(); ++appsIt ) {
562 const QString &app = appsIt.key();
563 const QMap<int, QString> &appcats = (*appsIt).idMap();
564 for ( QMap<int, QString>::ConstIterator appcatit = appcats.begin();
565 appcatit != appcats.end(); ++appcatit )
566 ts << "<Category id=\"" << appcatit.key() << "\""
567 << " app=\"" << escapeString(app) << "\""
568 << " name=\"" << escapeString(*appcatit) << "\" />" << endl;
569 }
570 ts << "</Categories>" << endl;
571
572 file.close();
573 return TRUE;
574}
575
576bool Categories::load( const QString &fname )
577{
578 QFile file( fname );
579 if ( !file.open( IO_ReadOnly ) ) {
580 qWarning("Unable to open %s", fname.latin1());
581 return FALSE;
582 }
583
584 clear();
585 QByteArray ba = file.readAll();
586 QString data = QString::fromUtf8( ba.data(), ba.size() );
587 QChar *uc = (QChar *)data.unicode();
588 int len = data.length();
589
590 // QTime t;
591 // t.start();
592 QString name;
593 QString id;
594 QString app;
595 int i = 0;
596 while ( (i = data.find( "<Category ", i)) != -1 ) {
597
598 i += 10;
599 name = QString::null;
600 app = QString::null;
601 while ( 1 ) {
602 // skip white space
603 while ( i < len &&
604 (uc[i] == ' ' || uc[i] == '\n' || uc[i] == '\r') )
605 i++;
606 // if at the end, then done
607 if ( i >= len-2 || (uc[i] == '/' && uc[i+1] == '>') )
608 break;
609 // we have another attribute read it.
610 int j = i;
611 while ( j < len && uc[j] != '=' )
612 j++;
613 QString attr = QConstString( uc+i, j-i ).string();
614 i = ++j; // skip =
615 while ( i < len && uc[i] != '"' )
616 i++;
617 j = ++i;
618 while ( j < len && uc[j] != '"' )
619 j++;
620 QString value = Qtopia::plainString( QConstString( uc+i, j-i ).string() );
621 i = j + 1;
622
623 // qDebug("attr='%s' value='%s'", attr.latin1(), value.latin1() );
624 if ( attr == "id" )
625 id = value;
626 else if ( attr == "app" )
627 app = value;
628
629 else if ( attr == "name" )
630 name = value;
631 }
632
633 if ( name.isNull() || id.isNull() ) {
634 qWarning("No name or id in the category");
635 continue;
636 }
637 if ( app.isNull() )
638 mGlobalCats.add( id.toInt(), name );
639 else
640 mAppCats[ app ].add( id.toInt(), name );
641 }
642
643 return TRUE;
644}
645
646void Categories::clear()
647{
648 mGlobalCats.clear();
649 mAppCats.clear();
650}
651
652void Categories::dump() const
653{
654 qDebug("\tglobal categories = %s", mGlobalCats.labels().join(", ").latin1() );
655 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt ) {
656 const QString &app = appsIt.key();
657 QStringList appcats = (*appsIt).labels();
658 qDebug("\tapp = %s\tcategories = %s", app.latin1(),
659 appcats.join(", ").latin1() );
660
661 }
662}
663
664QStringList CheckedListView::checked() const
665{
666 QStringList strs;
667 for ( QCheckListItem *i = (QCheckListItem *) firstChild();
668 i; i = (QCheckListItem *)i->nextSibling() )
669 if ( i->isOn() )
670 strs += i->text( 0 );
671 return strs;
672}
673
674void CheckedListView::addCheckableList( const QStringList &options )
675{
676 for ( QStringList::ConstIterator it = options.begin();
677 it != options.end(); ++it ) {
678 (void) new QCheckListItem( this, *it,
679 QCheckListItem::CheckBox );
680 }
681}
682
683void CheckedListView::setChecked( const QStringList &checked )
684{
685 // iterate over all items
686 bool showingChecked = FALSE;
687 for ( QCheckListItem *i = (QCheckListItem *) firstChild();
688 i; i = (QCheckListItem *)i->nextSibling() )
689 // see if the item should be checked by searching the
690 // checked list
691 if ( checked.find( i->text( 0 ) ) != checked.end() ) {
692 i->setOn( TRUE );
693 // make sure it is showing at least one checked item
694 if ( !showingChecked ) {
695 ensureItemVisible( i );
696 showingChecked = TRUE;
697 }
698 }
699 else
700 i->setOn( FALSE );
701}
diff --git a/library/backend/categories.h b/library/backend/categories.h
new file mode 100644
index 0000000..82d765b
--- a/dev/null
+++ b/library/backend/categories.h
@@ -0,0 +1,232 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free
8** Software Foundation and appearing in the file LICENSE.GPL included
9** in the packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
12** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
13** PARTICULAR PURPOSE.
14**
15** See http://www.trolltech.com/gpl/ for GPL licensing information.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21
22#ifndef QTPALMTOP_CATEGORIES_H
23#define QTPALMTOP_CATEGORIES_H
24
25#include <qstring.h>
26#include <qstringlist.h>
27#include <qmap.h>
28#include <qlistview.h>
29#include <qarray.h>
30#include "qpcglobal.h"
31#include "palmtopuidgen.h"
32
33class CategoryGroup;
34
35#if defined(QPC_TEMPLATEDLL)
36// MOC_SKIP_BEGIN
37template class QPC_EXPORT QMap<int, QString>;
38template class QPC_EXPORT QMap<QString, int>;
39template class QPC_EXPORT QMap< QString, CategoryGroup >;
40// MOC_SKIP_END
41#endif
42
43class QPC_EXPORT CategoryGroup
44{
45 friend class Categories;
46public:
47 CategoryGroup(): mIdLabelMap(), mLabelIdMap() { }
48 CategoryGroup( const CategoryGroup &c ) :
49 mIdLabelMap( c.mIdLabelMap), mLabelIdMap( c.mLabelIdMap ) { }
50
51 void clear() { mIdLabelMap.clear(); mLabelIdMap.clear(); }
52
53 int add( const QString &label );
54 bool add( int uid, const QString &label );
55
56 bool remove( const QString &label );
57 bool remove( int uid );
58
59 bool rename( int uid, const QString &newLabel );
60 bool rename( const QString &oldLabel, const QString &newLabel );
61
62 bool contains(int id) const;
63 bool contains(const QString &label) const;
64
65 /** Returns label associated with the uid or QString::null if
66 * not found
67 */
68 const QString &label(int id) const;
69 /** Returns the uid associated with label or 0 if not found */
70 int id(const QString &label) const;
71
72 /** Returns a sorted list of labels */
73 QStringList labels() const;
74 QArray<int> ids( const QStringList &cats ) const;
75 QArray<int> ids() const;
76 QStringList labels( const QArray<int> &catids ) const;
77
78 const QMap<int, QString> &idMap() const { return mIdLabelMap; }
79
80private:
81 void insert( int uid, const QString &label );
82 QMap<int, QString> mIdLabelMap;
83 QMap<QString, int> mLabelIdMap;
84
85 static Qtopia::UidGen &uidGen() { return sUidGen; }
86 static Qtopia::UidGen sUidGen;
87};
88
89/** Map from application name to categories */
90class QPC_EXPORT Categories : public QObject
91{
92 Q_OBJECT
93public:
94 Categories( QObject *parent=0, const char *name = 0 )
95 : QObject( parent, name ), mGlobalCats(), mAppCats() { }
96 Categories( const Categories &copyFrom ) : QObject( copyFrom.parent() ),
97 mGlobalCats( copyFrom.mGlobalCats ),
98 mAppCats( copyFrom.mAppCats ) { }
99 virtual ~Categories() { }
100
101 Categories &operator= ( const Categories &c )
102{ mAppCats = c.mAppCats; mGlobalCats = c.mGlobalCats; return *this; }
103
104 void clear();
105
106 /** Add the category name as long as it doesn't already exist
107 * locally or globally. Return UID if added, 0 if conflicts
108 * (error).
109 */
110 int addCategory( const QString &appname, const QString &catname);
111 /** Add the category name as long as it doesn't already exist
112 * locally or globally. Return UID if added, 0 if conflicts
113 * (error).
114 */
115 int addCategory( const QString &appname, const QString &catname, int uid);
116 /** Add the global category just checking that it doesn't
117 * already exist globally. Return UID if added, 0 if conflicts.
118 */
119 int addGlobalCategory( const QString &catname );
120 /** Add the global category just checking that it doesn't
121 * already exist globally. Return UID if added, 0 if conflicts.
122 */
123 int addGlobalCategory( const QString &catname, int uid );
124 /** Removes the category from the application; if it is not found
125 * in the application, then it removes it from the global list
126 */
127 bool removeCategory( const QString &appName, const QString &catName,
128 bool checkGlobal = TRUE);
129 bool removeCategory( const QString &appName, int uid );
130 bool removeGlobalCategory( const QString &catName );
131 bool removeGlobalCategory( int uid );
132
133 QArray<int> ids( const QString &app ) const;
134 QArray<int> ids( const QString &app,
135 const QStringList &cats ) const;
136 /** Returns the id associated with the app */
137 int id( const QString &app, const QString &cat ) const;
138 /** Returns the label associated with the id */
139 QString label( const QString &app, int id ) const;
140
141 enum ExtraLabels { NoExtra, AllUnfiled, AllLabel, UnfiledLabel };
142 /** Returns the sorted list of all categories that are
143 * associated with the app.
144 * If includeGlobal parameter is TRUE then the returned
145 * categories will include the global category items.
146 * If extra = NoExtra, then
147 * If extra = AllUnfiled, then All and Unfiled will be prepended to
148 * the list
149 * If extra = AllLabel, then All is prepended
150 * If extra = UnfiledLabel, then Unfiled is prepended
151 */
152 QStringList labels( const QString &app,
153 bool includeGlobal = TRUE,
154 ExtraLabels extra = NoExtra ) const;
155
156 /** Returns the labels of the categories associated with the uids */
157 QStringList labels( const QString & app,
158 const QArray<int> &catids ) const;
159
160 enum DisplaySingle { ShowMulti, ShowAll, ShowFirst };
161
162 /** Returns a single string associated with the cat ids for display in
163 * a combobox or any area that requires one string. If catids are empty
164 * then "Unfiled" will be returned. If multiple categories are assigned
165 * then the behavior depends on the DisplaySingle type.
166 * If /a display is set to ShowMulti then " (multi)" appended to the
167 * first string. If /a display is set to ShowAll, then a space seperated
168 * string is returned with all categories. If ShowFirst is returned,
169 * the just the first string is returned.
170 */
171 QString displaySingle( const QString &app,
172 const QArray<int> &catids,
173 DisplaySingle display ) const;
174
175 QStringList globalCategories() const { return mGlobalCats.labels();}
176
177 bool renameCategory( const QString &appname,
178 const QString &oldName,
179 const QString &newName );
180 bool renameGlobalCategory( const QString &oldName,
181 const QString &newName );
182
183 void setGlobal( const QString &appname, const QString &catname,
184 bool value );
185 bool isGlobal( const QString &catname ) const;
186
187
188 /** Returns true if the catname is associated with any application
189 */
190 bool exists( const QString &catname ) const;
191 bool exists( const QString &appname, const QString &catname) const;
192
193 bool save( const QString &fname ) const;
194 bool load( const QString &fname );
195
196 // for debugging
197 void dump() const;
198
199 const QMap<QString, CategoryGroup> &appGroupMap() const{ return mAppCats; }
200 const CategoryGroup &globalGroup() const { return mGlobalCats; }
201
202signals:
203 /** emitted if added a category;
204 * the second param is the application the category was added to
205 * or null if global
206 * the third param is the uid of the newly added category
207 */
208 void categoryAdded( const Categories &, const QString &, int );
209 /** emitted if removed a category
210 * the second param is the application the category was removed from
211 * or null if global
212 * the third param is the uid of the removed category
213 */
214 void categoryRemoved( const Categories &, const QString &, int );
215 /** emitted if a category is renamed; the second param is the uid of
216 * the removed category */
217 void categoryRenamed( const Categories &, const QString &, int );
218
219private:
220 CategoryGroup mGlobalCats;
221 QMap< QString, CategoryGroup > mAppCats;
222};
223
224class QPC_EXPORT CheckedListView : public QListView
225{
226public:
227 void addCheckableList( const QStringList &options );
228 void setChecked( const QStringList &checked );
229 QStringList checked() const;
230};
231
232#endif
diff --git a/library/backend/contact.cpp b/library/backend/contact.cpp
new file mode 100644
index 0000000..a5f10ab
--- a/dev/null
+++ b/library/backend/contact.cpp
@@ -0,0 +1,909 @@
1/**********************************************************************
2** Copyright (C) 2001 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#include "contact.h"
22#include "vobject_p.h"
23#include "qfiledirect_p.h"
24
25#include <qpe/stringutil.h>
26#include <qpe/timeconversion.h>
27
28#include <qobject.h>
29#include <qregexp.h>
30#include <qstylesheet.h>
31#include <qfileinfo.h>
32
33#include <stdio.h>
34
35Qtopia::UidGen Contact::sUidGen( Qtopia::UidGen::Qtopia );
36
37Contact::Contact()
38 : Record(), mMap(), d( 0 )
39{
40}
41
42Contact::Contact( const QMap<int, QString> &fromMap ) :
43 Record(), mMap( fromMap ), d( 0 )
44{
45 QString cats = mMap[ Qtopia::AddressCategory ];
46 if ( !cats.isEmpty() )
47 setCategories( idsFromString( cats ) );
48 QString uidStr = find( Qtopia::AddressUid );
49 if ( uidStr.isEmpty() )
50 setUid( uidGen().generate() );
51 else
52 setUid( uidStr.toInt() );
53}
54
55Contact::~Contact()
56{
57}
58
59QMap<int, QString> Contact::toMap() const
60{
61 QMap<int, QString> map = mMap;
62 map.insert( Qtopia::AddressCategory, idsToString( categories() ));
63 return map;
64}
65
66/*!
67 Returns a rich text formatted QString of the Contact.
68*/
69QString Contact::toRichText() const
70{
71 QString text;
72 QString value, comp, state;
73
74 // name, jobtitle and company
75 if ( !(value = fullName()).isEmpty() )
76 text += "<b>" + Qtopia::escapeString(value) + "</b><br>";
77 if ( !(value = jobTitle()).isEmpty() )
78 text += Qtopia::escapeString(value) + "<br>";
79
80 comp = company();
81 if ( !(value = department()).isEmpty() ) {
82 text += Qtopia::escapeString(value);
83 if ( comp )
84 text += ", ";
85 else
86 text += "<br>";
87 }
88 if ( !comp.isEmpty() )
89 text += Qtopia::escapeString(comp) + "<br>";
90
91 // business address
92 if ( !businessStreet().isEmpty() || !businessCity().isEmpty() ||
93 !businessZip().isEmpty() || !businessCountry().isEmpty() ) {
94 text += "<br>";
95 text += QObject::tr( "<b>Work Address:</b>" );
96 text += "<br>";
97 }
98
99 if ( !(value = businessStreet()).isEmpty() )
100 text += Qtopia::escapeString(value) + "<br>";
101 state = businessState();
102 if ( !(value = businessCity()).isEmpty() ) {
103 text += Qtopia::escapeString(value);
104 if ( state )
105 text += ", " + Qtopia::escapeString(state);
106 text += "<br>";
107 } else if ( !state.isEmpty() )
108 text += Qtopia::escapeString(state) + "<br>";
109 if ( !(value = businessZip()).isEmpty() )
110 text += Qtopia::escapeString(value) + "<br>";
111 if ( !(value = businessCountry()).isEmpty() )
112 text += Qtopia::escapeString(value) + "<br>";
113
114 // home address
115 if ( !homeStreet().isEmpty() || !homeCity().isEmpty() ||
116 !homeZip().isEmpty() || !homeCountry().isEmpty() ) {
117 text += "<br>";
118 text += QObject::tr( "<b>Home Address:</b>" );
119 text += "<br>";
120 }
121
122 if ( !(value = homeStreet()).isEmpty() )
123 text += Qtopia::escapeString(value) + "<br>";
124 state = homeState();
125 if ( !(value = homeCity()).isEmpty() ) {
126 text += Qtopia::escapeString(value);
127 if ( !state.isEmpty() )
128 text += ", " + Qtopia::escapeString(state);
129 text += "<br>";
130 } else if (!state.isEmpty())
131 text += Qtopia::escapeString(state) + "<br>";
132 if ( !(value = homeZip()).isEmpty() )
133 text += Qtopia::escapeString(value) + "<br>";
134 if ( !(value = homeCountry()).isEmpty() )
135 text += Qtopia::escapeString(value) + "<br>";
136
137 // the others...
138 QString str;
139 str = emails();
140 if ( !str.isEmpty() )
141 text += "<b>" + QObject::tr("Email Addresses: ") + "</b>"
142 + Qtopia::escapeString(str) + "<br>";
143 str = homePhone();
144 if ( !str.isEmpty() )
145 text += "<b>" + QObject::tr("Home Phone: ") + "</b>"
146 + Qtopia::escapeString(str) + "<br>";
147 str = homeFax();
148 if ( !str.isEmpty() )
149 text += "<b>" + QObject::tr("Home Fax: ") + "</b>"
150 + Qtopia::escapeString(str) + "<br>";
151 str = homeMobile();
152 if ( !str.isEmpty() )
153 text += "<b>" + QObject::tr("Home Mobile: ") + "</b>"
154 + Qtopia::escapeString(str) + "<br>";
155 str = homeWebpage();
156 if ( !str.isEmpty() )
157 text += "<b>" + QObject::tr("Home Web Page: ") + "</b>"
158 + Qtopia::escapeString(str) + "<br>";
159 str = businessWebpage();
160 if ( !str.isEmpty() )
161 text += "<b>" + QObject::tr("Business Web Page: ") + "</b>"
162 + Qtopia::escapeString(str) + "<br>";
163 str = office();
164 if ( !str.isEmpty() )
165 text += "<b>" + QObject::tr("Office: ") + "</b>"
166 + Qtopia::escapeString(str) + "<br>";
167 str = businessPhone();
168 if ( !str.isEmpty() )
169 text += "<b>" + QObject::tr("Business Phone: ") + "</b>"
170 + Qtopia::escapeString(str) + "<br>";
171 str = businessFax();
172 if ( !str.isEmpty() )
173 text += "<b>" + QObject::tr("Business Fax: ") + "</b>"
174 + Qtopia::escapeString(str) + "<br>";
175 str = businessMobile();
176 if ( !str.isEmpty() )
177 text += "<b>" + QObject::tr("Business Mobile: ") + "</b>"
178 + Qtopia::escapeString(str) + "<br>";
179 str = businessPager();
180 if ( !str.isEmpty() )
181 text += "<b>" + QObject::tr("Business Pager: ") + "</b>"
182 + Qtopia::escapeString(str) + "<br>";
183 str = profession();
184 if ( !str.isEmpty() )
185 text += "<b>" + QObject::tr("Profession: ") + "</b>"
186 + Qtopia::escapeString(str) + "<br>";
187 str = assistant();
188 if ( !str.isEmpty() )
189 text += "<b>" + QObject::tr("Assistant: ") + "</b>"
190 + Qtopia::escapeString(str) + "<br>";
191 str = manager();
192 if ( !str.isEmpty() )
193 text += "<b>" + QObject::tr("Manager: ") + "</b>"
194 + Qtopia::escapeString(str) + "<br>";
195 str = gender();
196 if ( !str.isEmpty() && str.toInt() != 0 ) {
197 if ( str.toInt() == 1 )
198 str = QObject::tr( "Male" );
199 else if ( str.toInt() == 2 )
200 str = QObject::tr( "Female" );
201 text += "<b>" + QObject::tr("Gender: ") + "</b>" + str + "<br>";
202 }
203 str = spouse();
204 if ( !str.isEmpty() )
205 text += "<b>" + QObject::tr("Spouse: ") + "</b>"
206 + Qtopia::escapeString(str) + "<br>";
207 str = birthday();
208 if ( !str.isEmpty() )
209 text += "<b>" + QObject::tr("Birthday: ") + "</b>"
210 + Qtopia::escapeString(str) + "<br>";
211 str = anniversary();
212 if ( !str.isEmpty() )
213 text += "<b>" + QObject::tr("Anniversary: ") + "</b>"
214 + Qtopia::escapeString(str) + "<br>";
215 str = nickname();
216 if ( !str.isEmpty() )
217 text += "<b>" + QObject::tr("Nickname: ") + "</b>"
218 + Qtopia::escapeString(str) + "<br>";
219
220 // notes last
221 if ( (value = notes()) ) {
222 QRegExp reg("\n");
223
224 //QString tmp = Qtopia::escapeString(value);
225 QString tmp = QStyleSheet::convertFromPlainText(value);
226 //tmp.replace( reg, "<br>" );
227 text += "<br>" + tmp + "<br>";
228 }
229 return text;
230}
231
232void Contact::insert( int key, const QString &v )
233{
234 QString value = v.stripWhiteSpace();
235 if ( value.isEmpty() )
236 mMap.remove( key );
237 else
238 mMap.insert( key, value );
239}
240
241void Contact::replace( int key, const QString & v )
242{
243 QString value = v.stripWhiteSpace();
244 if ( value.isEmpty() )
245 mMap.remove( key );
246 else
247 mMap.replace( key, value );
248}
249
250QString Contact::find( int key ) const
251{
252 return mMap[key];
253}
254
255QString Contact::displayAddress( const QString &street,
256 const QString &city,
257 const QString &state,
258 const QString &zip,
259 const QString &country ) const
260{
261 QString s = street;
262 if ( !street.isEmpty() )
263 s+= "\n";
264 s += city;
265 if ( !city.isEmpty() && !state.isEmpty() )
266 s += ", ";
267 s += state;
268 if ( !state.isEmpty() && !zip.isEmpty() )
269 s += " ";
270 s += zip;
271 if ( !country.isEmpty() && !s.isEmpty() )
272 s += "\n";
273 s += country;
274 return s;
275}
276
277QString Contact::displayBusinessAddress() const
278{
279 return displayAddress( businessStreet(), businessCity(),
280 businessState(), businessZip(),
281 businessCountry() );
282}
283
284QString Contact::displayHomeAddress() const
285{
286 return displayAddress( homeStreet(), homeCity(),
287 homeState(), homeZip(),
288 homeCountry() );
289}
290
291QString Contact::fullName() const
292{
293 QString title = find( Qtopia::Title );
294 QString firstName = find( Qtopia::FirstName );
295 QString middleName = find( Qtopia::MiddleName );
296 QString lastName = find( Qtopia::LastName );
297 QString suffix = find( Qtopia::Suffix );
298
299 QString name = title;
300 if ( !firstName.isEmpty() ) {
301 if ( !name.isEmpty() )
302 name += " ";
303 name += firstName;
304 }
305 if ( !middleName.isEmpty() ) {
306 if ( !name.isEmpty() )
307 name += " ";
308 name += middleName;
309 }
310 if ( !lastName.isEmpty() ) {
311 if ( !name.isEmpty() )
312 name += " ";
313 name += lastName;
314 }
315 if ( !suffix.isEmpty() ) {
316 if ( !name.isEmpty() )
317 name += " ";
318 name += suffix;
319 }
320 return name.simplifyWhiteSpace();
321}
322
323QStringList Contact::childrenList() const
324{
325 return QStringList::split( " ", find( Qtopia::Children ) );
326}
327
328QStringList Contact::emailList() const
329{
330 return QStringList::split( ";", find( Qtopia::Emails ) );
331}
332
333void Contact::setFileAs()
334{
335 QString lastName, firstName, middleName, fileas;
336
337 lastName = find( Qtopia::LastName );
338 firstName = find( Qtopia::FirstName );
339 middleName = find( Qtopia::MiddleName );
340 if ( !lastName.isEmpty() && !firstName.isEmpty()
341 && !middleName.isEmpty() )
342 fileas = lastName + ", " + firstName + " " + middleName;
343 else if ( !lastName.isEmpty() && !firstName.isEmpty() )
344 fileas = lastName + ", " + firstName;
345 else if ( !lastName.isEmpty() || !firstName.isEmpty() ||
346 !middleName.isEmpty() )
347 fileas = firstName + ( firstName.isEmpty() ? "" : " " )
348 + middleName + ( middleName.isEmpty() ? "" : " " )
349 + lastName;
350
351 replace( Qtopia::FileAs, fileas );
352}
353
354void Contact::save( QString &buf ) const
355{
356 static const QStringList SLFIELDS = fields();
357 // I'm expecting "<Contact " in front of this...
358 for ( QMap<int, QString>::ConstIterator it = mMap.begin();
359 it != mMap.end(); ++it ) {
360 const QString &value = it.data();
361 int key = it.key();
362 if ( !value.isEmpty() ) {
363 if ( key == Qtopia::AddressCategory || key == Qtopia::AddressUid)
364 continue;
365
366 key -= Qtopia::AddressCategory+1;
367 buf += SLFIELDS[key];
368 buf += "=\"" + Qtopia::escapeString(value) + "\" ";
369 }
370 }
371 buf += customToXml();
372 if ( categories().count() > 0 )
373 buf += "Categories=\"" + idsToString( categories() ) + "\" ";
374 buf += "Uid=\"" + QString::number( uid() ) + "\" ";
375 // You need to close this yourself
376}
377
378QStringList Contact::fields()
379{
380 QStringList list;
381
382 list.append( "Title" ); // Not Used!
383 list.append( "FirstName" );
384 list.append( "MiddleName" );
385 list.append( "LastName" );
386 list.append( "Suffix" );
387 list.append( "FileAs" );
388
389 list.append( "DefaultEmail" );
390 list.append( "Emails" );
391
392 list.append( "HomeStreet" );
393 list.append( "HomeCity" );
394 list.append( "HomeState" );
395 list.append( "HomeZip" );
396 list.append( "HomeCountry" );
397 list.append( "HomePhone" );
398 list.append( "HomeFax" );
399 list.append( "HomeMobile" );
400 list.append( "HomeWebPage" );
401
402 list.append( "Company" );
403 list.append( "BusinessStreet" );
404 list.append( "BusinessCity" );
405 list.append( "BusinessState" );
406 list.append( "BusinessZip" );
407 list.append( "BusinessCountry" );
408 list.append( "BusinessWebPage" );
409 list.append( "JobTitle" );
410 list.append( "Department" );
411 list.append( "Office" );
412 list.append( "BusinessPhone" );
413 list.append( "BusinessFax" );
414 list.append( "BusinessMobile" );
415 list.append( "BusinessPager" );
416 list.append( "Profession" );
417 list.append( "Assistant" );
418 list.append( "Manager" );
419
420 list.append( "Spouse" );
421 list.append( "Gender" );
422 list.append( "Birthday" );
423 list.append( "Anniversary" );
424 list.append( "Nickname" );
425
426 list.append( "Children" );
427 list.append( "Notes" );
428
429 return list;
430}
431
432QStringList Contact::trfields()
433{
434 QStringList list;
435
436 list.append( QObject::tr( "Name Title") );
437 list.append( QObject::tr( "First Name" ) );
438 list.append( QObject::tr( "Middle Name" ) );
439 list.append( QObject::tr( "Last Name" ) );
440 list.append( QObject::tr( "Suffix" ) );
441 list.append( QObject::tr( "File As" ) );
442
443 list.append( QObject::tr( "Default Email" ) );
444 list.append( QObject::tr( "Emails" ) );
445
446 list.append( QObject::tr( "Home Street" ) );
447 list.append( QObject::tr( "Home City" ) );
448 list.append( QObject::tr( "Home State" ) );
449 list.append( QObject::tr( "Home Zip" ) );
450 list.append( QObject::tr( "Home Country" ) );
451 list.append( QObject::tr( "Home Phone" ) );
452 list.append( QObject::tr( "Home Fax" ) );
453 list.append( QObject::tr( "Home Mobile" ) );
454 list.append( QObject::tr( "Home Web Page" ) );
455
456 list.append( QObject::tr( "Company" ) );
457 list.append( QObject::tr( "Business Street" ) );
458 list.append( QObject::tr( "Business City" ) );
459 list.append( QObject::tr( "Business State" ) );
460 list.append( QObject::tr( "Business Zip" ) );
461 list.append( QObject::tr( "Business Country" ) );
462 list.append( QObject::tr( "Business WebPage" ) );
463 list.append( QObject::tr( "Job Title" ) );
464 list.append( QObject::tr( "Department" ) );
465 list.append( QObject::tr( "Office" ) );
466 list.append( QObject::tr( "Business Phone" ) );
467 list.append( QObject::tr( "Business Fax" ) );
468 list.append( QObject::tr( "Business Mobile" ) );
469 list.append( QObject::tr( "Business Pager" ) );
470 list.append( QObject::tr( "Profession" ) );
471 list.append( QObject::tr( "Assistant" ) );
472 list.append( QObject::tr( "Manager" ) );
473
474 list.append( QObject::tr( "Spouse" ) );
475 list.append( QObject::tr( "Gender" ) );
476 list.append( QObject::tr( "Birthday" ) );
477 list.append( QObject::tr( "Anniversary" ) );
478 list.append( QObject::tr( "Nickname" ) );
479
480 list.append( QObject::tr( "Children" ) );
481 list.append( QObject::tr( "Notes" ) );
482
483 return list;
484}
485
486void Contact::setEmails( const QString &v )
487{
488 replace( Qtopia::Emails, v );
489 if ( v.isEmpty() )
490 setDefaultEmail( QString::null );
491}
492
493void Contact::setChildren( const QString &v )
494{
495 replace( Qtopia::Children, v );
496}
497
498// vcard conversion code
499static inline VObject *safeAddPropValue( VObject *o, const char *prop, const QString &value )
500{
501 VObject *ret = 0;
502 if ( o && !value.isEmpty() )
503 ret = addPropValue( o, prop, value.latin1() );
504 return ret;
505}
506
507static inline VObject *safeAddProp( VObject *o, const char *prop)
508{
509 VObject *ret = 0;
510 if ( o )
511 ret = addProp( o, prop );
512 return ret;
513}
514
515static VObject *createVObject( const Contact &c )
516{
517 VObject *vcard = newVObject( VCCardProp );
518 safeAddPropValue( vcard, VCVersionProp, "2.1" );
519 safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) );
520 safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) );
521
522 // full name
523 safeAddPropValue( vcard, VCFullNameProp, c.fullName() );
524
525 // name properties
526 VObject *name = safeAddProp( vcard, VCNameProp );
527 safeAddPropValue( name, VCFamilyNameProp, c.lastName() );
528 safeAddPropValue( name, VCGivenNameProp, c.firstName() );
529 safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() );
530 safeAddPropValue( name, VCNamePrefixesProp, c.title() );
531 safeAddPropValue( name, VCNameSuffixesProp, c.suffix() );
532
533 // home properties
534 VObject *home_adr= safeAddProp( vcard, VCAdrProp );
535 safeAddProp( home_adr, VCHomeProp );
536 safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() );
537 safeAddPropValue( home_adr, VCCityProp, c.homeCity() );
538 safeAddPropValue( home_adr, VCRegionProp, c.homeState() );
539 safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() );
540 safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() );
541
542 VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() );
543 safeAddProp( home_phone, VCHomeProp );
544 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() );
545 safeAddProp( home_phone, VCHomeProp );
546 safeAddProp( home_phone, VCCellularProp );
547 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() );
548 safeAddProp( home_phone, VCHomeProp );
549 safeAddProp( home_phone, VCFaxProp );
550
551 VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() );
552 safeAddProp( url, VCHomeProp );
553
554 // work properties
555 VObject *work_adr= safeAddProp( vcard, VCAdrProp );
556 safeAddProp( work_adr, VCWorkProp );
557 safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() );
558 safeAddPropValue( work_adr, VCCityProp, c.businessCity() );
559 safeAddPropValue( work_adr, VCRegionProp, c.businessState() );
560 safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() );
561 safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() );
562
563 VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() );
564 safeAddProp( work_phone, VCWorkProp );
565 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() );
566 safeAddProp( work_phone, VCWorkProp );
567 safeAddProp( work_phone, VCCellularProp );
568 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() );
569 safeAddProp( work_phone, VCWorkProp );
570 safeAddProp( work_phone, VCFaxProp );
571 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() );
572 safeAddProp( work_phone, VCWorkProp );
573 safeAddProp( work_phone, VCPagerProp );
574
575 url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() );
576 safeAddProp( url, VCWorkProp );
577
578 VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() );
579 safeAddProp( title, VCWorkProp );
580
581
582 QStringList emails = c.emailList();
583 emails.prepend( c.defaultEmail() );
584 for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) {
585 VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it );
586 safeAddProp( email, VCInternetProp );
587 }
588
589 safeAddPropValue( vcard, VCNoteProp, c.notes() );
590
591 safeAddPropValue( vcard, VCBirthDateProp, c.birthday() );
592
593 if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) {
594 VObject *org = safeAddProp( vcard, VCOrgProp );
595 safeAddPropValue( org, VCOrgNameProp, c.company() );
596 safeAddPropValue( org, VCOrgUnitProp, c.department() );
597 safeAddPropValue( org, VCOrgUnit2Prop, c.office() );
598 }
599
600 // some values we have to export as custom fields
601 safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() );
602 safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() );
603 safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() );
604
605 safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() );
606 safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() );
607 safeAddPropValue( vcard, "X-Qtopia-Anniversary", c.anniversary() );
608 safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() );
609 safeAddPropValue( vcard, "X-Qtopia-Children", c.children() );
610
611 return vcard;
612}
613
614
615static Contact parseVObject( VObject *obj )
616{
617 Contact c;
618
619 bool haveDefaultEmail = FALSE;
620
621 VObjectIterator it;
622 initPropIterator( &it, obj );
623 while( moreIteration( &it ) ) {
624 VObject *o = nextVObject( &it );
625 QCString name = vObjectName( o );
626 QCString value = vObjectStringZValue( o );
627 if ( name == VCNameProp ) {
628 VObjectIterator nit;
629 initPropIterator( &nit, o );
630 while( moreIteration( &nit ) ) {
631 VObject *o = nextVObject( &nit );
632 QCString name = vObjectName( o );
633 QString value = vObjectStringZValue( o );
634 if ( name == VCNamePrefixesProp )
635 c.setTitle( value );
636 else if ( name == VCNameSuffixesProp )
637 c.setSuffix( value );
638 else if ( name == VCFamilyNameProp )
639 c.setLastName( value );
640 else if ( name == VCGivenNameProp )
641 c.setFirstName( value );
642 else if ( name == VCAdditionalNamesProp )
643 c.setMiddleName( value );
644 }
645 }
646 else if ( name == VCAdrProp ) {
647 bool work = TRUE; // default address is work address
648 QString street;
649 QString city;
650 QString region;
651 QString postal;
652 QString country;
653
654 VObjectIterator nit;
655 initPropIterator( &nit, o );
656 while( moreIteration( &nit ) ) {
657 VObject *o = nextVObject( &nit );
658 QCString name = vObjectName( o );
659 QString value = vObjectStringZValue( o );
660 if ( name == VCHomeProp )
661 work = FALSE;
662 else if ( name == VCWorkProp )
663 work = TRUE;
664 else if ( name == VCStreetAddressProp )
665 street = value;
666 else if ( name == VCCityProp )
667 city = value;
668 else if ( name == VCRegionProp )
669 region = value;
670 else if ( name == VCPostalCodeProp )
671 postal = value;
672 else if ( name == VCCountryNameProp )
673 country = value;
674 }
675 if ( work ) {
676 c.setBusinessStreet( street );
677 c.setBusinessCity( city );
678 c.setBusinessCountry( country );
679 c.setBusinessZip( postal );
680 c.setBusinessState( region );
681 } else {
682 c.setHomeStreet( street );
683 c.setHomeCity( city );
684 c.setHomeCountry( country );
685 c.setHomeZip( postal );
686 c.setHomeState( region );
687 }
688 }
689 else if ( name == VCTelephoneProp ) {
690 enum {
691 HOME = 0x01,
692 WORK = 0x02,
693 VOICE = 0x04,
694 CELL = 0x08,
695 FAX = 0x10,
696 PAGER = 0x20,
697 UNKNOWN = 0x80
698 };
699 int type = 0;
700
701 VObjectIterator nit;
702 initPropIterator( &nit, o );
703 while( moreIteration( &nit ) ) {
704 VObject *o = nextVObject( &nit );
705 QCString name = vObjectName( o );
706 if ( name == VCHomeProp )
707 type |= HOME;
708 else if ( name == VCWorkProp )
709 type |= WORK;
710 else if ( name == VCVoiceProp )
711 type |= VOICE;
712 else if ( name == VCCellularProp )
713 type |= CELL;
714 else if ( name == VCFaxProp )
715 type |= FAX;
716 else if ( name == VCPagerProp )
717 type |= PAGER;
718 else if ( name == VCPreferredProp )
719 ;
720 else
721 type |= UNKNOWN;
722 }
723 if ( (type & UNKNOWN) != UNKNOWN ) {
724 if ( ( type & (HOME|WORK) ) == 0 ) // default
725 type |= HOME;
726 if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default
727 type |= VOICE;
728
729 if ( (type & (VOICE|HOME) ) == (VOICE|HOME) )
730 c.setHomePhone( value );
731 if ( ( type & (FAX|HOME) ) == (FAX|HOME) )
732 c.setHomeFax( value );
733 if ( ( type & (CELL|HOME) ) == (CELL|HOME) )
734 c.setHomeMobile( value );
735 if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) )
736 c.setBusinessPhone( value );
737 if ( ( type & (FAX|WORK) ) == (FAX|WORK) )
738 c.setBusinessFax( value );
739 if ( ( type & (CELL|WORK) ) == (CELL|WORK) )
740 c.setBusinessMobile( value );
741 if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) )
742 c.setBusinessPager( value );
743 }
744 }
745 else if ( name == VCEmailAddressProp ) {
746 QString email = vObjectStringZValue( o );
747 bool valid = TRUE;
748 VObjectIterator nit;
749 initPropIterator( &nit, o );
750 while( moreIteration( &nit ) ) {
751 VObject *o = nextVObject( &nit );
752 QCString name = vObjectName( o );
753 if ( name != VCInternetProp && name != VCHomeProp &&
754 name != VCWorkProp &&
755 name != VCPreferredProp )
756 // ### preffered should map to default email
757 valid = FALSE;
758 }
759 if ( valid ) {
760 if ( haveDefaultEmail ) {
761 QString str = c.emails();
762 if ( !str.isEmpty() )
763 str += ","+email;
764 c.setEmails( str );
765 } else {
766 c.setDefaultEmail( email );
767 }
768 }
769 }
770 else if ( name == VCURLProp ) {
771 VObjectIterator nit;
772 initPropIterator( &nit, o );
773 while( moreIteration( &nit ) ) {
774 VObject *o = nextVObject( &nit );
775 QCString name = vObjectName( o );
776 if ( name == VCHomeProp )
777 c.setHomeWebpage( value );
778 else if ( name == VCWorkProp )
779 c.setBusinessWebpage( value );
780 }
781 }
782 else if ( name == VCOrgProp ) {
783 VObjectIterator nit;
784 initPropIterator( &nit, o );
785 while( moreIteration( &nit ) ) {
786 VObject *o = nextVObject( &nit );
787 QCString name = vObjectName( o );
788 QString value = vObjectStringZValue( o );
789 if ( name == VCOrgNameProp )
790 c.setCompany( value );
791 else if ( name == VCOrgUnitProp )
792 c.setDepartment( value );
793 else if ( name == VCOrgUnit2Prop )
794 c.setOffice( value );
795 }
796 }
797 else if ( name == VCTitleProp ) {
798 c.setJobTitle( value );
799 }
800 else if ( name == "X-Qtopia-Profession" ) {
801 c.setProfession( value );
802 }
803 else if ( name == "X-Qtopia-Manager" ) {
804 c.setManager( value );
805 }
806 else if ( name == "X-Qtopia-Assistant" ) {
807 c.setAssistant( value );
808 }
809 else if ( name == "X-Qtopia-Spouse" ) {
810 c.setSpouse( value );
811 }
812 else if ( name == "X-Qtopia-Gender" ) {
813 c.setGender( value );
814 }
815 else if ( name == "X-Qtopia-Anniversary" ) {
816 c.setAnniversary( value );
817 }
818 else if ( name == "X-Qtopia-Nickname" ) {
819 c.setNickname( value );
820 }
821 else if ( name == "X-Qtopia-Children" ) {
822 c.setChildren( value );
823 }
824
825
826#if 0
827 else {
828 printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) );
829 VObjectIterator nit;
830 initPropIterator( &nit, o );
831 while( moreIteration( &nit ) ) {
832 VObject *o = nextVObject( &nit );
833 QCString name = vObjectName( o );
834 QString value = vObjectStringZValue( o );
835 printf(" subprop: %s = %s\n", name.data(), value.latin1() );
836 }
837 }
838#endif
839 }
840 c.setFileAs();
841 return c;
842}
843
844void Contact::writeVCard( const QString &filename, const QValueList<Contact> &contacts)
845{
846 QFileDirect f( filename.utf8().data() );
847 if ( !f.open( IO_WriteOnly ) ) {
848 qWarning("Unable to open vcard write");
849 return;
850 }
851
852 QValueList<Contact>::ConstIterator it;
853 for( it = contacts.begin(); it != contacts.end(); ++it ) {
854 VObject *obj = createVObject( *it );
855 writeVObject(f.directHandle() , obj );
856 cleanVObject( obj );
857 }
858 cleanStrTbl();
859}
860
861void Contact::writeVCard( const QString &filename, const Contact &contact)
862{
863 QFileDirect f( filename.utf8().data() );
864 if ( !f.open( IO_WriteOnly ) ) {
865 qWarning("Unable to open vcard write");
866 return;
867 }
868
869 VObject *obj = createVObject( contact );
870 writeVObject( f.directHandle() , obj );
871 cleanVObject( obj );
872
873 cleanStrTbl();
874}
875
876
877QValueList<Contact> Contact::readVCard( const QString &filename )
878{
879 qDebug("trying to open %s, exists=%d", filename.utf8().data(), QFileInfo( filename.utf8().data() ).size() );
880 VObject *obj = Parse_MIME_FromFileName( (char *)filename.utf8().data() );
881
882 qDebug("vobject = %p", obj );
883
884 QValueList<Contact> contacts;
885
886 while ( obj ) {
887 contacts.append( parseVObject( obj ) );
888
889 VObject *t = obj;
890 obj = nextVObjectInList(obj);
891 cleanVObject( t );
892 }
893
894 return contacts;
895}
896
897bool Contact::match( const QRegExp &r ) const
898{
899 bool match;
900 match = false;
901 QMap<int, QString>::ConstIterator it;
902 for ( it = mMap.begin(); it != mMap.end(); ++it ) {
903 if ( (*it).find( r ) > -1 ) {
904 match = true;
905 break;
906 }
907 }
908 return match;
909}
diff --git a/library/backend/contact.h b/library/backend/contact.h
new file mode 100644
index 0000000..6abdab6
--- a/dev/null
+++ b/library/backend/contact.h
@@ -0,0 +1,217 @@
1/**********************************************************************
2** Copyright (C) 2001 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#ifndef __CONTACT_H__
22#define __CONTACT_H__
23
24#include <qpe/palmtoprecord.h>
25#include <qpe/recordfields.h>
26
27#include <qstringlist.h>
28
29#if defined(QPC_TEMPLATEDLL)
30// MOC_SKIP_BEGIN
31template class QPC_EXPORT QMap<int, QString>;
32// MOC_SKIP_END
33#endif
34
35class ContactPrivate;
36class QPC_EXPORT Contact : public Qtopia::Record
37{
38 friend class DataSet;
39public:
40 Contact();
41 Contact( const QMap<int, QString> &fromMap );
42 virtual ~Contact();
43
44 static void writeVCard( const QString &filename, const QValueList<Contact> &contacts);
45 static void writeVCard( const QString &filename, const Contact &c );
46 static QValueList<Contact> readVCard( const QString &filename );
47
48 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE };
49
50 void setTitle( const QString &v ) { replace( Qtopia::Title, v ); }
51 void setFirstName( const QString &v ) { replace( Qtopia::FirstName, v ); }
52 void setMiddleName( const QString &v ) { replace( Qtopia::MiddleName, v ); }
53 void setLastName( const QString &v ) { replace( Qtopia::LastName, v ); }
54 void setSuffix( const QString &v ) { replace( Qtopia::Suffix, v ); }
55 void setFileAs( const QString &v ) { replace( Qtopia::FileAs, v ); }
56 void setFileAs();
57
58 // default email address
59 void setDefaultEmail( const QString &v ) { replace( Qtopia::DefaultEmail, v ); }
60 // the emails should be seperated by a semicolon
61 void setEmails( const QString &v );
62
63 // home
64 void setHomeStreet( const QString &v ) { replace( Qtopia::HomeStreet, v ); }
65 void setHomeCity( const QString &v ) { replace( Qtopia::HomeCity, v ); }
66 void setHomeState( const QString &v ) { replace( Qtopia::HomeState, v ); }
67 void setHomeZip( const QString &v ) { replace( Qtopia::HomeZip, v ); }
68 void setHomeCountry( const QString &v ) { replace( Qtopia::HomeCountry, v ); }
69 void setHomePhone( const QString &v ) { replace( Qtopia::HomePhone, v ); }
70 void setHomeFax( const QString &v ) { replace( Qtopia::HomeFax, v ); }
71 void setHomeMobile( const QString &v ) { replace( Qtopia::HomeMobile, v ); }
72 void setHomeWebpage( const QString &v ) { replace( Qtopia::HomeWebPage, v ); }
73
74 // business
75 void setCompany( const QString &v ) { replace( Qtopia::Company, v ); }
76 void setBusinessStreet( const QString &v ) { replace( Qtopia::BusinessStreet, v ); }
77 void setBusinessCity( const QString &v ) { replace( Qtopia::BusinessCity, v ); }
78 void setBusinessState( const QString &v ) { replace( Qtopia::BusinessState, v ); }
79 void setBusinessZip( const QString &v ) { replace( Qtopia::BusinessZip, v ); }
80 void setBusinessCountry( const QString &v ) { replace( Qtopia::BusinessCountry, v ); }
81 void setBusinessWebpage( const QString &v ) { replace( Qtopia::BusinessWebPage, v ); }
82 void setJobTitle( const QString &v ) { replace( Qtopia::JobTitle, v ); }
83 void setDepartment( const QString &v ) { replace( Qtopia::Department, v ); }
84 void setOffice( const QString &v ) { replace( Qtopia::Office, v ); }
85 void setBusinessPhone( const QString &v ) { replace( Qtopia::BusinessPhone, v ); }
86 void setBusinessFax( const QString &v ) { replace( Qtopia::BusinessFax, v ); }
87 void setBusinessMobile( const QString &v ) { replace( Qtopia::BusinessMobile, v ); }
88 void setBusinessPager( const QString &v ) { replace( Qtopia::BusinessPager, v ); }
89 void setProfession( const QString &v ) { replace( Qtopia::Profession, v ); }
90 void setAssistant( const QString &v ) { replace( Qtopia::Assistant, v ); }
91 void setManager( const QString &v ) { replace( Qtopia::Manager, v ); }
92
93 // personal
94 void setSpouse( const QString &v ) { replace( Qtopia::Spouse, v ); }
95 void setGender( const QString &v ) { replace( Qtopia::Gender, v ); }
96 void setBirthday( const QString &v ) { replace( Qtopia::Birthday, v ); }
97 void setAnniversary( const QString &v ) { replace( Qtopia::Anniversary, v ); }
98 void setNickname( const QString &v ) { replace( Qtopia::Nickname, v ); }
99 void setChildren( const QString &v );
100
101 // other
102 void setNotes( const QString &v ) { replace( Qtopia::Notes, v); }
103
104 bool match( const QRegExp &r ) const;
105
106// // custom
107// void setCustomField( const QString &key, const QString &v )
108// { replace(Custom- + key, v ); }
109
110 // name
111 QString fullName() const;
112 QString title() const { return find( Qtopia::Title ); }
113 QString firstName() const { return find( Qtopia::FirstName ); }
114 QString middleName() const { return find( Qtopia::MiddleName ); }
115 QString lastName() const { return find( Qtopia::LastName ); }
116 QString suffix() const { return find( Qtopia::Suffix ); }
117 QString fileAs() const { return find( Qtopia::FileAs ); }
118
119 // email
120 QString defaultEmail() const { return find( Qtopia::DefaultEmail ); }
121 QString emails() const { return find( Qtopia::Emails ); }
122 QStringList emailList() const;
123
124 // home
125 QString homeStreet() const { return find( Qtopia::HomeStreet ); }
126 QString homeCity() const { return find( Qtopia::HomeCity ); }
127 QString homeState() const { return find( Qtopia::HomeState ); }
128 QString homeZip() const { return find( Qtopia::HomeZip ); }
129 QString homeCountry() const { return find( Qtopia::HomeCountry ); }
130 QString homePhone() const { return find( Qtopia::HomePhone ); }
131 QString homeFax() const { return find( Qtopia::HomeFax ); }
132 QString homeMobile() const { return find( Qtopia::HomeMobile ); }
133 QString homeWebpage() const { return find( Qtopia::HomeWebPage ); }
134 /** Multi line string containing all non-empty address info in the form
135 * Street
136 * City, State Zip
137 * Country
138 */
139 QString displayHomeAddress() const;
140
141 // business
142 QString company() const { return find( Qtopia::Company ); }
143 QString businessStreet() const { return find( Qtopia::BusinessStreet ); }
144 QString businessCity() const { return find( Qtopia::BusinessCity ); }
145 QString businessState() const { return find( Qtopia::BusinessState ); }
146 QString businessZip() const { return find( Qtopia::BusinessZip ); }
147 QString businessCountry() const { return find( Qtopia::BusinessCountry ); }
148 QString businessWebpage() const { return find( Qtopia::BusinessWebPage ); }
149 QString jobTitle() const { return find( Qtopia::JobTitle ); }
150 QString department() const { return find( Qtopia::Department ); }
151 QString office() const { return find( Qtopia::Office ); }
152 QString businessPhone() const { return find( Qtopia::BusinessPhone ); }
153 QString businessFax() const { return find( Qtopia::BusinessFax ); }
154 QString businessMobile() const { return find( Qtopia::BusinessMobile ); }
155 QString businessPager() const { return find( Qtopia::BusinessPager ); }
156 QString profession() const { return find( Qtopia::Profession ); }
157 QString assistant() const { return find( Qtopia::Assistant ); }
158 QString manager() const { return find( Qtopia::Manager ); }
159 /** Multi line string containing all non-empty address info in the form
160 * Street
161 * City, State Zip
162 * Country
163 */
164 QString displayBusinessAddress() const;
165
166 //personal
167 QString spouse() const { return find( Qtopia::Spouse ); }
168 QString gender() const { return find( Qtopia::Gender ); }
169 QString birthday() const { return find( Qtopia::Birthday ); }
170 QString anniversary() const { return find( Qtopia::Anniversary ); }
171 QString nickname() const { return find( Qtopia::Nickname ); }
172 QString children() const { return find( Qtopia::Children ); }
173 QStringList childrenList() const;
174
175 // other
176 QString notes() const { return find( Qtopia::Notes ); }
177 QString groups() const { return find( Qtopia::Groups ); }
178 QStringList groupList() const;
179
180// // custom
181// const QString &customField( const QString &key )
182// { return find( Custom- + key ); }
183
184 static QStringList fields();
185 static QStringList trfields();
186
187 QString toRichText() const;
188 QMap<int, QString> toMap() const;
189 QString field( int key ) const { return find( key ); }
190
191
192 // journaling...
193 void saveJournal( journal_action action, const QString &key = QString::null );
194 void save( QString &buf ) const;
195
196 void setUid( int i )
197{ Record::setUid(i); replace( Qtopia::AddressUid , QString::number(i)); }
198
199private:
200 friend class AbTable;
201 void insert( int key, const QString &value );
202 void replace( int key, const QString &value );
203 QString find( int key ) const;
204
205 QString displayAddress( const QString &street,
206 const QString &city,
207 const QString &state,
208 const QString &zip,
209 const QString &country ) const;
210
211 Qtopia::UidGen &uidGen() { return sUidGen; }
212 static Qtopia::UidGen sUidGen;
213 QMap<int, QString> mMap;
214 ContactPrivate *d;
215};
216
217#endif
diff --git a/library/backend/event.cpp b/library/backend/event.cpp
new file mode 100644
index 0000000..50a663d
--- a/dev/null
+++ b/library/backend/event.cpp
@@ -0,0 +1,830 @@
1/**********************************************************************
2** Copyright (C) 2001 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#include "event.h"
22#include "qfiledirect_p.h"
23#include <qpe/timeconversion.h>
24#include <qpe/stringutil.h>
25#include <qpe/recordfields.h>
26#include <qbuffer.h>
27#include <time.h>
28#include "vobject_p.h"
29
30#include <stdio.h>
31
32using namespace Qtopia;
33
34static void write( QString& buf, const Event::RepeatPattern &r )
35{
36 buf += " rtype=\"";
37 switch ( r.type ) {
38 case Event::Daily:
39 buf += "Daily";
40 break;
41 case Event::Weekly:
42 buf += "Weekly";
43 break;
44 case Event::MonthlyDay:
45 buf += "MonthlyDay";
46 break;
47 case Event::MonthlyDate:
48 buf += "MonthlyDate";
49 break;
50 case Event::Yearly:
51 buf += "Yearly";
52 break;
53 default:
54 buf += "NoRepeat";
55 break;
56 }
57 buf += "\"";
58 if ( r.days > 0 )
59 buf += " rweekdays=\"" + QString::number( static_cast<int>( r.days ) ) + "\"";
60 if ( r.position != 0 )
61 buf += " rposition=\"" + QString::number( r.position ) + "\"";
62
63 buf += " rfreq=\"" + QString::number( r.frequency ) + "\"";
64 buf += " rhasenddate=\"" + QString::number( static_cast<int>( r.hasEndDate ) ) + "\"";
65 if ( r.hasEndDate )
66 buf += " enddt=\""
67 + QString::number( r.endDateUTC ? r.endDateUTC : time( 0 ) )
68 + "\"";
69 buf += " created=\"" + QString::number( r.createTime ) + "\"";
70}
71
72Qtopia::UidGen Event::sUidGen( Qtopia::UidGen::Qtopia );
73
74Event::Event() : Record()
75{
76 startUTC = endUTC = time( 0 );
77 typ = Normal;
78 hAlarm = FALSE;
79 hRepeat = FALSE;
80 aMinutes = 0;
81 aSound = Silent;
82 pattern.type = NoRepeat;
83 pattern.frequency = -1;
84}
85
86Event::Event( const QMap<int, QString> &map )
87{
88 setDescription( map[DatebookDescription] );
89 setLocation( map[Location] );
90 setCategories( idsFromString( map[DatebookCategory] ) );
91 setTimeZone( map[TimeZone] );
92 setNotes( map[Note] );
93 setStart( TimeConversion::fromUTC( map[StartDateTime].toUInt() ) );
94 setEnd( TimeConversion::fromUTC( map[EndDateTime].toUInt() ) );
95 setType( (Event::Type) map[DatebookType].toInt() );
96 setAlarm( ( map[HasAlarm] == "1" ? TRUE : FALSE ), map[AlarmTime].toInt(), (Event::SoundTypeChoice)map[SoundType].toInt() );
97 Event::RepeatPattern p;
98 p.type = (Event::RepeatType) map[ RepeatPatternType ].toInt();
99 p.frequency = map[ RepeatPatternFrequency ].toInt();
100 p.position = map[ RepeatPatternPosition ].toInt();
101 p.days = map[ RepeatPatternDays ].toInt();
102 p.hasEndDate = map[ RepeatPatternHasEndDate ].toInt();
103 p.endDateUTC = map[ RepeatPatternEndDate ].toUInt();
104 setRepeat( p );
105
106 setUid( map[ DatebookUid ].toInt() );
107}
108
109Event::~Event()
110{
111}
112
113int Event::week( const QDate& date )
114{
115 // Calculates the week this date is in within that
116 // month. Equals the "row" is is in in the month view
117 int week = 1;
118 QDate tmp( date.year(), date.month(), 1 );
119
120 if ( date.dayOfWeek() < tmp.dayOfWeek() )
121 ++week;
122
123 week += ( date.day() - 1 ) / 7;
124 return week;
125}
126
127int Event::occurrence( const QDate& date )
128{
129 // calculates the number of occurrances of this day of the
130 // week till the given date (e.g 3rd Wednesday of the month)
131 return ( date.day() - 1 ) / 7 + 1;
132}
133
134int Event::dayOfWeek( char day )
135{
136 int dayOfWeek = 1;
137 char i = Event::MON;
138 while ( !( i & day ) && i <= Event::SUN ) {
139 i <<= 1;
140 ++dayOfWeek;
141 }
142 return dayOfWeek;
143}
144
145int Event::monthDiff( const QDate& first, const QDate& second )
146{
147 return ( second.year() - first.year() ) * 12 +
148 second.month() - first.month();
149}
150
151QMap<int, QString> Event::toMap() const
152{
153 QMap<int, QString> m;
154 m.insert( DatebookDescription, description() );
155 m.insert ( Location, location() );
156 m.insert ( DatebookCategory, idsToString( categories() ) );
157 m.insert ( TimeZone, timeZone() );
158 m.insert ( Note, notes() );
159 m.insert ( StartDateTime, QString::number( TimeConversion::toUTC( start() ) ) );
160 m.insert ( EndDateTime, QString::number( TimeConversion::toUTC( end() ) ) );
161 m.insert ( DatebookType, QString::number( (int)type() ) );
162 m.insert ( HasAlarm, ( hasAlarm() ? "1" : "0" ) );
163 m.insert ( SoundType, QString::number( (int)alarmSound() ) );
164 m.insert ( AlarmTime, QString::number( alarmTime() ) );
165 m.insert ( RepeatPatternType, QString::number( static_cast<int>( repeatPattern().type ) ) );
166 m.insert ( RepeatPatternFrequency, QString::number( repeatPattern().frequency ) );
167 m.insert ( RepeatPatternPosition, QString::number( repeatPattern().position ) );
168 m.insert ( RepeatPatternDays, QString::number( repeatPattern().days ) );
169 m.insert ( RepeatPatternHasEndDate, QString::number( static_cast<int>( repeatPattern().hasEndDate ) ) );
170 m.insert ( RepeatPatternEndDate, QString::number( repeatPattern().endDateUTC ) );
171
172 m.insert( DatebookUid, QString::number( uid()) );
173
174 return m;
175}
176
177void Event::setRepeat( const RepeatPattern &p )
178{
179 setRepeat( p.type != NoRepeat, p );
180}
181
182void Event::setDescription( const QString &s )
183{
184 descript = s;
185}
186
187void Event::setLocation( const QString &s )
188{
189 locat = s;
190}
191
192// void Event::setCategory( const QString &s )
193// {
194// categ = s;
195// }
196
197void Event::setType( Type t )
198{
199 typ = t;
200}
201
202void Event::setStart( const QDateTime &d )
203{
204 startUTC = TimeConversion::toUTC( d );
205}
206
207void Event::setStart( time_t time )
208{
209 startUTC = time;
210}
211
212void Event::setEnd( const QDateTime &d )
213{
214 endUTC = TimeConversion::toUTC( d );
215}
216
217void Event::setEnd( time_t time )
218{
219 endUTC = time;
220}
221
222void Event::setTimeZone( const QString &z )
223{
224 tz = z;
225}
226
227void Event::setAlarm( bool b, int minutes, SoundTypeChoice s )
228{
229 hAlarm = b;
230 aMinutes = minutes;
231 aSound = s;
232}
233
234void Event::setRepeat( bool b, const RepeatPattern &p )
235{
236 hRepeat = b;
237 pattern = p;
238}
239
240void Event::setNotes( const QString &n )
241{
242 note = n;
243}
244
245const QString &Event::description() const
246{
247 return descript;
248}
249
250const QString &Event::location() const
251{
252 return locat;
253}
254
255// QString Event::category() const
256// {
257// return categ;
258// }
259
260Event::Type Event::type() const
261{
262 return typ;
263}
264
265QDateTime Event::start( bool actual ) const
266{
267 QDateTime dt = (startUTC > 0) ? TimeConversion::fromUTC( startUTC ) : QDateTime::currentDateTime();
268
269 if ( actual && typ == AllDay ) {
270 QTime t = dt.time();
271 t.setHMS( 0, 0, 0 );
272 dt.setTime( t );
273 }
274 return dt;
275}
276
277QDateTime Event::end( bool actual ) const
278{
279 QDateTime dt = (endUTC > 0) ? TimeConversion::fromUTC( endUTC ) : QDateTime::currentDateTime();
280
281 if ( actual && typ == AllDay ) {
282 QTime t = dt.time();
283 t.setHMS( 23, 59, 59 );
284 dt.setTime( t );
285 }
286 return dt;
287}
288
289const QString &Event::timeZone() const
290{
291 return tz;
292}
293
294bool Event::hasAlarm() const
295{
296 return hAlarm;
297}
298
299int Event::alarmTime() const
300{
301 return aMinutes;
302}
303
304Event::SoundTypeChoice Event::alarmSound() const
305{
306 return aSound;
307}
308
309bool Event::hasRepeat() const
310{
311 return doRepeat();
312}
313
314const Event::RepeatPattern &Event::repeatPattern() const
315{
316 return pattern;
317}
318
319Event::RepeatPattern &Event::repeatPattern()
320{
321 return pattern;
322}
323
324const QString &Event::notes() const
325{
326 return note;
327}
328
329bool Event::operator==( const Event &e ) const
330{
331 return ( e.descript == descript &&
332 e.locat == locat &&
333 e.categ == categ &&
334 e.typ == typ &&
335 e.startUTC == startUTC &&
336 e.endUTC == endUTC &&
337 e.tz == tz &&
338 e.hAlarm == hAlarm &&
339 e.aMinutes == aMinutes &&
340 e.aSound == aSound &&
341 e.hRepeat == hRepeat &&
342 e.pattern == pattern &&
343 e.note == note );
344}
345
346void Event::save( QString& buf )
347{
348 buf += " description=\"" + Qtopia::escapeString(descript) + "\"";
349 if ( !locat.isEmpty() )
350 buf += " location=\"" + Qtopia::escapeString(locat) + "\"";
351 // save the categoies differently....
352 QString strCats = idsToString( categories() );
353 buf += " categories=\"" + Qtopia::escapeString(strCats) + "\"";
354 buf += " uid=\"" + QString::number( uid() ) + "\"";
355 if ( (Type)typ != Normal )
356 buf += " type=\"AllDay\"";
357 if ( hAlarm ) {
358 buf += " alarm=\"" + QString::number( aMinutes ) + "\" sound=\"";
359 if ( aSound == Event::Loud )
360 buf += "loud";
361 else
362 buf += "silent";
363 buf += "\"";
364 }
365 if ( hRepeat )
366 write( buf, pattern );
367
368 buf += " start=\""
369 + QString::number( startUTC )
370 + "\"";
371
372 buf += " end=\""
373 + QString::number( endUTC )
374 + "\"";
375
376 if ( !note.isEmpty() )
377 buf += " note=\"" + Qtopia::escapeString( note ) + "\"";
378 buf += customToXml();
379}
380
381bool Event::RepeatPattern::operator==( const Event::RepeatPattern &right ) const
382{
383 // *sigh*
384 return ( type == right.type
385 && frequency == right.frequency
386 && position == right.position
387 && days == right.days
388 && hasEndDate == right.hasEndDate
389 && endDateUTC == right.endDateUTC
390 && createTime == right.createTime );
391}
392
393
394class EffectiveEventPrivate
395{
396public:
397 //currently the existence of the d pointer means multi-day repeating,
398 //msut be changed if we use the d pointer for anything else.
399 QDate startDate;
400 QDate endDate;
401};
402
403
404EffectiveEvent::EffectiveEvent()
405{
406 mDate = QDate::currentDate();
407 mStart = mEnd = QTime::currentTime();
408 d = 0;
409}
410
411EffectiveEvent::EffectiveEvent( const Event &e, const QDate &date, Position pos )
412{
413 mEvent = e;
414 mDate = date;
415 if ( pos & Start )
416 mStart = e.start( TRUE ).time();
417 else
418 mStart = QTime( 0, 0, 0 );
419
420 if ( pos & End )
421 mEnd = e.end( TRUE ).time();
422 else
423 mEnd = QTime( 23, 59, 59 );
424 d = 0;
425}
426
427EffectiveEvent::~EffectiveEvent()
428{
429 delete d;
430}
431
432EffectiveEvent::EffectiveEvent( const EffectiveEvent &e )
433{
434 d = 0;
435 *this = e;
436}
437
438EffectiveEvent& EffectiveEvent::operator=( const EffectiveEvent & e )
439{
440 if ( &e == this )
441 return *this;
442 delete d;
443 if ( e.d ) {
444 d = new EffectiveEventPrivate;
445 d->startDate = e.d->startDate;
446 d->endDate = e.d->endDate;
447 } else {
448 d = 0;
449 }
450 mEvent = e.mEvent;
451 mDate = e.mDate;
452 mStart = e.mStart;
453 mEnd = e.mEnd;
454
455 return *this;
456
457}
458
459// QString EffectiveEvent::category() const
460// {
461// return mEvent.category();
462// }
463
464const QString &EffectiveEvent::description( ) const
465{
466 return mEvent.description();
467}
468
469const QString &EffectiveEvent::location( ) const
470{
471 return mEvent.location();
472}
473
474const QString &EffectiveEvent::notes() const
475{
476 return mEvent.notes();
477}
478
479const Event &EffectiveEvent::event() const
480{
481 return mEvent;
482}
483
484const QTime &EffectiveEvent::end() const
485{
486 return mEnd;
487}
488
489const QTime &EffectiveEvent::start() const
490{
491 return mStart;
492}
493
494const QDate &EffectiveEvent::date() const
495{
496 return mDate;
497}
498
499int EffectiveEvent::length() const
500{
501 return (mEnd.hour() * 60 - mStart.hour() * 60)
502 + QABS(mStart.minute() - mEnd.minute() );
503}
504
505void EffectiveEvent::setDate( const QDate &dt )
506{
507 mDate = dt;
508}
509
510void EffectiveEvent::setStart( const QTime &start )
511{
512 mStart = start;
513}
514
515void EffectiveEvent::setEnd( const QTime &end )
516{
517 mEnd = end;
518}
519
520void EffectiveEvent::setEvent( Event e )
521{
522 mEvent = e;
523}
524
525bool EffectiveEvent::operator<( const EffectiveEvent &e ) const
526{
527 if ( mDate < e.date() )
528 return TRUE;
529 if ( mDate == e.date() )
530 return ( mStart < e.start() );
531 else
532 return FALSE;
533}
534
535bool EffectiveEvent::operator<=( const EffectiveEvent &e ) const
536{
537 return (mDate <= e.date() );
538}
539
540bool EffectiveEvent::operator==( const EffectiveEvent &e ) const
541{
542 return ( mDate == e.date()
543 && mStart == e.start()
544 && mEnd == e.end()
545 && mEvent == e.event() );
546}
547
548bool EffectiveEvent::operator!=( const EffectiveEvent &e ) const
549{
550 return !(*this == e);
551}
552
553bool EffectiveEvent::operator>( const EffectiveEvent &e ) const
554{
555 return !(*this <= e );
556}
557
558bool EffectiveEvent::operator>=(const EffectiveEvent &e) const
559{
560 return !(*this < e);
561}
562
563void EffectiveEvent::setEffectiveDates( const QDate &from, const QDate &to )
564{
565 if ( !from.isValid() ) {
566 delete d;
567 d = 0;
568 return;
569 }
570 if ( !d )
571 d = new EffectiveEventPrivate;
572 d->startDate = from;
573 d->endDate = to;
574}
575
576QDate EffectiveEvent::startDate() const
577{
578 if ( d )
579 return d->startDate;
580 else if ( mEvent.hasRepeat() )
581 return mDate; // single day, since multi-day should have a d pointer
582 else
583 return mEvent.start().date();
584}
585
586QDate EffectiveEvent::endDate() const
587{
588 if ( d )
589 return d->endDate;
590 else if ( mEvent.hasRepeat() )
591 return mDate; // single day, since multi-day should have a d pointer
592 else
593 return mEvent.end().date();
594}
595
596int EffectiveEvent::size() const
597{
598 return ( mEnd.hour() - mStart.hour() ) * 3600
599 + (mEnd.minute() - mStart.minute() * 60
600 + mEnd.second() - mStart.second() );
601}
602
603
604// vcal conversion code
605static inline VObject *safeAddPropValue( VObject *o, const char *prop, const QString &value )
606{
607 VObject *ret = 0;
608 if ( o && !value.isEmpty() )
609 ret = addPropValue( o, prop, value.latin1() );
610 return ret;
611}
612
613static inline VObject *safeAddProp( VObject *o, const char *prop)
614{
615 VObject *ret = 0;
616 if ( o )
617 ret = addProp( o, prop );
618 return ret;
619}
620
621static VObject *createVObject( const Event &e )
622{
623 VObject *vcal = newVObject( VCCalProp );
624 safeAddPropValue( vcal, VCVersionProp, "1.0" );
625 VObject *event = safeAddProp( vcal, VCEventProp );
626
627 safeAddPropValue( event, VCDTstartProp, TimeConversion::toISO8601( e.start() ) );
628 safeAddPropValue( event, VCDTendProp, TimeConversion::toISO8601( e.end() ) );
629 safeAddPropValue( event, "X-Qtopia-NOTES", e.description() );
630 safeAddPropValue( event, VCDescriptionProp, e.description() );
631 safeAddPropValue( event, VCLocationProp, e.location() );
632
633 if ( e.hasAlarm() ) {
634 VObject *alarm = safeAddProp( event, VCAAlarmProp );
635 QDateTime dt = e.start();
636 dt = dt.addSecs( -e.alarmTime()*60 );
637 safeAddPropValue( alarm, VCRunTimeProp, TimeConversion::toISO8601( dt ) );
638 safeAddPropValue( alarm, VCAudioContentProp,
639 (e.alarmSound() == Event::Silent ? "silent" : "alarm" ) );
640 }
641
642 safeAddPropValue( event, "X-Qtopia-TIMEZONE", e.timeZone() );
643
644 if ( e.type() == Event::AllDay )
645 safeAddPropValue( event, "X-Qtopia-AllDay", e.timeZone() );
646
647 // ### repeat missing
648
649 // ### categories missing
650
651 return vcal;
652}
653
654
655static Event parseVObject( VObject *obj )
656{
657 Event e;
658
659 bool haveAlarm = FALSE;
660 bool haveStart = FALSE;
661 bool haveEnd = FALSE;
662 QDateTime alarmTime;
663 Event::SoundTypeChoice soundType = Event::Silent;
664
665 VObjectIterator it;
666 initPropIterator( &it, obj );
667 while( moreIteration( &it ) ) {
668 VObject *o = nextVObject( &it );
669 QCString name = vObjectName( o );
670 QCString value = vObjectStringZValue( o );
671 if ( name == VCDTstartProp ) {
672 e.setStart( TimeConversion::fromISO8601( value ) );
673 haveStart = TRUE;
674 }
675 else if ( name == VCDTendProp ) {
676 e.setEnd( TimeConversion::fromISO8601( value ) );
677 haveEnd = TRUE;
678 }
679 else if ( name == "X-Qtopia-NOTES" ) {
680 e.setNotes( value );
681 }
682 else if ( name == VCDescriptionProp ) {
683 e.setDescription( value );
684 }
685 else if ( name == VCLocationProp ) {
686 e.setLocation( value );
687 }
688 else if ( name == VCAudioContentProp ) {
689 haveAlarm = TRUE;
690 VObjectIterator nit;
691 initPropIterator( &nit, o );
692 while( moreIteration( &nit ) ) {
693 VObject *o = nextVObject( &nit );
694 QCString name = vObjectName( o );
695 QCString value = vObjectStringZValue( o );
696 if ( name == VCRunTimeProp )
697 alarmTime = TimeConversion::fromISO8601( value );
698 else if ( name == VCAudioContentProp ) {
699 if ( value == "silent" )
700 soundType = Event::Silent;
701 else
702 soundType = Event::Loud;
703 }
704 }
705 }
706 else if ( name == "X-Qtopia-TIMEZONE") {
707 e.setTimeZone( value );
708 }
709 else if ( name == "X-Qtopia-AllDay" ) {
710 e.setType( Event::AllDay );
711 }
712#if 0
713 else {
714 printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) );
715 VObjectIterator nit;
716 initPropIterator( &nit, o );
717 while( moreIteration( &nit ) ) {
718 VObject *o = nextVObject( &nit );
719 QCString name = vObjectName( o );
720 QString value = vObjectStringZValue( o );
721 printf(" subprop: %s = %s\n", name.data(), value.latin1() );
722 }
723 }
724#endif
725 }
726
727 if ( !haveStart && !haveEnd )
728 e.setStart( QDateTime::currentDateTime() );
729
730 if ( !haveEnd ) {
731 e.setType( Event::AllDay );
732 e.setEnd( e.start() );
733 }
734
735 if ( haveAlarm ) {
736 int minutes = alarmTime.secsTo( e.start() ) / 60;
737 e.setAlarm( TRUE, minutes, soundType );
738 }
739 return e;
740}
741
742
743
744void Event::writeVCalendar( const QString &filename, const QValueList<Event> &events)
745{
746 QFileDirect f( filename.utf8().data() );
747 if ( !f.open( IO_WriteOnly ) ) {
748 qWarning("Unable to open vcard write");
749 return;
750 }
751
752 QValueList<Event>::ConstIterator it;
753 for( it = events.begin(); it != events.end(); ++it ) {
754 VObject *obj = createVObject( *it );
755 writeVObject( f.directHandle() , obj );
756 cleanVObject( obj );
757 }
758
759 cleanStrTbl();
760}
761
762void Event::writeVCalendar( const QString &filename, const Event &event)
763{
764 QFileDirect f( filename.utf8().data() );
765 if ( !f.open( IO_WriteOnly ) ) {
766 qWarning("Unable to open vcard write");
767 return;
768 }
769
770 VObject *obj = createVObject( event );
771 writeVObject( f.directHandle() , obj );
772 cleanVObject( obj );
773
774 cleanStrTbl();
775}
776
777
778QValueList<Event> Event::readVCalendar( const QString &filename )
779{
780 VObject *obj = Parse_MIME_FromFileName( (char *)filename.utf8().data() );
781
782 QValueList<Event> events;
783
784 while ( obj ) {
785 QCString name = vObjectName( obj );
786 if ( name == VCCalProp ) {
787 VObjectIterator nit;
788 initPropIterator( &nit, obj );
789 while( moreIteration( &nit ) ) {
790 VObject *o = nextVObject( &nit );
791 QCString name = vObjectName( o );
792 if ( name == VCEventProp )
793 events.append( parseVObject( o ) );
794 }
795 } else if ( name == VCEventProp ) {
796 // shouldn't happen, but just to be sure
797 events.append( parseVObject( obj ) );
798 }
799 VObject *t = obj;
800 obj = nextVObjectInList(obj);
801 cleanVObject( t );
802 }
803
804 return events;
805}
806
807bool Event::match( const QRegExp &r ) const
808{
809 bool returnMe;
810 returnMe = false;
811
812 if ( descript.find( r ) > -1 )
813 returnMe = true;
814 else if ( locat.find( r ) > -1 )
815 returnMe = true;
816 else if ( TimeConversion::fromUTC( startUTC ).toString().find( r ) > -1 )
817 returnMe = true;
818 else if ( TimeConversion::fromUTC( endUTC ).toString().find( r ) > -1 )
819 returnMe = true;
820 else if ( tz.find( r ) > -1 )
821 returnMe = true;
822 else if ( note.find( r ) > -1 )
823 returnMe = true;
824 else if ( doRepeat() ) {
825 if ( pattern.hasEndDate )
826 if ( TimeConversion::fromUTC( pattern.endDateUTC ).toString().find(r) > -1 )
827 returnMe = true;
828 }
829 return returnMe;
830}
diff --git a/library/backend/event.h b/library/backend/event.h
new file mode 100644
index 0000000..0ebe9ea
--- a/dev/null
+++ b/library/backend/event.h
@@ -0,0 +1,229 @@
1/**********************************************************************
2** Copyright (C) 2001 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#ifndef __EVENT_H__
22#define __EVENT_H__
23
24#include <qdatetime.h>
25#include <qvaluelist.h>
26
27#ifdef PALMTOPCENTER
28#include <qpc/qsorter.h>
29#endif
30#include <qpe/palmtoprecord.h>
31
32#include <qpe/timeconversion.h>
33
34class EventPrivate;
35class QPC_EXPORT Event : public Qtopia::Record
36{
37public:
38 enum RepeatType { NoRepeat = -1, Daily, Weekly, MonthlyDay,
39 MonthlyDate, Yearly };
40 enum Days { MON = 0x01, TUE = 0x02, WED = 0x04, THU = 0x08,
41 FRI = 0x10, SAT = 0x20, SUN = 0x40 };
42 struct QPC_EXPORT RepeatPattern
43 {
44 RepeatPattern() {
45 type = NoRepeat; frequency = -1; days = 0; position = 0; createTime = -1;
46 hasEndDate = FALSE; endDateUTC = 0; }
47 bool operator ==( const RepeatPattern &right ) const;
48
49 RepeatType type;
50 int frequency;
51 int position;// the posistion in the month (e.g. the first sunday, etc) positive, count from the front negative count from the end...
52 char days; // a mask for days OR in your days!
53 bool hasEndDate;
54 QDate endDate() const { return TimeConversion::fromUTC( endDateUTC ).date(); }
55 void setEndDate( const QDate &dt ) { endDateUTC = TimeConversion::toUTC( dt ); }
56 time_t endDateUTC;
57 time_t createTime;
58 };
59
60 Event();
61 Event( const QMap<int, QString > & map );
62 virtual ~Event();
63
64 QMap<int, QString> toMap() const;
65
66 static void writeVCalendar( const QString &filename, const QValueList<Event> &events);
67 static void writeVCalendar( const QString &filename, const Event &event);
68 static QValueList<Event> readVCalendar( const QString &filename );
69
70 enum Type { Normal, AllDay };
71 enum SoundTypeChoice { Silent, Loud };
72
73 bool operator<( const Event &e1) const { return start() < e1.start(); };
74 bool operator<=( const Event &e1 ) const { return start() <= e1.start(); };
75 bool operator!=( const Event &e1 ) const { return !( *this == e1 ); };
76 bool operator>( const Event &e1 ) const { return start() > e1.start(); };
77 bool operator>=(const Event &e1 ) const { return start() >= e1.start(); };
78 bool operator==( const Event &e ) const;
79
80 void setDescription( const QString &s );
81 const QString &description() const;
82
83 void setLocation( const QString &s );
84 const QString &location() const;
85
86 void setType( Type t );
87 Type type() const;
88 void setStart( const QDateTime &d );
89 void setStart( time_t time );
90 QDateTime start( bool actual = FALSE ) const;
91 time_t startTime() const { return startUTC; }
92 void setEnd( const QDateTime &e );
93 void setEnd( time_t time );
94 QDateTime end( bool actual = FALSE ) const;
95 time_t endTime() const { return endUTC; }
96 void setTimeZone( const QString & );
97 const QString &timeZone() const;
98 void setAlarm( bool b, int minutes, SoundTypeChoice );
99 bool hasAlarm() const;
100 int alarmTime() const;
101 SoundTypeChoice alarmSound() const;
102 void setRepeat( bool b, const RepeatPattern &p );
103 void setRepeat( const RepeatPattern &p );
104 bool hasRepeat() const;
105 const RepeatPattern &repeatPattern() const;
106 RepeatPattern &repeatPattern();
107 void setNotes( const QString &n );
108 const QString &notes() const;
109 bool doRepeat() const { return pattern.type != NoRepeat; }
110
111 void save( QString& buf );
112 //void load( Node *n );
113
114 // helper function to calculate the week of the given date
115 static int week( const QDate& date );
116 // calculates the number of occurrences of the week day of
117 // the given date from the start of the month
118 static int occurrence( const QDate& date );
119 // returns a proper days-char for a given dayOfWeek()
120 static char day( int dayOfWeek ) { return 1 << ( dayOfWeek - 1 ); }
121 // returns the dayOfWeek for the *first* day it finds (ignores
122 // any further days!). Returns 1 (Monday) if there isn't any day found
123 static int dayOfWeek( char day );
124 // returns the difference of months from first to second.
125 static int monthDiff( const QDate& first, const QDate& second );
126 bool match( const QRegExp &r ) const;
127
128private:
129 Qtopia::UidGen &uidGen() { return sUidGen; }
130 static Qtopia::UidGen sUidGen;
131
132 QString descript, locat, categ;
133 Type typ : 4;
134 bool startTimeDirty : 1;
135 bool endTimeDirty : 1;
136 time_t startUTC, endUTC;
137 QString tz;
138 bool hAlarm, hRepeat;
139 int aMinutes;
140 SoundTypeChoice aSound;
141 RepeatPattern pattern;
142 QString note;
143 EventPrivate *d;
144};
145
146// Since an event spans multiple day, it is better to have this
147// class to represent a day instead of creating many
148// dummy events...
149
150class EffectiveEventPrivate;
151class QPC_EXPORT EffectiveEvent
152{
153public:
154 // If we calculate the effective event of a multi-day event
155 // we have to figure out whether we are at the first day,
156 // at the end, or anywhere else ("middle"). This is important
157 // for the start/end times (00:00/23:59)
158 // MidWay: 00:00 -> 23:59, as we are "in the middle" of a multi-
159 // day event
160 // Start: start time -> 23:59
161 // End: 00:00 -> end time
162 // Start | End == StartEnd: for single-day events (default)
163 // here we draw start time -> end time
164 enum Position { MidWay = 0, Start = 1, End = 2, StartEnd = 3 };
165
166 EffectiveEvent();
167 EffectiveEvent( const Event &event, const QDate &startDate, Position pos = StartEnd );
168 EffectiveEvent( const EffectiveEvent & );
169 EffectiveEvent& operator=( const EffectiveEvent & );
170 ~EffectiveEvent();
171
172
173 bool operator<( const EffectiveEvent &e ) const;
174 bool operator<=( const EffectiveEvent &e ) const;
175 bool operator==( const EffectiveEvent &e ) const;
176 bool operator!=( const EffectiveEvent &e ) const;
177 bool operator>( const EffectiveEvent &e ) const;
178 bool operator>= ( const EffectiveEvent &e ) const;
179
180 void setStart( const QTime &start );
181 void setEnd( const QTime &end );
182 void setEvent( Event e );
183 void setDate( const QDate &date );
184 void setEffectiveDates( const QDate &from, const QDate &to );
185
186 // QString category() const;
187 const QString &description() const;
188 const QString &location() const;
189 const QString &notes() const;
190 const Event &event() const;
191 const QTime &start() const;
192 const QTime &end() const;
193 const QDate &date() const;
194 int length() const;
195 int size() const;
196
197 QDate startDate() const;
198 QDate endDate() const;
199
200private:
201 class EffectiveEventPrivate *d;
202 Event mEvent;
203 QDate mDate;
204 QTime mStart,
205 mEnd;
206
207};
208
209#ifdef PALMTOPCENTER
210class QPC_EXPORT EffectiveEventSizeSorter : public QSorter<EffectiveEvent>
211{
212public:
213 int compare( const EffectiveEvent& a, const EffectiveEvent& b ) const
214 {
215 return a.size() - b.size();
216 }
217};
218
219class QPC_EXPORT EffectiveEventTimeSorter : public QSorter<EffectiveEvent>
220{
221public:
222 int compare( const EffectiveEvent& a, const EffectiveEvent& b ) const
223 {
224 return a.start().secsTo( b.start() );
225 }
226};
227#endif
228
229#endif
diff --git a/library/backend/palmtoprecord.cpp b/library/backend/palmtoprecord.cpp
new file mode 100644
index 0000000..0d57699
--- a/dev/null
+++ b/library/backend/palmtoprecord.cpp
@@ -0,0 +1,127 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free
8** Software Foundation and appearing in the file LICENSE.GPL included
9** in the packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
12** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
13** PARTICULAR PURPOSE.
14**
15** See http://www.trolltech.com/gpl/ for GPL licensing information.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21#include "palmtoprecord.h"
22#include "stringutil.h"
23#include <qstringlist.h>
24
25namespace Qtopia {
26
27Record &Record::operator=( const Record &c )
28{
29 mUid = c.mUid;
30 mCats = c.mCats;
31 customMap = c.customMap;
32 return *this;
33}
34
35void Record::setCategories( int single )
36{
37 if ( single == 0 )
38 return;
39 mCats.resize(1);
40 mCats[0] = single;
41}
42
43// convenience methods provided for loading and saving to xml
44QString Record::idsToString( const QArray<int> &cats )
45{
46 QString str;
47 for ( uint i = 0; i < cats.size(); i++ )
48 if ( i == 0 )
49 str = QString::number( cats[int(i)] );
50 else
51 str += ";" + QString::number( cats[int(i)] );
52
53 return str;
54}
55
56// convenience methods provided for loading and saving to xml
57QArray<int> Record::idsFromString( const QString &str )
58{
59 QStringList catStrs = QStringList::split( ";", str );
60 QArray<int> cats( catStrs.count() );
61 uint i = 0;
62 for ( QStringList::ConstIterator it = catStrs.begin();
63 it != catStrs.end(); ++it ) {
64 cats[int(i)] = (*it).toInt();
65 i++;
66 }
67 return cats;
68}
69
70/*!
71 Returns the string stored for the custom field \a key.
72 Returns a null string if the field does not exist.
73 */
74QString Record::customField( const QString &key) const
75{
76 if (customMap.contains(key))
77 return customMap[key];
78
79 return QString::null;
80}
81
82/*!
83 Sets the string stored for the custom field \a key to \a value.
84 */
85void Record::setCustomField( const QString &key, const QString &value)
86{
87 qWarning("setting custom " + key + " to " + value);
88 if (customMap.contains(key))
89 customMap.replace(key, value);
90 else
91 customMap.insert(key, value);
92
93 qWarning(QString("custom size %1").arg(customMap.count()));
94}
95
96/*!
97 Removes the custom field \a key.
98 */
99void Record::removeCustomField(const QString &key)
100{
101 customMap.remove(key);
102}
103
104QString Record::customToXml() const
105{
106 //qWarning(QString("writing custom %1").arg(customMap.count()));
107 QString buf(" ");
108 for ( QMap<QString, QString>::ConstIterator cit = customMap.begin();
109 cit != customMap.end(); ++cit) {
110 qWarning(".ITEM.");
111 buf += cit.key();
112 buf += "=\"";
113 buf += escapeString(cit.data());
114 buf += "\" ";
115 }
116 return buf;
117}
118
119void Record::dump( const QMap<int, QString> &map )
120{
121 QMap<int, QString>::ConstIterator it;
122 for( it = map.begin(); it != map.end(); ++it )
123 qDebug("%d : %s", it.key(), it.data().local8Bit().data() );
124}
125
126}
127
diff --git a/library/backend/palmtoprecord.h b/library/backend/palmtoprecord.h
new file mode 100644
index 0000000..0372011
--- a/dev/null
+++ b/library/backend/palmtoprecord.h
@@ -0,0 +1,94 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free
8** Software Foundation and appearing in the file LICENSE.GPL included
9** in the packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
12** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
13** PARTICULAR PURPOSE.
14**
15** See http://www.trolltech.com/gpl/ for GPL licensing information.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21
22#ifndef QTPALMTOP_RECORD_H
23#define QTPALMTOP_RECORD_H
24
25#include <qglobal.h>
26#include "qpcglobal.h"
27#include "palmtopuidgen.h"
28#include <qarray.h>
29#include <qmap.h>
30
31#if defined(QPC_TEMPLATEDLL)
32// MOC_SKIP_BEGIN
33template class QPC_EXPORT QMap<QString, QString>;
34// MOC_SKIP_END
35#endif
36
37class QRegExp;
38namespace Qtopia {
39
40class RecordPrivate;
41class QPC_EXPORT Record
42{
43public:
44 Record() : mUid(0), mCats() { }
45 Record( const Record &c ) :mUid( c.mUid ), mCats ( c.mCats ), customMap(c.customMap) { }
46 virtual ~Record() { }
47
48 Record &operator=( const Record &c );
49
50 virtual bool match( const QRegExp & ) const { return FALSE; }
51
52 void setCategories( const QArray<int> &v ) { mCats = v; }
53 void setCategories( int single );
54 const QArray<int> &categories() const { return mCats; }
55
56 int uid() const { return mUid; };
57 virtual void setUid( int i ) { mUid = i; uidGen().store( mUid ); }
58 bool isValidUid() const { return mUid != 0; }
59 void assignUid() { setUid( uidGen().generate() ); }
60
61 virtual QString customField(const QString &) const;
62 virtual void setCustomField(const QString &, const QString &);
63 virtual void removeCustomField(const QString &);
64
65 virtual bool operator == ( const Record &r ) const
66{ return mUid == r.mUid; }
67 virtual bool operator != ( const Record &r ) const
68{ return mUid != r.mUid; }
69
70 // convenience methods provided for loading and saving to xml
71 static QString idsToString( const QArray<int> &ids );
72 // convenience methods provided for loading and saving to xml
73 static QArray<int> idsFromString( const QString &str );
74
75 // for debugging
76 static void dump( const QMap<int, QString> &map );
77
78protected:
79 virtual UidGen &uidGen() = 0;
80
81 virtual QString customToXml() const;
82
83private:
84 int mUid;
85 QArray<int> mCats;
86
87 QMap<QString, QString> customMap;
88
89 RecordPrivate *d;
90};
91
92}
93
94#endif
diff --git a/library/backend/palmtopuidgen.h b/library/backend/palmtopuidgen.h
new file mode 100644
index 0000000..1a16681
--- a/dev/null
+++ b/library/backend/palmtopuidgen.h
@@ -0,0 +1,83 @@
1#ifndef QTPALMTOP_UIDGEN_H
2#define QTPALMTOP_UIDGEN_H
3/**********************************************************************
4** Copyright (C) 2000 Trolltech AS. All rights reserved.
5**
6** This file is part of Qtopia Environment.
7**
8** Licensees holding valid Qtopia Developer license may use this
9** file in accordance with the Qtopia Developer License Agreement
10** provided with the Software.
11**
12** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
13** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14** PURPOSE.
15**
16** email sales@trolltech.com for information about Qtopia License
17** Agreements.
18**
19** Contact info@trolltech.com if any conditions of this licensing are
20** not clear to you.
21**
22**********************************************************************/
23
24#include <time.h>
25#include <qmap.h>
26#include "qpcglobal.h"
27
28#if defined(QPC_TEMPLATEDLL)
29// MOC_SKIP_BEGIN
30template class QPC_EXPORT QMap< int, bool >;
31// MOC_SKIP_END
32#endif
33
34namespace Qtopia {
35
36
37class QPC_EXPORT UidGen
38{
39public:
40 enum Type { Qtopia, PalmtopCenter };
41
42 UidGen() : type( Qtopia ), sign( -1 ), ids()
43{
44#ifdef PALMTOPCENTER
45 type = PalmtopCenter;
46 sign = 1;
47#endif
48}
49 UidGen( Type t ) : type(t), sign(1), ids()
50{
51 if ( t == Qtopia )
52 sign = -1;
53}
54
55 virtual ~UidGen() { }
56
57 int generate() const
58{
59 int id = sign * (int) ::time(NULL);
60 while ( ids.contains( id ) ) {
61 id += sign;
62
63 // check for overflow cases; if so, wrap back to beginning of
64 // set ( -1 or 1 )
65 if ( sign == -1 && id > 0 || sign == 1 && id < 0 )
66 id = sign;
67 }
68 return id;
69}
70
71 void store(int id) { ids.insert(id, TRUE); }
72 bool isUnique(int id) const { return (!ids.contains(id)); }
73
74private:
75 Type type;
76 int sign;
77 QMap<int, bool> ids;
78
79};
80
81}
82
83#endif
diff --git a/library/backend/qfiledirect_p.h b/library/backend/qfiledirect_p.h
new file mode 100644
index 0000000..fc29ac5
--- a/dev/null
+++ b/library/backend/qfiledirect_p.h
@@ -0,0 +1,36 @@
1/**********************************************************************
2** Copyright (C) 2001 Trolltech AS. All rights reserved.
3**
4** This file is part of the Qtopia Environment.
5**
6** Licensees holding valid Qtopia Developer license may use this
7** file in accordance with the Qtopia Developer License Agreement
8** provided with the Software.
9**
10** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
11** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12** PURPOSE.
13**
14** email sales@trolltech.com for information about Qtopia License
15** Agreements.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21
22#ifndef QFILE_DIRECT_H
23#define QFILE_DIRECT_H
24#include <qfile.h>
25#include <qpe/qpcglobal.h>
26
27class QPC_EXPORT QFileDirect : public QFile
28{
29public:
30 QFileDirect() : QFile() { }
31 QFileDirect( const QString &name ) : QFile(name) { }
32
33 FILE *directHandle() { return fh; }
34};
35
36#endif \ No newline at end of file
diff --git a/library/backend/qpcglobal.h b/library/backend/qpcglobal.h
new file mode 100644
index 0000000..0d60272
--- a/dev/null
+++ b/library/backend/qpcglobal.h
@@ -0,0 +1,50 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** Licensees holding valid Qtopia Developer license may use this
7** file in accordance with the Qtopia Developer License Agreement
8** provided with the Software.
9**
10** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
11** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12** PURPOSE.
13**
14** email sales@trolltech.com for information about Qtopia License
15** Agreements.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21
22#ifndef QPC_GLOBAL_H
23#define QPC_GLOBAL_H
24
25#if ( defined(Q_OS_WIN32) || defined(Q_OS_WIN64) ) && defined(PALMTOPCENTER)
26#include <qglobal.h>
27// # if defined(QT_NODLL)
28//# undef QPC_MAKEDLL
29//# undef QPC_DLL
30 # if defined(QPC_MAKEDLL)/* create a Qt DLL library */
31# if defined(QPC_DLL)
32# undef QPC_DLL
33# endif
34# define QPC_EXPORT __declspec(dllexport)
35# define QPC_TEMPLATEDLL
36 # undef QPC_DISABLE_COPY/* avoid unresolved externals */
37 # elif defined(QPC_DLL) /* use a Qt DLL library */
38# define QPC_EXPORT __declspec(dllimport)
39# define QPC_TEMPLATEDLL
40 # undef QPC_DISABLE_COPY/* avoid unresolved externals */
41# endif
42#else
43 # undef QPC_MAKEDLL /* ignore these for other platforms */
44# undef QPC_DLL
45#endif
46#endif
47
48#ifndef QPC_EXPORT
49# define QPC_EXPORT
50#endif
diff --git a/library/backend/recordfields.h b/library/backend/recordfields.h
new file mode 100644
index 0000000..3cddde2
--- a/dev/null
+++ b/library/backend/recordfields.h
@@ -0,0 +1,135 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** Licensees holding valid Qtopia Developer license may use this
7** file in accordance with the Qtopia Developer License Agreement
8** provided with the Software.
9**
10** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
11** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12** PURPOSE.
13**
14** email sales@trolltech.com for information about Qtopia License
15** Agreements.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21#ifndef QPC_RECORD_FIELDS_H
22#define QPC_RECORD_FIELDS_H
23#include "qpcglobal.h"
24
25// dataset = "addressbook"
26namespace Qtopia
27{
28 static const int UID_ID = 0;
29 static const int CATEGORY_ID = 1;
30
31 enum AddressBookFields {
32 AddressUid = UID_ID,
33 AddressCategory = CATEGORY_ID,
34
35 Title,
36 FirstName,
37 MiddleName,
38 LastName,
39 Suffix,
40 FileAs,
41
42 // email
43 DefaultEmail,
44 Emails,
45
46 // home
47 HomeStreet,
48 HomeCity,
49 HomeState,
50 HomeZip,
51 HomeCountry,
52 HomePhone,
53 HomeFax,
54 HomeMobile,
55 HomeWebPage,
56
57 // business
58 Company,
59 BusinessStreet,
60 BusinessCity,
61 BusinessState,
62 BusinessZip,
63 BusinessCountry,
64 BusinessWebPage,
65 JobTitle,
66 Department,
67 Office,
68 BusinessPhone,
69 BusinessFax,
70 BusinessMobile,
71 BusinessPager,
72 Profession,
73 Assistant,
74 Manager,
75
76 //personal
77 Spouse,
78 Gender,
79 Birthday,
80 Anniversary,
81 Nickname,
82 Children,
83
84 // other
85 Notes,
86 Groups
87 };
88
89 // dataset = "todolist"
90 enum TaskFields {
91 TaskUid = UID_ID,
92 TaskCategory = CATEGORY_ID,
93
94 HasDate,
95 Completed,
96 TaskDescription,
97 Priority,
98 Date
99 };
100
101 // dataset = "categories" for todos
102 enum CategoryFields {
103 CatUid = UID_ID,
104 CatName,
105 CatAppGroup
106 };
107
108
109// dataset = "datebook"
110 enum DatebookFields {
111 DatebookUid = UID_ID,
112 DatebookCategory = CATEGORY_ID,
113
114 DatebookDescription,
115 Location,
116 TimeZone,
117 Note,
118 StartDateTime,
119 EndDateTime,
120 DatebookType,
121 HasAlarm,
122 SoundType,
123 AlarmTime,
124
125 RepeatPatternType,
126 RepeatPatternFrequency,
127 RepeatPatternPosition,
128 RepeatPatternDays,
129 RepeatPatternHasEndDate,
130 RepeatPatternEndDate,
131 };
132};
133
134
135#endif
diff --git a/library/backend/stringutil.cpp b/library/backend/stringutil.cpp
new file mode 100644
index 0000000..df58f54
--- a/dev/null
+++ b/library/backend/stringutil.cpp
@@ -0,0 +1,415 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free
8** Software Foundation and appearing in the file LICENSE.GPL included
9** in the packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
12** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
13** PARTICULAR PURPOSE.
14**
15** See http://www.trolltech.com/gpl/ for GPL licensing information.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21
22#include "stringutil.h"
23#include <qregexp.h>
24#include <qstringlist.h>
25
26namespace Qtopia
27{
28
29
30
31/*
32 Very, very simple Latin-1 only collation guaranteed to displease anyone
33 who actually uses the non-ASCII characters.
34 */
35
36static const char collationHack[] = {
370x00, //C-@
380x01, //C-A
390x02, //C-B
400x03, //C-C
410x04, //C-D
420x05, //C-E
430x06, //C-F
440x07, //C-G
450x08, //C-H
460x09, //C-I
470x0a, //C-J
480x0b, //C-K
490x0c, //C-L
500x0d, //C-M
510x0e, //C-N
520x0f, //C-O
530x10, //C-P
540x11, //C-Q
550x12, //C-R
560x13, //C-S
570x14, //C-T
580x15, //C-U
590x16, //C-V
600x17, //C-W
610x18, //C-X
620x19, //C-Y
630x1a, //C-Z
640x1b, //C-[
650x1c, //C-\
660x1d, //C-]
670x1e, //C-^
680x1f, //C-_
69' ', //
70'!', //!
71'"', //"
72'#', //#
73'$', //$
74'%', //%
75'&', //&
76'\'', //'
77'(', //(
78')', //)
79'*', //*
80'+', //+
81',', //,
82'-', //-
83'.', //.
84'/', ///
850x80, //0
860x81, //1
870x82, //2
880x83, //3
890x84, //4
900x85, //5
910x86, //6
920x87, //7
930x88, //8
940x89, //9
95':', //:
96';', //;
97'<', //<
98'=', //=
99'>', //>
100'?', //?
101'@', //@
102'A', //A
103'B', //B
104'C', //C
105'D', //D
106'E', //E
107'F', //F
108'G', //G
109'H', //H
110'I', //I
111'J', //J
112'K', //K
113'L', //L
114'M', //M
115'N', //N
116'O', //O
117'P', //P
118'Q', //Q
119'R', //R
120'S', //S
121'T', //T
122'U', //U
123'V', //V
124'W', //W
125'X', //X
126'Y', //Y
127'Z', //Z
128'[', //[
129'\\', //\
130']', //]
131'^', //^
132'_', //_
133'`', //`
134'A', //a
135'B', //b
136'C', //c
137'D', //d
138'E', //e
139'F', //f
140'G', //g
141'H', //h
142'I', //i
143'J', //j
144'K', //k
145'L', //l
146'M', //m
147'N', //n
148'O', //o
149'P', //p
150'Q', //q
151'R', //r
152'S', //s
153'T', //t
154'U', //u
155'V', //v
156'W', //w
157'X', //x
158'Y', //y
159'Z', //z
160'{', //{
161'|', //|
162'}', //}
163'~', //~
164'', //
1650x80, //C-M-@
1660x81, //C-M-A
1670x82, //C-M-B
1680x83, //C-M-C
1690x84, //C-M-D
1700x85, //C-M-E
1710x86, //C-M-F
1720x87, //C-M-G
1730x88, //C-M-H
1740x89, //C-M-I
1750x8a, //C-M-J
1760x8b, //C-M-K
1770x8c, //C-M-L
1780x8d, //C-M-M
1790x8e, //C-M-N
1800x8f, //C-M-O
1810x90, //C-M-P
1820x91, //C-M-Q
1830x92, //C-M-R
1840x93, //C-M-S
1850x94, //C-M-T
1860x95, //C-M-U
1870x96, //C-M-V
1880x97, //C-M-W
1890x98, //C-M-X
1900x99, //C-M-Y
1910x9a, //C-M-Z
1920x9b, //C-M-[
1930x9c, //C-M-\
1940x9d, //C-M-]
1950x9e, //C-M-^
1960x9f, //C-M-_
197' ', // 
198'¡', //¡
199'¢', //¢
200'£', //£
201'¤', //¤
202'¥', //¥
203'¦', //¦
204'§', //§
205'¨', //¨
206'©', //©
207'A', //ª
208'«', //«
209'¬', //¬
210'­', //­
211'®', //®
212'¯', //¯
213'O', //°
214'±', //±
215'²', //²
216'³', //³
217'´', //´
218'µ', //µ
219'P', //¶
220'·', //·
221'¸', //¸
222'¹', //¹
223'O', //º
224'»', //»
225'¼', //¼
226'½', //½
227'¾', //¾
228'¿', //¿
229'A', //À
230'A', //Á
231'A', //Â
232'A', //Ã
233'A', //Ä
234'A', //Å
235'A', //Æ
236'C', //Ç
237'E', //È
238'E', //É
239'E', //Ê
240'E', //Ë
241'I', //Ì
242'I', //Í
243'I', //Î
244'I', //Ï
245'D', //Ð
246'N', //Ñ
247'O', //Ò
248'O', //Ó
249'O', //Ô
250'O', //Õ
251'O', //Ö
252'×', //×
253'O', //Ø
254'U', //Ù
255'U', //Ú
256'U', //Û
257'U', //Ü
258'Y', //Ý
259'T', //Þ
260'S', //ß
261'A', //à
262'A', //á
263'A', //â
264'A', //ã
265'A', //ä
266'A', //å
267'A', //æ
268'C', //ç
269'E', //è
270'E', //é
271'E', //ê
272'E', //ë
273'I', //ì
274'I', //í
275'I', //î
276'I', //ï
277'D', //ð
278'N', //ñ
279'O', //ò
280'O', //ó
281'O', //ô
282'O', //õ
283'O', //ö
284'÷', //÷
285'O', //ø
286'U', //ù
287'U', //ú
288'U', //û
289'U', //ü
290'Y', //ý
291'T', //þ
292'Y', //ÿ
293};
294
295
296
297
298
299static void hackString ( QString &s )
300{
301 int len = s.length();
302 const QChar* uc = s.unicode();
303 for ( int i = 0; i < len; i++ ) {
304 if ( !uc++->row() )
305 s[i] = collationHack[s[i].cell()];
306 }
307}
308
309QString buildSortKey( const QString & s )
310{
311 QString res = s;
312 hackString( res );
313 return res;
314}
315
316QString buildSortKey( const QString & s1, const QString & s2 )
317{
318 QString res = s1 + QChar( '\0' ) + s2;
319 hackString( res );
320 return res;
321}
322
323QString buildSortKey( const QString & s1, const QString & s2,
324 const QString & s3 )
325{
326 QString res = s1 + QChar( '\0' ) + s2 + QChar( '\0' ) + s3;
327 hackString( res );
328 return res;
329}
330
331static inline QChar coll( QChar u )
332{
333 return u.row() ? u : QChar(collationHack[ u.cell() ]);
334}
335
336
337int compare( const QString & s1, const QString & s2 )
338{
339 const QChar* u1 = s1.unicode();
340 const QChar* u2 = s2.unicode();
341
342 if ( u1 == u2 )
343 return 0;
344 if ( u1 == 0 )
345 return 1;
346 if ( u2 == 0 )
347 return -1;
348 int l=QMIN(s1.length(),s2.length());
349 while ( l-- && coll(*u1) == coll(*u2) )
350 u1++,u2++;
351 if ( l==-1 )
352 return ( s1.length()-s2.length() );
353 return u1->unicode() - u2->unicode();
354}
355
356QString simplifyMultiLineSpace( const QString &multiLine )
357{
358 QString result;
359 QStringList lines = QStringList::split("\n", multiLine);
360 for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) {
361 if ( it != lines.begin() )
362 result += "\n";
363 result += (*it).simplifyWhiteSpace();
364 }
365 return result;
366}
367
368QString escapeString( const QString& plain )
369{
370 QString tmp(plain);
371 int pos = tmp.length();
372 const QChar *uc = plain.unicode();
373 while ( pos-- ) {
374 unsigned char ch = uc[pos].latin1();
375 if ( ch == '&' )
376 tmp.replace( pos, 1, "&amp;" );
377 else if ( ch == '<' )
378 tmp.replace( pos, 1, "&lt;" );
379 else if ( ch == '>' )
380 tmp.replace( pos, 1, "&gt;" );
381 else if ( ch == '\"' )
382 tmp.replace( pos, 1, "&quot;" );
383 }
384 return tmp;
385}
386
387QString plainString( const char* escaped, unsigned int length )
388{
389 return plainString( QString::fromUtf8( escaped, length ) );
390}
391
392QString plainString( const QCString& string )
393{
394 // We first have to pass it through a ::fromUtf8()
395 return plainString( string.data(), string.length() );
396}
397
398QString plainString( const QString& string )
399{
400 QString tmp( string );
401 int pos = -1;
402 while ( (pos = tmp.find( "&", pos +1 ) ) != -1 ) {
403 if ( tmp.find( "&amp;", pos ) == pos )
404 tmp.replace( pos, 5, "&" );
405 else if ( tmp.find( "&lt;", pos ) == pos )
406 tmp.replace( pos, 4, "<" );
407 else if( tmp.find( "&gt;", pos ) == pos )
408 tmp.replace( pos, 4, ">" );
409 else if ( tmp.find( "&quot;", pos ) == pos )
410 tmp.replace( pos, 6, "\"" );
411 }
412 return tmp;
413}
414
415} // namespace QPC
diff --git a/library/backend/stringutil.h b/library/backend/stringutil.h
new file mode 100644
index 0000000..e9daf70
--- a/dev/null
+++ b/library/backend/stringutil.h
@@ -0,0 +1,57 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free
8** Software Foundation and appearing in the file LICENSE.GPL included
9** in the packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
12** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
13** PARTICULAR PURPOSE.
14**
15** See http://www.trolltech.com/gpl/ for GPL licensing information.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21
22
23#ifndef QTPALMTOP_stringutil_h__
24#define QTPALMTOP_stringutil_h__
25
26#include <qstring.h>
27#include "qpcglobal.h"
28
29namespace Qtopia
30{
31
32// Simplifies white space within each line but keeps the new line characters
33QString QPC_EXPORT simplifyMultiLineSpace( const QString &multiLine );
34
35// Creates a QString which doesn't contain any "dangerous"
36// characters (i.e. <, >, &, ")
37QString QPC_EXPORT escapeString( const QString& plain );
38
39// Takes a UTF-8!! string and removes all the XML thingies (entities?)
40// from the string and also calls fromUtf8() on it... so make sure
41// to pass a QCString/const char* with UTF-8 data only
42QString QPC_EXPORT plainString( const char* escaped, unsigned int length );
43QString QPC_EXPORT plainString( const QCString& string );
44
45QString QPC_EXPORT plainString( const QString& string );
46
47
48// collation functions
49int compare( const QString & s1, const QString & s2 );
50QString buildSortKey( const QString & s );
51QString buildSortKey( const QString & s1, const QString & s2 );
52QString buildSortKey( const QString & s1, const QString & s2,
53 const QString & s3 );
54
55}
56
57#endif
diff --git a/library/backend/task.cpp b/library/backend/task.cpp
new file mode 100644
index 0000000..e7d697d
--- a/dev/null
+++ b/library/backend/task.cpp
@@ -0,0 +1,271 @@
1/**********************************************************************
2** Copyright (C) 2001 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#include <qpe/task.h>
22#include <qregexp.h>
23#include <qstring.h>
24#include <qpe/recordfields.h>
25#include "vobject_p.h"
26#include "timeconversion.h"
27#include "qfiledirect_p.h"
28
29#include <stdio.h>
30
31using namespace Qtopia;
32UidGen Task::sUidGen( UidGen::Qtopia );
33
34Task::Task() : Record(), mDue( FALSE ),
35mDueDate( QDate::currentDate() ),
36mCompleted( FALSE ), mPriority( 3 ), mDesc()
37{
38}
39
40Task::Task( const QMap<int, QString> &m ) : Record(), mDue( FALSE ),
41mDueDate( QDate::currentDate() ), mCompleted( FALSE ), mPriority( 3 ), mDesc()
42{
43 //qDebug("Task::Task fromMap");
44 //dump( m );
45 for ( QMap<int,QString>::ConstIterator it = m.begin(); it != m.end();++it )
46 switch ( (TaskFields) it.key() ) {
47 case HasDate: if ( *it == "1" ) mDue = TRUE; break;
48 case Completed: setCompleted( *it == "1" ); break;
49 case TaskCategory: setCategories( idsFromString( *it ) ); break;
50 case TaskDescription: setDescription( *it ); break;
51 case Priority: setPriority( (*it).toInt() ); break;
52 case Date: mDueDate = TimeConversion::fromString( (*it) ); break;
53 case TaskUid: setUid( (*it).toInt() ); break;
54 }
55}
56
57Task::~Task()
58{
59}
60
61QMap<int, QString> Task::toMap() const
62{
63 QMap<int, QString> m;
64 m.insert( HasDate, hasDueDate() ? "1" : "0" );
65 m.insert( Completed, isCompleted() ? "1" : "0" );
66 m.insert( TaskCategory, idsToString( categories() ) );
67 m.insert( TaskDescription, description() );
68 m.insert( Priority, QString::number( priority() ) );
69 m.insert( Date, TimeConversion::toString( dueDate() ) );
70 m.insert( TaskUid, QString::number(uid()) );
71
72 //qDebug("Task::toMap");
73 //dump( m );
74 return m;
75}
76
77void Task::save( QString& buf ) const
78{
79 buf += " Completed=\"";
80 // qDebug( "writing %d", complete );
81 buf += QString::number( (int)mCompleted );
82 buf += "\"";
83 buf += " HasDate=\"";
84 // qDebug( "writing %d", );
85 buf += QString::number( (int)mDue );
86 buf += "\"";
87 buf += " Priority=\"";
88 // qDebug ("writing %d", prior );
89 buf += QString::number( mPriority );
90 buf += "\"";
91 buf += " Categories=\"";
92 buf += Qtopia::Record::idsToString( categories() );
93 buf += "\"";
94 buf += " Description=\"";
95 // qDebug( "writing note %s", note.latin1() );
96 buf += Qtopia::escapeString( mDesc );
97 buf += "\"";
98 if ( mDue ) {
99 // qDebug("saving ymd %d %d %d", mDueDate.year(), mDueDate.month(),
100 // mDueDate.day() );
101 buf += " DateYear=\"";
102 buf += QString::number( mDueDate.year() );
103 buf += "\"";
104 buf += " DateMonth=\"";
105 buf += QString::number( mDueDate.month() );
106 buf += "\"";
107 buf += " DateDay=\"";
108 buf += QString::number( mDueDate.day() );
109 buf += "\"";
110 }
111 buf += customToXml();
112 // qDebug ("writing uid %d", uid() );
113 buf += " Uid=\"";
114 buf += QString::number( uid() );
115 // terminate it in the application...
116 buf += "\"";
117}
118
119bool Task::match ( const QRegExp &r ) const
120{
121 // match on priority, description on due date...
122 bool match;
123 match = false;
124 if ( QString::number( mPriority ).find( r ) > -1 )
125 match = true;
126 else if ( mDue && mDueDate.toString().find( r ) > -1 )
127 match = true;
128 else if ( mDesc.find( r ) > -1 )
129 match = true;
130 return match;
131}
132
133static inline VObject *safeAddPropValue( VObject *o, const char *prop, const QString &value )
134{
135 VObject *ret = 0;
136 if ( o && !value.isEmpty() )
137 ret = addPropValue( o, prop, value.latin1() );
138 return ret;
139}
140
141static inline VObject *safeAddProp( VObject *o, const char *prop)
142{
143 VObject *ret = 0;
144 if ( o )
145 ret = addProp( o, prop );
146 return ret;
147}
148
149
150static VObject *createVObject( const Task &t )
151{
152 VObject *vcal = newVObject( VCCalProp );
153 safeAddPropValue( vcal, VCVersionProp, "1.0" );
154 VObject *task = safeAddProp( vcal, VCTodoProp );
155
156 if ( t.hasDueDate() )
157 safeAddPropValue( task, VCDueProp, TimeConversion::toISO8601( t.dueDate() ) );
158 safeAddPropValue( task, VCDescriptionProp, t.description() );
159 if ( t.isCompleted() )
160 safeAddPropValue( task, VCStatusProp, "COMPLETED" );
161 safeAddPropValue( task, VCPriorityProp, QString::number( t.priority() ) );
162
163 return vcal;
164}
165
166
167static Task parseVObject( VObject *obj )
168{
169 Task t;
170
171 VObjectIterator it;
172 initPropIterator( &it, obj );
173 while( moreIteration( &it ) ) {
174 VObject *o = nextVObject( &it );
175 QCString name = vObjectName( o );
176 QCString value = vObjectStringZValue( o );
177 if ( name == VCDueProp ) {
178 t.setDueDate( TimeConversion::fromISO8601( value ).date(), TRUE );
179 }
180 else if ( name == VCDescriptionProp ) {
181 t.setDescription( value );
182 }
183 else if ( name == VCStatusProp ) {
184 if ( value == "COMPLETED" )
185 t.setCompleted( TRUE );
186 }
187 else if ( name == VCPriorityProp ) {
188 t.setPriority( value.toInt() );
189 }
190#if 0
191 else {
192 printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) );
193 VObjectIterator nit;
194 initPropIterator( &nit, o );
195 while( moreIteration( &nit ) ) {
196 VObject *o = nextVObject( &nit );
197 QCString name = vObjectName( o );
198 QString value = vObjectStringZValue( o );
199 printf(" subprop: %s = %s\n", name.data(), value.latin1() );
200 }
201 }
202#endif
203 }
204
205 return t;
206}
207
208
209
210void Task::writeVCalendar( const QString &filename, const QValueList<Task> &tasks)
211{
212 QFileDirect f( filename.utf8().data() );
213 if ( !f.open( IO_WriteOnly ) ) {
214 qWarning("Unable to open vcard write");
215 return;
216 }
217
218 QValueList<Task>::ConstIterator it;
219 for( it = tasks.begin(); it != tasks.end(); ++it ) {
220 VObject *obj = createVObject( *it );
221 writeVObject(f.directHandle() , obj );
222 cleanVObject( obj );
223 }
224
225 cleanStrTbl();
226}
227
228void Task::writeVCalendar( const QString &filename, const Task &task)
229{
230 QFileDirect f( filename.utf8().data() );
231 if ( !f.open( IO_WriteOnly ) ) {
232 qWarning("Unable to open vcard write");
233 return;
234 }
235
236 VObject *obj = createVObject( task );
237 writeVObject(f.directHandle() , obj );
238 cleanVObject( obj );
239
240 cleanStrTbl();
241}
242
243
244QValueList<Task> Task::readVCalendar( const QString &filename )
245{
246 VObject *obj = Parse_MIME_FromFileName( (char *)filename.utf8().data() );
247
248 QValueList<Task> tasks;
249
250 while ( obj ) {
251 QCString name = vObjectName( obj );
252 if ( name == VCCalProp ) {
253 VObjectIterator nit;
254 initPropIterator( &nit, obj );
255 while( moreIteration( &nit ) ) {
256 VObject *o = nextVObject( &nit );
257 QCString name = vObjectName( o );
258 if ( name == VCTodoProp )
259 tasks.append( parseVObject( o ) );
260 }
261 } else if ( name == VCTodoProp ) {
262 // shouldn't happen, but just to be sure
263 tasks.append( parseVObject( obj ) );
264 }
265 VObject *t = obj;
266 obj = nextVObjectInList(obj);
267 cleanVObject( t );
268 }
269
270 return tasks;
271}
diff --git a/library/backend/task.h b/library/backend/task.h
new file mode 100644
index 0000000..ffe26b0
--- a/dev/null
+++ b/library/backend/task.h
@@ -0,0 +1,77 @@
1/**********************************************************************
2** Copyright (C) 2001 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20#ifndef __TASK_H__
21#define __TASK_H__
22
23#include <qpe/palmtoprecord.h>
24#include <qpe/stringutil.h>
25
26#include <qvaluelist.h>
27#include <qdatetime.h>
28
29class TaskPrivate;
30class QPC_EXPORT Task : public Qtopia::Record
31{
32public:
33 Task();
34 Task( const QMap<int, QString> &fromMap );
35 ~Task();
36
37 QMap<int, QString> toMap() const;
38
39 static void writeVCalendar( const QString &filename, const QValueList<Task> &tasks);
40 static void writeVCalendar( const QString &filename, const Task &task);
41 static QValueList<Task> readVCalendar( const QString &filename );
42
43 void setPriority( int priority ) { mPriority = priority; }
44 int priority() const { return mPriority; }
45
46// void setCategory( const QString& category )
47// { mCategory = category.stripWhiteSpace(); }
48// const QString &category() const { return mCategory; }
49
50 void setDescription( const QString& description )
51 { mDesc = Qtopia::simplifyMultiLineSpace(description); }
52 const QString &description() const { return mDesc; }
53
54 void setDueDate( const QDate& date, bool hasDue ) { mDueDate = date; mDue = hasDue; }
55 const QDate &dueDate() const { return mDueDate; }
56 bool hasDueDate() const { return mDue; }
57 void setHasDueDate( bool b ) { mDue = b; }
58
59 void setCompleted( bool b ) { mCompleted = b; }
60 bool isCompleted() const { return mCompleted; }
61
62 void save( QString& buf ) const;
63 bool match( const QRegExp &r ) const;
64
65private:
66 Qtopia::UidGen &uidGen() { return sUidGen; }
67 static Qtopia::UidGen sUidGen;
68
69 bool mDue;
70 QDate mDueDate;
71 bool mCompleted;
72 int mPriority;
73 QString mDesc;
74 TaskPrivate *d;
75};
76
77#endif
diff --git a/library/backend/timeconversion.cpp b/library/backend/timeconversion.cpp
new file mode 100644
index 0000000..a4a2547
--- a/dev/null
+++ b/library/backend/timeconversion.cpp
@@ -0,0 +1,237 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#include <qglobal.h>
22#include "timeconversion.h"
23#include <qregexp.h>
24#include <stdlib.h>
25
26QString TimeConversion::toString( const QDate &d )
27{
28 QString r = QString::number( d.day() ) + "." +
29 QString::number( d.month() ) + "." +
30 QString::number( d.year() );
31 //qDebug("TimeConversion::toString %s", r.latin1());
32 return r;
33}
34
35QDate TimeConversion::fromString( const QString &datestr )
36{
37 int monthPos = datestr.find('.');
38 int yearPos = datestr.find('.', monthPos+1 );
39 if ( monthPos == -1 || yearPos == -1 ) {
40 qDebug("fromString didn't find . in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, yearPos );
41 return QDate();
42 }
43 int d = datestr.left( monthPos ).toInt();
44 int m = datestr.mid( monthPos+1, yearPos - monthPos - 1 ).toInt();
45 int y = datestr.mid( yearPos+1 ).toInt();
46 QDate date ( y,m,d );
47 //qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, yearPos);
48 return date;
49}
50
51time_t TimeConversion::toUTC( const QDateTime& dt )
52{
53 time_t tmp;
54 struct tm *lt;
55
56#if defined(_OS_WIN32) || defined (Q_OS_WIN32) || defined (Q_OS_WIN64)
57 _tzset();
58#else
59 tzset();
60#endif
61
62 // get a tm structure from the system to get the correct tz_name
63 tmp = time( 0 );
64 lt = localtime( &tmp );
65
66 lt->tm_sec = dt.time().second();
67 lt->tm_min = dt.time().minute();
68 lt->tm_hour = dt.time().hour();
69 lt->tm_mday = dt.date().day();
70 lt->tm_mon = dt.date().month() - 1; // 0-11 instead of 1-12
71 lt->tm_year = dt.date().year() - 1900; // year - 1900
72 //lt->tm_wday = dt.date().dayOfWeek(); ignored anyway
73 //lt->tm_yday = dt.date().dayOfYear(); ignored anyway
74 lt->tm_wday = -1;
75 lt->tm_yday = -1;
76 // tm_isdst negative -> mktime will find out about DST
77 lt->tm_isdst = -1;
78 // keep tm_zone and tm_gmtoff
79 tmp = mktime( lt );
80 return tmp;
81}
82
83QDateTime TimeConversion::fromUTC( time_t time )
84{
85 struct tm *lt;
86
87#if defined(_OS_WIN32) || defined (Q_OS_WIN32) || defined (Q_OS_WIN64)
88 _tzset();
89#else
90 tzset();
91#endif
92 lt = localtime( &time );
93 QDateTime dt;
94 dt.setDate( QDate( lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday ) );
95 dt.setTime( QTime( lt->tm_hour, lt->tm_min, lt->tm_sec ) );
96 return dt;
97}
98
99
100int TimeConversion::secsTo( const QDateTime &from, const QDateTime &to )
101{
102 return toUTC( to ) - toUTC( from );
103}
104
105QCString TimeConversion::toISO8601( const QDate &d )
106{
107 time_t tmp = toUTC( d );
108 struct tm *utc = gmtime( &tmp );
109
110 QCString str;
111 str.sprintf("%04d%02d%02d", (utc->tm_year + 1900), utc->tm_mon+1, utc->tm_mday );
112 return str;
113}
114
115QCString TimeConversion::toISO8601( const QDateTime &dt )
116{
117 time_t tmp = toUTC( dt );
118 struct tm *utc = gmtime( &tmp );
119
120 QCString str;
121 str.sprintf("%04d%02d%02dT%02d%02d%02dZ",
122 (utc->tm_year + 1900), utc->tm_mon+1, utc->tm_mday,
123 utc->tm_hour, utc->tm_min, utc->tm_sec );
124 return str;
125}
126
127QDateTime TimeConversion::fromISO8601( const QCString &s )
128{
129
130#if defined(_OS_WIN32) || defined (Q_OS_WIN32) || defined (Q_OS_WIN64)
131 _tzset();
132#else
133 tzset();
134#endif
135
136 struct tm *thetime = new tm;
137
138 QCString str = s.copy();
139 str.replace(QRegExp("-"), "" );
140 str.replace(QRegExp(":"), "" );
141 str.stripWhiteSpace();
142 str = str.lower();
143
144 int i = str.find( "t" );
145 QCString date;
146 QCString timestr;
147 if ( i != -1 ) {
148 date = str.left( i );
149 timestr = str.mid( i+1 );
150 } else {
151 date = str;
152 }
153
154// qDebug("--- parsing ISO time---");
155 thetime->tm_year = 100;
156 thetime->tm_mon = 0;
157 thetime->tm_mday = 0;
158 thetime->tm_hour = 0;
159 thetime->tm_min = 0;
160 thetime->tm_sec = 0;
161
162// qDebug("date = %s", date.data() );
163
164 switch( date.length() ) {
165 case 8:
166 thetime->tm_mday = date.right( 2 ).toInt();
167 case 6:
168 thetime->tm_mon = date.mid( 4, 2 ).toInt() - 1;
169 case 4:
170 thetime->tm_year = date.left( 4 ).toInt();
171 thetime->tm_year -= 1900;
172 break;
173 default:
174 break;
175 }
176
177 int tzoff = 0;
178 bool inLocalTime = FALSE;
179 if ( timestr.find( 'z' ) == (int)timestr.length() - 1 )
180 // UTC
181 timestr = timestr.left( timestr.length() -1 );
182 else {
183 int plus = timestr.find( "+" );
184 int minus = timestr.find( "-" );
185 if ( plus != -1 || minus != -1 ) {
186 // have a timezone offset
187 plus = (plus != -1) ? plus : minus;
188 QCString off = timestr.mid( plus );
189 timestr = timestr.left( plus );
190
191 int tzoffhour = 0;
192 int tzoffmin = 0;
193 switch( off.length() ) {
194 case 5:
195 tzoffmin = off.mid(3).toInt();
196 case 3:
197 tzoffhour = off.left(3).toInt();
198 default:
199 break;
200 }
201 tzoff = 60*tzoffhour + tzoffmin;
202 } else
203 inLocalTime = TRUE;
204 }
205
206 // get the time:
207 switch( timestr.length() ) {
208 case 6:
209 thetime->tm_sec = timestr.mid( 4 ).toInt();
210 case 4:
211 thetime->tm_min = timestr.mid( 2, 2 ).toInt();
212 case 2:
213 thetime->tm_hour = timestr.left( 2 ).toInt();
214 default:
215 break;
216 }
217
218 int tzloc = 0;
219 time_t tmp = time( 0 );
220 if ( !inLocalTime ) {
221 // have to get the offset between gmt and local time
222 struct tm *lt = localtime( &tmp );
223 tzloc = mktime( lt );
224 struct tm *ut = gmtime( &tmp );
225 tzloc -= mktime( ut );
226 }
227// qDebug("time: %d %d %d, tzloc=%d, tzoff=%d", thetime->tm_hour, thetime->tm_min, thetime->tm_sec,
228 // tzloc, tzoff );
229
230 tmp = mktime( thetime );
231 tmp += 60*(-tzloc + tzoff);
232
233 delete thetime;
234
235 return fromUTC( tmp );
236}
237
diff --git a/library/backend/timeconversion.h b/library/backend/timeconversion.h
new file mode 100644
index 0000000..1724812
--- a/dev/null
+++ b/library/backend/timeconversion.h
@@ -0,0 +1,45 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#ifndef __timeconversion_h__
22#define __timeconversion_h__
23
24#include <time.h>
25#include <sys/types.h>
26#include <qdatetime.h>
27
28#include <qpe/qpcglobal.h>
29
30class QPC_EXPORT TimeConversion
31{
32public:
33 static QString toString( const QDate &d );
34 static QDate fromString( const QString &datestr );
35
36 static time_t toUTC( const QDateTime& dt );
37 static QDateTime fromUTC( time_t time );
38 static int secsTo( const QDateTime &from, const QDateTime &to );
39
40 static QCString toISO8601( const QDate & );
41 static QCString toISO8601( const QDateTime & );
42 static QDateTime fromISO8601( const QCString & );
43};
44
45#endif // __timeconversion_h__
diff --git a/library/backend/vcc.y b/library/backend/vcc.y
new file mode 100644
index 0000000..0225982
--- a/dev/null
+++ b/library/backend/vcc.y
@@ -0,0 +1,1199 @@
1%{
2
3/***************************************************************************
4(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
5Business Machines Corporation and Siemens Rolm Communications Inc.
6
7For purposes of this license notice, the term Licensors shall mean,
8collectively, Apple Computer, Inc., AT&T Corp., International
9Business Machines Corporation and Siemens Rolm Communications Inc.
10The term Licensor shall mean any of the Licensors.
11
12Subject to acceptance of the following conditions, permission is hereby
13granted by Licensors without the need for written agreement and without
14license or royalty fees, to use, copy, modify and distribute this
15software for any purpose.
16
17The above copyright notice and the following four paragraphs must be
18reproduced in all copies of this software and any software including
19this software.
20
21THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
22ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
23MODIFICATIONS.
24
25IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
26INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
27OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28DAMAGE.
29
30EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
31INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
32IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33PURPOSE.
34
35The software is provided with RESTRICTED RIGHTS. Use, duplication, or
36disclosure by the government are subject to restrictions set forth in
37DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
38
39***************************************************************************/
40
41/*
42 * src: vcc.c
43 * doc: Parser for vCard and vCalendar. Note that this code is
44 * generated by a yacc parser generator. Generally it should not
45 * be edited by hand. The real source is vcc.y. The #line directives
46 * can be commented out here to make it easier to trace through
47 * in a debugger. However, if a bug is found it should
48 * be fixed in vcc.y and this file regenerated.
49 */
50
51
52/* debugging utilities */
53#if __DEBUG
54#define DBG_(x) printf x
55#else
56#define DBG_(x)
57#endif
58
59/**** External Functions ****/
60
61/* assign local name to parser variables and functions so that
62 we can use more than one yacc based parser.
63*/
64
65#if 0
66#define yyparse mime_parse
67#define yylex mime_lex
68#define yyerror mime_error
69#define yychar mime_char
70/* #define p_yyval p_mime_val */
71#undef yyval
72#define yyval mime_yyval
73/* #define p_yylval p_mime_lval */
74#undef yylval
75#define yylval mime_yylval
76#define yydebug mime_debug
77#define yynerrs mime_nerrs
78#define yyerrflag mime_errflag
79#define yyss mime_ss
80#define yyssp mime_ssp
81#define yyvs mime_vs
82#define yyvsp mime_vsp
83#define yylhs mime_lhs
84#define yylen mime_len
85#define yydefred mime_defred
86#define yydgoto mime_dgoto
87#define yysindex mime_sindex
88#define yyrindex mime_rindex
89#define yygindex mime_gindex
90#define yytable mime_table
91#define yycheck mime_check
92#define yyname mime_name
93#define yyrule mime_rule
94#ifdef YYPREFIX
95#undef YYPREFIX
96#endif
97#define YYPREFIX "mime_"
98#endif
99
100
101#ifndef _NO_LINE_FOLDING
102#define _SUPPORT_LINE_FOLDING 1
103#endif
104
105/* undef below if compile with MFC */
106/* #define INCLUDEMFC 1 */
107
108#if defined(WIN32) || defined(_WIN32)
109#ifdef INCLUDEMFC
110#include <afx.h>
111#endif
112#endif
113
114#include <string.h>
115#ifndef __MWERKS__
116#include <stdlib.h>
117#endif
118#include <stdio.h>
119#include <stdlib.h>
120#include <ctype.h>
121
122//#ifdef PALMTOPCENTER
123//#include <qpe/vobject_p.h>
124//#else
125#include "vobject_p.h"
126//#endif
127
128/**** Types, Constants ****/
129
130 #define YYDEBUG 0/* 1 to compile in some debugging code */
131 #define MAXTOKEN 256/* maximum token (line) length */
132 #define YYSTACKSIZE 100// ~unref ?
133 #define MAXLEVEL 10/* max # of nested objects parseable */
134 /* (includes outermost) */
135
136
137/**** Global Variables ****/
138int mime_lineNum, mime_numErrors; /* yyerror() can use these */
139static VObject* vObjList;
140static VObject *curProp;
141static VObject *curObj;
142static VObject* ObjStack[MAXLEVEL];
143static int ObjStackTop;
144
145
146/* A helpful utility for the rest of the app. */
147#if __CPLUSPLUS__
148extern "C" {
149#endif
150
151 extern void yyerror(char *s);
152
153#if __CPLUSPLUS__
154 };
155#endif
156
157int yyparse();
158
159enum LexMode {
160 L_NORMAL,
161 L_VCARD,
162 L_VCAL,
163 L_VEVENT,
164 L_VTODO,
165 L_VALUES,
166 L_BASE64,
167 L_QUOTED_PRINTABLE
168 };
169
170/**** Private Forward Declarations ****/
171static int pushVObject(const char *prop);
172static VObject* popVObject();
173static void lexPopMode(int top);
174static int lexWithinMode(enum LexMode mode);
175static void lexPushMode(enum LexMode mode);
176static void enterProps(const char *s);
177static void enterAttr(const char *s1, const char *s2);
178static void enterValues(const char *value);
179#define mime_error yyerror
180void mime_error(char *s);
181void mime_error_(char *s);
182
183%}
184
185/***************************************************************************/
186/*** The grammar ****/
187/***************************************************************************/
188
189%union {
190 char *str;
191 VObject *vobj;
192 }
193
194%token
195 EQ COLON DOT SEMICOLON SPACE HTAB LINESEP NEWLINE
196 BEGIN_VCARD END_VCARD BEGIN_VCAL END_VCAL
197 BEGIN_VEVENT END_VEVENT BEGIN_VTODO END_VTODO
198 ID
199
200/*
201 * NEWLINE is the token that would occur outside a vCard,
202 * while LINESEP is the token that would occur inside a vCard.
203 */
204
205%token <str>
206 STRING ID
207
208%type <str> name value
209
210%type <vobj> vcard vcal vobject
211
212%start mime
213
214%%
215
216
217mime: vobjects
218 ;
219
220vobjects: vobjects vobject
221 { addList(&vObjList, $2); curObj = 0; }
222 | vobject
223 { addList(&vObjList, $1); curObj = 0; }
224 ;
225
226vobject: vcard
227 | vcal
228 ;
229
230vcard:
231 BEGIN_VCARD
232 {
233 lexPushMode(L_VCARD);
234 if (!pushVObject(VCCardProp)) YYERROR;
235 }
236 items END_VCARD
237 {
238 lexPopMode(0);
239 $$ = popVObject();
240 }
241 | BEGIN_VCARD
242 {
243 lexPushMode(L_VCARD);
244 if (!pushVObject(VCCardProp)) YYERROR;
245 }
246 END_VCARD
247 {
248 lexPopMode(0);
249 $$ = popVObject();
250 }
251 ;
252
253items: items item
254 | item
255 ;
256
257item: prop COLON
258 {
259 lexPushMode(L_VALUES);
260 }
261 values LINESEP
262 {
263 if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
264 lexPopMode(0);
265 lexPopMode(0);
266 }
267 | error
268 ;
269
270prop: name
271 {
272 enterProps($1);
273 }
274 attr_params
275 | name
276 {
277 enterProps($1);
278 }
279 ;
280
281attr_params: attr_params attr_param
282 | attr_param
283 ;
284
285attr_param: SEMICOLON attr
286 ;
287
288attr: name
289 {
290 enterAttr($1,0);
291 }
292 | name EQ name
293 {
294 enterAttr($1,$3);
295
296 }
297 ;
298
299name: ID
300 ;
301
302values: value SEMICOLON { enterValues($1); } values
303 | value
304 { enterValues($1); }
305 ;
306
307value: STRING
308 |
309 { $$ = 0; }
310 ;
311
312vcal:
313 BEGIN_VCAL
314 { if (!pushVObject(VCCalProp)) YYERROR; }
315 calitems
316 END_VCAL
317 { $$ = popVObject(); }
318 | BEGIN_VCAL
319 { if (!pushVObject(VCCalProp)) YYERROR; }
320 END_VCAL
321 { $$ = popVObject(); }
322 ;
323
324calitems: calitems calitem
325 | calitem
326 ;
327
328calitem:
329 eventitem
330 | todoitem
331 | items
332 ;
333
334eventitem:
335 BEGIN_VEVENT
336 {
337 lexPushMode(L_VEVENT);
338 if (!pushVObject(VCEventProp)) YYERROR;
339 }
340 items
341 END_VEVENT
342 {
343 lexPopMode(0);
344 popVObject();
345 }
346 | BEGIN_VEVENT
347 {
348 lexPushMode(L_VEVENT);
349 if (!pushVObject(VCEventProp)) YYERROR;
350 }
351 END_VEVENT
352 {
353 lexPopMode(0);
354 popVObject();
355 }
356 ;
357
358todoitem:
359 BEGIN_VTODO
360 {
361 lexPushMode(L_VTODO);
362 if (!pushVObject(VCTodoProp)) YYERROR;
363 }
364 items
365 END_VTODO
366 {
367 lexPopMode(0);
368 popVObject();
369 }
370 | BEGIN_VTODO
371 {
372 lexPushMode(L_VTODO);
373 if (!pushVObject(VCTodoProp)) YYERROR;
374 }
375 END_VTODO
376 {
377 lexPopMode(0);
378 popVObject();
379 }
380 ;
381
382%%
383/*------------------------------------*/
384static int pushVObject(const char *prop)
385 {
386 VObject *newObj;
387 if (ObjStackTop == MAXLEVEL)
388 return FALSE;
389
390 ObjStack[++ObjStackTop] = curObj;
391
392 if (curObj) {
393 newObj = addProp(curObj,prop);
394 curObj = newObj;
395 }
396 else
397 curObj = newVObject(prop);
398
399 return TRUE;
400 }
401
402
403/*---------------------------------------*/
404/* This pops the recently built vCard off the stack and returns it. */
405static VObject* popVObject()
406 {
407 VObject *oldObj;
408 if (ObjStackTop < 0) {
409 yyerror("pop on empty Object Stack\n");
410 return 0;
411 }
412 oldObj = curObj;
413 curObj = ObjStack[ObjStackTop--];
414
415 return oldObj;
416 }
417
418
419static void enterValues(const char *value)
420 {
421 if (fieldedProp && *fieldedProp) {
422 if (value) {
423 addPropValue(curProp,*fieldedProp,value);
424 }
425 /* else this field is empty, advance to next field */
426 fieldedProp++;
427 }
428 else {
429 if (value) {
430 setVObjectStringZValue_(curProp,strdup( value ));
431 }
432 }
433 deleteStr(value);
434 }
435
436static void enterProps(const char *s)
437 {
438 curProp = addGroup(curObj,s);
439 deleteStr(s);
440 }
441
442static void enterAttr(const char *s1, const char *s2)
443 {
444 const char *p1, *p2;
445 p1 = lookupProp_(s1);
446 if (s2) {
447 VObject *a;
448 p2 = lookupProp_(s2);
449 a = addProp(curProp,p1);
450 setVObjectStringZValue(a,p2);
451 }
452 else
453 addProp(curProp,p1);
454 if (qstricmp(p1,VCBase64Prop) == 0 || (s2 && qstricmp(p2,VCBase64Prop)==0))
455 lexPushMode(L_BASE64);
456 else if (qstricmp(p1,VCQuotedPrintableProp) == 0
457 || (s2 && qstricmp(p2,VCQuotedPrintableProp)==0))
458 lexPushMode(L_QUOTED_PRINTABLE);
459 deleteStr(s1); deleteStr(s2);
460 }
461
462
463#define MAX_LEX_LOOKAHEAD_0 32
464#define MAX_LEX_LOOKAHEAD 64
465#define MAX_LEX_MODE_STACK_SIZE 10
466#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
467
468struct LexBuf {
469 /* input */
470#ifdef INCLUDEMFC
471 CFile *inputFile;
472#else
473 FILE *inputFile;
474#endif
475 char *inputString;
476 unsigned long curPos;
477 unsigned long inputLen;
478 /* lookahead buffer */
479 /* -- lookahead buffer is short instead of char so that EOF
480 / can be represented correctly.
481 */
482 unsigned long len;
483 short buf[MAX_LEX_LOOKAHEAD];
484 unsigned long getPtr;
485 /* context stack */
486 unsigned long lexModeStackTop;
487 enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
488 /* token buffer */
489 unsigned long maxToken;
490 char *strs;
491 unsigned long strsLen;
492 } lexBuf;
493
494static void lexPushMode(enum LexMode mode)
495 {
496 if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
497 yyerror("lexical context stack overflow");
498 else {
499 lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
500 }
501 }
502
503static void lexPopMode(int top)
504 {
505 /* special case of pop for ease of error recovery -- this
506 version will never underflow */
507 if (top)
508 lexBuf.lexModeStackTop = 0;
509 else
510 if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
511 }
512
513static int lexWithinMode(enum LexMode mode) {
514 unsigned long i;
515 for (i=0;i<lexBuf.lexModeStackTop;i++)
516 if (mode == lexBuf.lexModeStack[i]) return 1;
517 return 0;
518 }
519
520static char lexGetc_()
521 {
522 /* get next char from input, no buffering. */
523 if (lexBuf.curPos == lexBuf.inputLen)
524 return EOF;
525 else if (lexBuf.inputString)
526 return *(lexBuf.inputString + lexBuf.curPos++);
527 else {
528#ifdef INCLUDEMFC
529 char result;
530 return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF;
531#else
532 return fgetc(lexBuf.inputFile);
533#endif
534 }
535 }
536
537static int lexGeta()
538 {
539 ++lexBuf.len;
540 return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
541 }
542
543static int lexGeta_(int i)
544 {
545 ++lexBuf.len;
546 return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
547 }
548
549static void lexSkipLookahead() {
550 if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
551 /* don't skip EOF. */
552 lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
553 lexBuf.len--;
554 }
555 }
556
557static int lexLookahead() {
558 int c = (lexBuf.len)?
559 lexBuf.buf[lexBuf.getPtr]:
560 lexGeta();
561 /* do the \r\n -> \n or \r -> \n translation here */
562 if (c == '\r') {
563 int a = (lexBuf.len>1)?
564 lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
565 lexGeta_(1);
566 if (a == '\n') {
567 lexSkipLookahead();
568 }
569 lexBuf.buf[lexBuf.getPtr] = c = '\n';
570 }
571 else if (c == '\n') {
572 int a = (lexBuf.len>1)?
573 lexBuf.buf[lexBuf.getPtr+1]:
574 lexGeta_(1);
575 if (a == '\r') {
576 lexSkipLookahead();
577 }
578 lexBuf.buf[lexBuf.getPtr] = '\n';
579 }
580 return c;
581 }
582
583static int lexGetc() {
584 int c = lexLookahead();
585 if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
586 /* EOF will remain in lookahead buffer */
587 lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
588 lexBuf.len--;
589 }
590 return c;
591 }
592
593static void lexSkipLookaheadWord() {
594 if (lexBuf.strsLen <= lexBuf.len) {
595 lexBuf.len -= lexBuf.strsLen;
596 lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
597 }
598 }
599
600static void lexClearToken()
601 {
602 lexBuf.strsLen = 0;
603 }
604
605static void lexAppendc(int c)
606 {
607 lexBuf.strs[lexBuf.strsLen] = c;
608 /* append up to zero termination */
609 if (c == 0) return;
610 lexBuf.strsLen++;
611 if (lexBuf.strsLen > lexBuf.maxToken) {
612 /* double the token string size */
613 lexBuf.maxToken <<= 1;
614 lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
615 }
616 }
617
618static char* lexStr() {
619 return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
620 }
621
622static void lexSkipWhite() {
623 int c = lexLookahead();
624 while (c == ' ' || c == '\t') {
625 lexSkipLookahead();
626 c = lexLookahead();
627 }
628 }
629
630static char* lexGetWord() {
631 int c;
632 lexSkipWhite();
633 lexClearToken();
634 c = lexLookahead();
635 while (c != EOF && !strchr("\t\n ;:=",c)) {
636 lexAppendc(c);
637 lexSkipLookahead();
638 c = lexLookahead();
639 }
640 lexAppendc(0);
641 return lexStr();
642 }
643
644static void lexPushLookaheadc(int c) {
645 int putptr;
646 /* can't putback EOF, because it never leaves lookahead buffer */
647 if (c == EOF) return;
648 putptr = (int)lexBuf.getPtr - 1;
649 if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
650 lexBuf.getPtr = putptr;
651 lexBuf.buf[putptr] = c;
652 lexBuf.len += 1;
653 }
654
655static char* lexLookaheadWord() {
656 /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
657 / and thing bigger than that will stop the lookahead and return 0;
658 / leading white spaces are not recoverable.
659 */
660 int c;
661 int len = 0;
662 int curgetptr = 0;
663 lexSkipWhite();
664 lexClearToken();
665 curgetptr = (int)lexBuf.getPtr;// remember!
666 while (len < (MAX_LEX_LOOKAHEAD_0)) {
667 c = lexGetc();
668 len++;
669 if (c == EOF || strchr("\t\n ;:=", c)) {
670 lexAppendc(0);
671 /* restore lookahead buf. */
672 lexBuf.len += len;
673 lexBuf.getPtr = curgetptr;
674 return lexStr();
675 }
676 else
677 lexAppendc(c);
678 }
679 lexBuf.len += len;/* char that has been moved to lookahead buffer */
680 lexBuf.getPtr = curgetptr;
681 return 0;
682 }
683
684#ifdef _SUPPORT_LINE_FOLDING
685static void handleMoreRFC822LineBreak(int c) {
686 /* suport RFC 822 line break in cases like
687 *ADR: foo;
688 * morefoo;
689 * more foo;
690 */
691 if (c == ';') {
692 int a;
693 lexSkipLookahead();
694 /* skip white spaces */
695 a = lexLookahead();
696 while (a == ' ' || a == '\t') {
697 lexSkipLookahead();
698 a = lexLookahead();
699 }
700 if (a == '\n') {
701 lexSkipLookahead();
702 a = lexLookahead();
703 if (a == ' ' || a == '\t') {
704 /* continuation, throw away all the \n and spaces read so
705 * far
706 */
707 lexSkipWhite();
708 lexPushLookaheadc(';');
709 }
710 else {
711 lexPushLookaheadc('\n');
712 lexPushLookaheadc(';');
713 }
714 }
715 else {
716 lexPushLookaheadc(';');
717 }
718 }
719 }
720
721static char* lexGet1Value() {
722 int c;
723 lexSkipWhite();
724 c = lexLookahead();
725 lexClearToken();
726 while (c != EOF && c != ';') {
727 if (c == '\\' ) {
728 int a;
729 lexSkipLookahead();
730 a = lexLookahead();
731 if ( a != ';' ) {
732 lexAppendc('\\');
733 } else {
734 lexAppendc( ';' );
735 lexSkipLookahead();
736 }
737 } else if (c == '\n') {
738 int a;
739 lexSkipLookahead();
740 a = lexLookahead();
741 if (a == ' ' || a == '\t') {
742 lexAppendc(' ');
743 lexSkipLookahead();
744 }
745 else {
746 lexPushLookaheadc('\n');
747 break;
748 }
749 }
750 else {
751 lexAppendc(c);
752 lexSkipLookahead();
753 }
754 c = lexLookahead();
755 }
756 lexAppendc(0);
757 handleMoreRFC822LineBreak(c);
758 return c==EOF?0:lexStr();
759 }
760#endif
761
762static int match_begin_name(int end) {
763 char *n = lexLookaheadWord();
764 int token = ID;
765 if (n) {
766 if (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
767 else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
768 else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
769 else if (!qstricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
770 deleteStr(n);
771 return token;
772 }
773 return 0;
774 }
775
776
777#ifdef INCLUDEMFC
778void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile)
779#else
780void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
781#endif
782 {
783 // initialize lex mode stack
784 lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
785
786 // iniatialize lex buffer.
787 lexBuf.inputString = (char*) inputstring;
788 lexBuf.inputLen = inputlen;
789 lexBuf.curPos = 0;
790 lexBuf.inputFile = inputfile;
791
792 lexBuf.len = 0;
793 lexBuf.getPtr = 0;
794
795 lexBuf.maxToken = MAXTOKEN;
796 lexBuf.strs = (char*)malloc(MAXTOKEN);
797 lexBuf.strsLen = 0;
798
799 }
800
801static void finiLex() {
802 free(lexBuf.strs);
803 }
804
805
806/*-----------------------------------*/
807/* This parses and converts the base64 format for binary encoding into
808 * a decoded buffer (allocated with new). See RFC 1521.
809 */
810static char * lexGetDataFromBase64()
811 {
812 unsigned long bytesLen = 0, bytesMax = 0;
813 int quadIx = 0, pad = 0;
814 unsigned long trip = 0;
815 unsigned char b;
816 int c;
817 unsigned char *bytes = NULL;
818 unsigned char *oldBytes = NULL;
819
820 DBG_(("db: lexGetDataFromBase64\n"));
821 while (1) {
822 c = lexGetc();
823 if (c == '\n') {
824 ++mime_lineNum;
825 if (lexLookahead() == '\n') {
826 /* a '\n' character by itself means end of data */
827 break;
828 }
829 else continue; /* ignore '\n' */
830 }
831 else {
832 if ((c >= 'A') && (c <= 'Z'))
833 b = (unsigned char)(c - 'A');
834 else if ((c >= 'a') && (c <= 'z'))
835 b = (unsigned char)(c - 'a') + 26;
836 else if ((c >= '0') && (c <= '9'))
837 b = (unsigned char)(c - '0') + 52;
838 else if (c == '+')
839 b = 62;
840 else if (c == '/')
841 b = 63;
842 else if (c == '=') {
843 b = 0;
844 pad++;
845 } else if ((c == ' ') || (c == '\t')) {
846 continue;
847 } else { /* error condition */
848 if (bytes) free(bytes);
849 else if (oldBytes) free(oldBytes);
850 // error recovery: skip until 2 adjacent newlines.
851 DBG_(("db: invalid character 0x%x '%c'\n", c,c));
852 if (c != EOF) {
853 c = lexGetc();
854 while (c != EOF) {
855 if (c == '\n' && lexLookahead() == '\n') {
856 ++mime_lineNum;
857 break;
858 }
859 c = lexGetc();
860 }
861 }
862 return NULL;
863 }
864 trip = (trip << 6) | b;
865 if (++quadIx == 4) {
866 unsigned char outBytes[3];
867 int numOut;
868 int i;
869 for (i = 0; i < 3; i++) {
870 outBytes[2-i] = (unsigned char)(trip & 0xFF);
871 trip >>= 8;
872 }
873 numOut = 3 - pad;
874 if (bytesLen + numOut > bytesMax) {
875 if (!bytes) {
876 bytesMax = 1024;
877 bytes = (unsigned char*)malloc((size_t)bytesMax);
878 }
879 else {
880 bytesMax <<= 2;
881 oldBytes = bytes;
882 bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
883 }
884 if (bytes == 0) {
885 mime_error("out of memory while processing BASE64 data\n");
886 }
887 }
888 if (bytes) {
889 memcpy(bytes + bytesLen, outBytes, numOut);
890 bytesLen += numOut;
891 }
892 trip = 0;
893 quadIx = 0;
894 }
895 }
896 } /* while */
897 DBG_(("db: bytesLen = %d\n", bytesLen));
898 /* kludge: all this won't be necessary if we have tree form
899 representation */
900 if (bytes) {
901 setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
902 free(bytes);
903 }
904 else if (oldBytes) {
905 setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
906 free(oldBytes);
907 }
908 return 0;
909 }
910
911static int match_begin_end_name(int end) {
912 int token;
913 lexSkipWhite();
914 if (lexLookahead() != ':') return ID;
915 lexSkipLookahead();
916 lexSkipWhite();
917 token = match_begin_name(end);
918 if (token == ID) {
919 lexPushLookaheadc(':');
920 DBG_(("db: ID '%s'\n", yylval.str));
921 return ID;
922 }
923 else if (token != 0) {
924 lexSkipLookaheadWord();
925 deleteStr(yylval.str);
926 DBG_(("db: begin/end %d\n", token));
927 return token;
928 }
929 return 0;
930 }
931
932static char* lexGetQuotedPrintable()
933 {
934 char cur;
935
936 lexClearToken();
937 do {
938 cur = lexGetc();
939 switch (cur) {
940 case '=': {
941 int c = 0;
942 int next[2];
943 int i;
944 for (i = 0; i < 2; i++) {
945 next[i] = lexGetc();
946 if (next[i] >= '0' && next[i] <= '9')
947 c = c * 16 + next[i] - '0';
948 else if (next[i] >= 'A' && next[i] <= 'F')
949 c = c * 16 + next[i] - 'A' + 10;
950 else
951 break;
952 }
953 if (i == 0) {
954 /* single '=' follow by LINESEP is continuation sign? */
955 if (next[0] == '\n') {
956 ++mime_lineNum;
957 }
958 else {
959 lexPushLookaheadc('=');
960 goto EndString;
961 }
962 }
963 else if (i == 1) {
964 lexPushLookaheadc(next[1]);
965 lexPushLookaheadc(next[0]);
966 lexAppendc('=');
967 } else {
968 lexAppendc(c);
969 }
970 break;
971 } /* '=' */
972 case '\n': {
973 lexPushLookaheadc('\n');
974 goto EndString;
975 }
976 case (char)EOF:
977 break;
978 default:
979 lexAppendc(cur);
980 break;
981 } /* switch */
982 } while (cur != (char)EOF);
983
984EndString:
985 lexAppendc(0);
986 return lexStr();
987 } /* LexQuotedPrintable */
988
989static int yylex() {
990
991 int lexmode = LEXMODE();
992 if (lexmode == L_VALUES) {
993 int c = lexGetc();
994 if (c == ';') {
995 DBG_(("db: SEMICOLON\n"));
996 lexPushLookaheadc(c);
997 handleMoreRFC822LineBreak(c);
998 lexSkipLookahead();
999 return SEMICOLON;
1000 }
1001 else if (strchr("\n",c)) {
1002 ++mime_lineNum;
1003 /* consume all line separator(s) adjacent to each other */
1004 c = lexLookahead();
1005 while (strchr("\n",c)) {
1006 lexSkipLookahead();
1007 c = lexLookahead();
1008 ++mime_lineNum;
1009 }
1010 DBG_(("db: LINESEP\n"));
1011 return LINESEP;
1012 }
1013 else {
1014 char *p = 0;
1015 lexPushLookaheadc(c);
1016 if (lexWithinMode(L_BASE64)) {
1017 /* get each char and convert to bin on the fly... */
1018 p = lexGetDataFromBase64();
1019 yylval.str = p;
1020 return STRING;
1021 }
1022 else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
1023 p = lexGetQuotedPrintable();
1024 }
1025 else {
1026#ifdef _SUPPORT_LINE_FOLDING
1027 p = lexGet1Value();
1028#else
1029 p = lexGetStrUntil(";\n");
1030#endif
1031 }
1032 if (p) {
1033 DBG_(("db: STRING: '%s'\n", p));
1034 yylval.str = p;
1035 return STRING;
1036 }
1037 else return 0;
1038 }
1039 }
1040 else {
1041 /* normal mode */
1042 while (1) {
1043 int c = lexGetc();
1044 switch(c) {
1045 case ':': {
1046 /* consume all line separator(s) adjacent to each other */
1047 /* ignoring linesep immediately after colon. */
1048 c = lexLookahead();
1049 while (strchr("\n",c)) {
1050 lexSkipLookahead();
1051 c = lexLookahead();
1052 ++mime_lineNum;
1053 }
1054 DBG_(("db: COLON\n"));
1055 return COLON;
1056 }
1057 case ';':
1058 DBG_(("db: SEMICOLON\n"));
1059 return SEMICOLON;
1060 case '=':
1061 DBG_(("db: EQ\n"));
1062 return EQ;
1063 /* ignore whitespace in this mode */
1064 case '\t':
1065 case ' ': continue;
1066 case '\n': {
1067 ++mime_lineNum;
1068 continue;
1069 }
1070 case EOF: return 0;
1071 break;
1072 default: {
1073 lexPushLookaheadc(c);
1074 if (isalnum(c)) {
1075 char *t = lexGetWord();
1076 yylval.str = t;
1077 if (!qstricmp(t, "begin")) {
1078 return match_begin_end_name(0);
1079 }
1080 else if (!qstricmp(t,"end")) {
1081 return match_begin_end_name(1);
1082 }
1083 else {
1084 DBG_(("db: ID '%s'\n", t));
1085 return ID;
1086 }
1087 }
1088 else {
1089 /* unknow token */
1090 return 0;
1091 }
1092 break;
1093 }
1094 }
1095 }
1096 }
1097 return 0;
1098 }
1099
1100
1101/***************************************************************************/
1102 /*** Public Functions ****/
1103/***************************************************************************/
1104
1105static VObject* Parse_MIMEHelper()
1106 {
1107 ObjStackTop = -1;
1108 mime_numErrors = 0;
1109 mime_lineNum = 1;
1110 vObjList = 0;
1111 curObj = 0;
1112
1113 if (yyparse() != 0)
1114 return 0;
1115
1116 finiLex();
1117 return vObjList;
1118 }
1119
1120/*--------------------------------------------*/
1121DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len)
1122 {
1123 initLex(input, len, 0);
1124 return Parse_MIMEHelper();
1125 }
1126
1127
1128#if INCLUDEMFC
1129
1130DLLEXPORT(VObject*) Parse_MIME_FromFile(CFile *file)
1131 {
1132 unsigned long startPos;
1133 VObject *result;
1134
1135 initLex(0,-1,file);
1136 startPos = file->GetPosition();
1137 if (!(result = Parse_MIMEHelper()))
1138 file->Seek(startPos, CFile::begin);
1139 return result;
1140 }
1141
1142#else
1143
1144VObject* Parse_MIME_FromFile(FILE *file)
1145 {
1146 VObject *result;
1147 long startPos;
1148
1149 initLex(0,(unsigned long)-1,file);
1150 startPos = ftell(file);
1151 if (!(result = Parse_MIMEHelper())) {
1152 fseek(file,startPos,SEEK_SET);
1153 }
1154 return result;
1155 }
1156
1157DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname)
1158 {
1159 FILE *fp = fopen(fname,"r");
1160 if (fp) {
1161 VObject* o = Parse_MIME_FromFile(fp);
1162 fclose(fp);
1163 return o;
1164 }
1165 else {
1166 char msg[80];
1167 sprintf(msg, "can't open file '%s' for reading\n", fname);
1168 mime_error_(msg);
1169 return 0;
1170 }
1171 }
1172
1173#endif
1174
1175/*-------------------------------------*/
1176
1177static MimeErrorHandler mimeErrorHandler;
1178
1179DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me)
1180 {
1181 mimeErrorHandler = me;
1182 }
1183
1184void mime_error(char *s)
1185 {
1186 char msg[256];
1187 if (mimeErrorHandler) {
1188 sprintf(msg,"%s at line %d", s, mime_lineNum);
1189 mimeErrorHandler(msg);
1190 }
1191 }
1192
1193void mime_error_(char *s)
1194 {
1195 if (mimeErrorHandler) {
1196 mimeErrorHandler(s);
1197 }
1198 }
1199
diff --git a/library/backend/vobject.cpp b/library/backend/vobject.cpp
new file mode 100644
index 0000000..af112a7
--- a/dev/null
+++ b/library/backend/vobject.cpp
@@ -0,0 +1,1210 @@
1/***************************************************************************
2(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
3Business Machines Corporation and Siemens Rolm Communications Inc.
4
5For purposes of this license notice, the term Licensors shall mean,
6collectively, Apple Computer, Inc., AT&T Corp., International
7Business Machines Corporation and Siemens Rolm Communications Inc.
8The term Licensor shall mean any of the Licensors.
9
10Subject to acceptance of the following conditions, permission is hereby
11granted by Licensors without the need for written agreement and without
12license or royalty fees, to use, copy, modify and distribute this
13software for any purpose.
14
15The above copyright notice and the following four paragraphs must be
16reproduced in all copies of this software and any software including
17this software.
18
19THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
20ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
21MODIFICATIONS.
22
23IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
24INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
25OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26DAMAGE.
27
28EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
29INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
30IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31PURPOSE.
32
33The software is provided with RESTRICTED RIGHTS. Use, duplication, or
34disclosure by the government are subject to restrictions set forth in
35DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
36
37***************************************************************************/
38
39/*
40 * src: vobject.c
41 * doc: vobject and APIs to construct vobject, APIs pretty print
42 * vobject, and convert a vobject into its textual representation.
43 */
44
45 #ifndef MWERKS
46#include <malloc.h>
47#endif
48
49#include "vobject_p.h"
50#include "qfiledirect_p.h"
51#include <string.h>
52#include <stdio.h>
53#include <fcntl.h>
54//#include <io.h>
55
56
57 #define NAME_OF(o) o->id
58 #define VALUE_TYPE(o) o->valType
59 #define STRINGZ_VALUE_OF(o) o->val.strs
60 #define INTEGER_VALUE_OF(o) o->val.i
61 #define LONG_VALUE_OF(o) o->val.l
62 #define ANY_VALUE_OF(o) o->val.any
63 #define VOBJECT_VALUE_OF(o) o->val.vobj
64
65typedef union ValueItem {
66 const char *strs;
67 unsigned int i;
68 unsigned long l;
69 void *any;
70 VObject *vobj;
71 } ValueItem;
72
73struct VObject {
74 VObject *next;
75 const char *id;
76 VObject *prop;
77 unsigned short valType;
78 ValueItem val;
79 };
80
81typedef struct StrItem StrItem;
82
83struct StrItem {
84 StrItem *next;
85 const char *s;
86 unsigned int refCnt;
87 };
88
89const char** fieldedProp;
90
91
92
93/*----------------------------------------------------------------------
94 The following functions involve with memory allocation:
95 newVObject
96 deleteVObject
97 dupStr
98 deleteStr
99 newStrItem
100 deleteStrItem
101 ----------------------------------------------------------------------*/
102
103DLLEXPORT(VObject*) newVObject_(const char *id)
104{
105 VObject *p = (VObject*)malloc(sizeof(VObject));
106 p->next = 0;
107 p->id = id;
108 p->prop = 0;
109 VALUE_TYPE(p) = 0;
110 ANY_VALUE_OF(p) = 0;
111 return p;
112}
113
114DLLEXPORT(VObject*) newVObject(const char *id)
115{
116 return newVObject_(lookupStr(id));
117}
118
119DLLEXPORT(void) deleteVObject(VObject *p)
120{
121 unUseStr(p->id);
122 free(p);
123}
124
125DLLEXPORT(char*) dupStr(const char *s, unsigned int size)
126{
127 char *t;
128 if (size == 0) {
129 size = strlen(s);
130 }
131 t = (char*)malloc(size+1);
132 if (t) {
133 memcpy(t,s,size);
134 t[size] = 0;
135 return t;
136 }
137 else {
138 return (char*)0;
139 }
140}
141
142DLLEXPORT(void) deleteStr(const char *p)
143{
144 if (p) free((void*)p);
145}
146
147
148static StrItem* newStrItem(const char *s, StrItem *next)
149{
150 StrItem *p = (StrItem*)malloc(sizeof(StrItem));
151 p->next = next;
152 p->s = s;
153 p->refCnt = 1;
154 return p;
155}
156
157static void deleteStrItem(StrItem *p)
158{
159 free((void*)p);
160}
161
162
163/*----------------------------------------------------------------------
164 The following function provide accesses to VObject's value.
165 ----------------------------------------------------------------------*/
166
167DLLEXPORT(const char*) vObjectName(VObject *o)
168{
169 return NAME_OF(o);
170}
171
172DLLEXPORT(void) setVObjectName(VObject *o, const char* id)
173{
174 NAME_OF(o) = id;
175}
176
177DLLEXPORT(const char*) vObjectStringZValue(VObject *o)
178{
179 return STRINGZ_VALUE_OF(o);
180}
181
182DLLEXPORT(void) setVObjectStringZValue(VObject *o, const char *s)
183{
184 STRINGZ_VALUE_OF(o) = dupStr(s,0);
185 VALUE_TYPE(o) = VCVT_STRINGZ;
186}
187
188DLLEXPORT(void) setVObjectStringZValue_(VObject *o, const char *s)
189{
190 STRINGZ_VALUE_OF(o) = s;
191 VALUE_TYPE(o) = VCVT_STRINGZ;
192}
193
194DLLEXPORT(unsigned int) vObjectIntegerValue(VObject *o)
195{
196 return INTEGER_VALUE_OF(o);
197}
198
199DLLEXPORT(void) setVObjectIntegerValue(VObject *o, unsigned int i)
200{
201 INTEGER_VALUE_OF(o) = i;
202 VALUE_TYPE(o) = VCVT_UINT;
203}
204
205DLLEXPORT(unsigned long) vObjectLongValue(VObject *o)
206{
207 return LONG_VALUE_OF(o);
208}
209
210DLLEXPORT(void) setVObjectLongValue(VObject *o, unsigned long l)
211{
212 LONG_VALUE_OF(o) = l;
213 VALUE_TYPE(o) = VCVT_ULONG;
214}
215
216DLLEXPORT(void*) vObjectAnyValue(VObject *o)
217{
218 return ANY_VALUE_OF(o);
219}
220
221DLLEXPORT(void) setVObjectAnyValue(VObject *o, void *t)
222{
223 ANY_VALUE_OF(o) = t;
224 VALUE_TYPE(o) = VCVT_RAW;
225}
226
227DLLEXPORT(VObject*) vObjectVObjectValue(VObject *o)
228{
229 return VOBJECT_VALUE_OF(o);
230}
231
232DLLEXPORT(void) setVObjectVObjectValue(VObject *o, VObject *p)
233{
234 VOBJECT_VALUE_OF(o) = p;
235 VALUE_TYPE(o) = VCVT_VOBJECT;
236}
237
238DLLEXPORT(int) vObjectValueType(VObject *o)
239{
240 return VALUE_TYPE(o);
241}
242
243
244/*----------------------------------------------------------------------
245 The following functions can be used to build VObject.
246 ----------------------------------------------------------------------*/
247
248DLLEXPORT(VObject*) addVObjectProp(VObject *o, VObject *p)
249{
250 /* circular link list pointed to tail */
251 /*
252 o {next,id,prop,val}
253 V
254 pn {next,id,prop,val}
255 V
256 ...
257 p1 {next,id,prop,val}
258 V
259 pn
260 -->
261 o {next,id,prop,val}
262 V
263 pn {next,id,prop,val}
264 V
265 p {next,id,prop,val}
266 ...
267 p1 {next,id,prop,val}
268 V
269 pn
270 */
271
272 VObject *tail = o->prop;
273 if (tail) {
274 p->next = tail->next;
275 o->prop = tail->next = p;
276 }
277 else {
278 o->prop = p->next = p;
279 }
280 return p;
281}
282
283DLLEXPORT(VObject*) addProp(VObject *o, const char *id)
284{
285 return addVObjectProp(o,newVObject(id));
286}
287
288DLLEXPORT(VObject*) addProp_(VObject *o, const char *id)
289{
290 return addVObjectProp(o,newVObject_(id));
291}
292
293DLLEXPORT(void) addList(VObject **o, VObject *p)
294{
295 p->next = 0;
296 if (*o == 0) {
297 *o = p;
298 }
299 else {
300 VObject *t = *o;
301 while (t->next) {
302 t = t->next;
303 }
304 t->next = p;
305 }
306}
307
308DLLEXPORT(VObject*) nextVObjectInList(VObject *o)
309{
310 return o->next;
311}
312
313DLLEXPORT(VObject*) setValueWithSize_(VObject *prop, void *val, unsigned int size)
314{
315 VObject *sizeProp;
316 setVObjectAnyValue(prop, val);
317 sizeProp = addProp(prop,VCDataSizeProp);
318 setVObjectLongValue(sizeProp, size);
319 return prop;
320}
321
322DLLEXPORT(VObject*) setValueWithSize(VObject *prop, void *val, unsigned int size)
323{
324 void *p = dupStr((const char *)val,size);
325 return setValueWithSize_(prop,p,p?size:0);
326}
327
328DLLEXPORT(void) initPropIterator(VObjectIterator *i, VObject *o)
329{
330 i->start = o->prop;
331 i->next = 0;
332}
333
334DLLEXPORT(void) initVObjectIterator(VObjectIterator *i, VObject *o)
335{
336 i->start = o->next;
337 i->next = 0;
338}
339
340DLLEXPORT(int) moreIteration(VObjectIterator *i)
341{
342 return (i->start && (i->next==0 || i->next!=i->start));
343}
344
345DLLEXPORT(VObject*) nextVObject(VObjectIterator *i)
346{
347 if (i->start && i->next != i->start) {
348 if (i->next == 0) {
349 i->next = i->start->next;
350 return i->next;
351 }
352 else {
353 i->next = i->next->next;
354 return i->next;
355 }
356 }
357 else return (VObject*)0;
358}
359
360DLLEXPORT(VObject*) isAPropertyOf(VObject *o, const char *id)
361{
362 VObjectIterator i;
363 initPropIterator(&i,o);
364 while (moreIteration(&i)) {
365 VObject *each = nextVObject(&i);
366 if (!qstricmp(id,each->id))
367 return each;
368 }
369 return (VObject*)0;
370}
371
372DLLEXPORT(VObject*) addGroup(VObject *o, const char *g)
373{
374 /*
375 a.b.c
376 -->
377 prop(c)
378 prop(VCGrouping=b)
379 prop(VCGrouping=a)
380 */
381 char *dot = strrchr(g,'.');
382 if (dot) {
383 VObject *p, *t;
384 char *gs, *n = dot+1;
385 gs = dupStr(g,0);/* so we can write to it. */
386 /* used to be
387 * t = p = addProp_(o,lookupProp_(n));
388 */
389 t = p = addProp_(o,lookupProp(n));
390 dot = strrchr(gs,'.');
391 *dot = 0;
392 do {
393 dot = strrchr(gs,'.');
394 if (dot) {
395 n = dot+1;
396 *dot=0;
397 }
398 else
399 n = gs;
400 /* property(VCGroupingProp=n);
401 *and the value may have VCGrouping property
402 */
403 t = addProp(t,VCGroupingProp);
404 setVObjectStringZValue(t,lookupProp_(n));
405 } while (n != gs);
406 deleteStr(gs);
407 return p;
408 }
409 else
410 return addProp_(o,lookupProp(g));
411}
412
413DLLEXPORT(VObject*) addPropValue(VObject *o, const char *p, const char *v)
414{
415 VObject *prop;
416 prop = addProp(o,p);
417 setVObjectStringZValue_(prop, strdup( v ) );
418 return prop;
419}
420
421DLLEXPORT(VObject*) addPropSizedValue_(VObject *o, const char *p, const char *v,
422 unsigned int size)
423{
424 VObject *prop;
425 prop = addProp(o,p);
426 setValueWithSize_(prop, (void*)v, size);
427 return prop;
428}
429
430DLLEXPORT(VObject*) addPropSizedValue(VObject *o, const char *p, const char *v,
431 unsigned int size)
432{
433 return addPropSizedValue_(o,p,dupStr(v,size),size);
434}
435
436
437DLLEXPORT(void) cleanVObject(VObject *o)
438{
439 if (o == 0) return;
440 if (o->prop) {
441 /* destroy time: cannot use the iterator here.
442 Have to break the cycle in the circular link
443 list and turns it into regular NULL-terminated
444 list -- since at some point of destruction,
445 the reference entry for the iterator to work
446 will not longer be valid.
447 */
448 VObject *p;
449 p = o->prop->next;
450 o->prop->next = 0;
451 do {
452 VObject *t = p->next;
453 cleanVObject(p);
454 p = t;
455 } while (p);
456 }
457 switch (VALUE_TYPE(o)) {
458 case VCVT_STRINGZ:
459 case VCVT_RAW:
460 // assume they are all allocated by malloc.
461 free((char*)STRINGZ_VALUE_OF(o));
462 break;
463 case VCVT_VOBJECT:
464 cleanVObject(VOBJECT_VALUE_OF(o));
465 break;
466 }
467 deleteVObject(o);
468}
469
470DLLEXPORT(void) cleanVObjects(VObject *list)
471{
472 while (list) {
473 VObject *t = list;
474 list = nextVObjectInList(list);
475 cleanVObject(t);
476 }
477}
478
479/*----------------------------------------------------------------------
480 The following is a String Table Facilities.
481 ----------------------------------------------------------------------*/
482
483#define STRTBLSIZE 255
484
485static StrItem *strTbl[STRTBLSIZE];
486
487static unsigned int hashStr(const char *s)
488{
489 unsigned int h = 0;
490 int i;
491 for (i=0;s[i];i++) {
492 h += s[i]*i;
493 }
494 return h % STRTBLSIZE;
495}
496
497DLLEXPORT(const char*) lookupStr(const char *s)
498{
499 StrItem *t;
500 unsigned int h = hashStr(s);
501 if ((t = strTbl[h]) != 0) {
502 do {
503 if (qstricmp(t->s,s) == 0) {
504 t->refCnt++;
505 return t->s;
506 }
507 t = t->next;
508 } while (t);
509 }
510 s = dupStr(s,0);
511 strTbl[h] = newStrItem(s,strTbl[h]);
512 return s;
513}
514
515DLLEXPORT(void) unUseStr(const char *s)
516{
517 StrItem *t, *p;
518 unsigned int h = hashStr(s);
519 if ((t = strTbl[h]) != 0) {
520 p = t;
521 do {
522 if (qstricmp(t->s,s) == 0) {
523 t->refCnt--;
524 if (t->refCnt == 0) {
525 if (p == strTbl[h]) {
526 strTbl[h] = t->next;
527 }
528 else {
529 p->next = t->next;
530 }
531 deleteStr(t->s);
532 deleteStrItem(t);
533 return;
534 }
535 }
536 p = t;
537 t = t->next;
538 } while (t);
539 }
540}
541
542DLLEXPORT(void) cleanStrTbl()
543{
544 int i;
545 for (i=0; i<STRTBLSIZE;i++) {
546 StrItem *t = strTbl[i];
547 while (t) {
548 StrItem *p;
549 deleteStr(t->s);
550 p = t;
551 t = t->next;
552 deleteStrItem(p);
553 } while (t);
554 strTbl[i] = 0;
555 }
556}
557
558
559struct PreDefProp {
560 const char *name;
561 const char *alias;
562 const char** fields;
563 unsigned int flags;
564 };
565
566/* flags in PreDefProp */
567 #define PD_BEGIN0x1
568 #define PD_INTERNAL0x2
569
570static const char *adrFields[] = {
571 VCPostalBoxProp,
572 VCExtAddressProp,
573 VCStreetAddressProp,
574 VCCityProp,
575 VCRegionProp,
576 VCPostalCodeProp,
577 VCCountryNameProp,
578 0
579};
580
581static const char *nameFields[] = {
582 VCFamilyNameProp,
583 VCGivenNameProp,
584 VCAdditionalNamesProp,
585 VCNamePrefixesProp,
586 VCNameSuffixesProp,
587 NULL
588 };
589
590static const char *orgFields[] = {
591 VCOrgNameProp,
592 VCOrgUnitProp,
593 VCOrgUnit2Prop,
594 VCOrgUnit3Prop,
595 VCOrgUnit4Prop,
596 NULL
597 };
598
599static const char *AAlarmFields[] = {
600 VCRunTimeProp,
601 VCSnoozeTimeProp,
602 VCRepeatCountProp,
603 VCAudioContentProp,
604 0
605 };
606
607/* ExDate -- has unamed fields */
608/* RDate -- has unamed fields */
609
610static const char *DAlarmFields[] = {
611 VCRunTimeProp,
612 VCSnoozeTimeProp,
613 VCRepeatCountProp,
614 VCDisplayStringProp,
615 0
616 };
617
618static const char *MAlarmFields[] = {
619 VCRunTimeProp,
620 VCSnoozeTimeProp,
621 VCRepeatCountProp,
622 VCEmailAddressProp,
623 VCNoteProp,
624 0
625 };
626
627static const char *PAlarmFields[] = {
628 VCRunTimeProp,
629 VCSnoozeTimeProp,
630 VCRepeatCountProp,
631 VCProcedureNameProp,
632 0
633 };
634
635static struct PreDefProp propNames[] = {
636 { VC7bitProp, 0, 0, 0 },
637 { VC8bitProp, 0, 0, 0 },
638 { VCAAlarmProp, 0, AAlarmFields, 0 },
639 { VCAdditionalNamesProp, 0, 0, 0 },
640 { VCAdrProp, 0, adrFields, 0 },
641 { VCAgentProp, 0, 0, 0 },
642 { VCAIFFProp, 0, 0, 0 },
643 { VCAOLProp, 0, 0, 0 },
644 { VCAppleLinkProp, 0, 0, 0 },
645 { VCAttachProp, 0, 0, 0 },
646 { VCAttendeeProp, 0, 0, 0 },
647 { VCATTMailProp, 0, 0, 0 },
648 { VCAudioContentProp, 0, 0, 0 },
649 { VCAVIProp, 0, 0, 0 },
650 { VCBase64Prop, 0, 0, 0 },
651 { VCBBSProp, 0, 0, 0 },
652 { VCBirthDateProp, 0, 0, 0 },
653 { VCBMPProp, 0, 0, 0 },
654 { VCBodyProp, 0, 0, 0 },
655 { VCBusinessRoleProp, 0, 0, 0 },
656 { VCCalProp, 0, 0, PD_BEGIN },
657 { VCCaptionProp, 0, 0, 0 },
658 { VCCardProp, 0, 0, PD_BEGIN },
659 { VCCarProp, 0, 0, 0 },
660 { VCCategoriesProp, 0, 0, 0 },
661 { VCCellularProp, 0, 0, 0 },
662 { VCCGMProp, 0, 0, 0 },
663 { VCCharSetProp, 0, 0, 0 },
664 { VCCIDProp, VCContentIDProp, 0, 0 },
665 { VCCISProp, 0, 0, 0 },
666 { VCCityProp, 0, 0, 0 },
667 { VCClassProp, 0, 0, 0 },
668 { VCCommentProp, 0, 0, 0 },
669 { VCCompletedProp, 0, 0, 0 },
670 { VCContentIDProp, 0, 0, 0 },
671 { VCCountryNameProp, 0, 0, 0 },
672 { VCDAlarmProp, 0, DAlarmFields, 0 },
673 { VCDataSizeProp, 0, 0, PD_INTERNAL },
674 { VCDayLightProp, 0, 0, 0 },
675 { VCDCreatedProp, 0, 0, 0 },
676 { VCDeliveryLabelProp, 0, 0, 0 },
677 { VCDescriptionProp, 0, 0, 0 },
678 { VCDIBProp, 0, 0, 0 },
679 { VCDisplayStringProp, 0, 0, 0 },
680 { VCDomesticProp, 0, 0, 0 },
681 { VCDTendProp, 0, 0, 0 },
682 { VCDTstartProp, 0, 0, 0 },
683 { VCDueProp, 0, 0, 0 },
684 { VCEmailAddressProp, 0, 0, 0 },
685 { VCEncodingProp, 0, 0, 0 },
686 { VCEndProp, 0, 0, 0 },
687 { VCEventProp, 0, 0, PD_BEGIN },
688 { VCEWorldProp, 0, 0, 0 },
689 { VCExNumProp, 0, 0, 0 },
690 { VCExpDateProp, 0, 0, 0 },
691 { VCExpectProp, 0, 0, 0 },
692 { VCExtAddressProp, 0, 0, 0 },
693 { VCFamilyNameProp, 0, 0, 0 },
694 { VCFaxProp, 0, 0, 0 },
695 { VCFullNameProp, 0, 0, 0 },
696 { VCGeoLocationProp, 0, 0, 0 },
697 { VCGeoProp, 0, 0, 0 },
698 { VCGIFProp, 0, 0, 0 },
699 { VCGivenNameProp, 0, 0, 0 },
700 { VCGroupingProp, 0, 0, 0 },
701 { VCHomeProp, 0, 0, 0 },
702 { VCIBMMailProp, 0, 0, 0 },
703 { VCInlineProp, 0, 0, 0 },
704 { VCInternationalProp, 0, 0, 0 },
705 { VCInternetProp, 0, 0, 0 },
706 { VCISDNProp, 0, 0, 0 },
707 { VCJPEGProp, 0, 0, 0 },
708 { VCLanguageProp, 0, 0, 0 },
709 { VCLastModifiedProp, 0, 0, 0 },
710 { VCLastRevisedProp, 0, 0, 0 },
711 { VCLocationProp, 0, 0, 0 },
712 { VCLogoProp, 0, 0, 0 },
713 { VCMailerProp, 0, 0, 0 },
714 { VCMAlarmProp, 0, MAlarmFields, 0 },
715 { VCMCIMailProp, 0, 0, 0 },
716 { VCMessageProp, 0, 0, 0 },
717 { VCMETProp, 0, 0, 0 },
718 { VCModemProp, 0, 0, 0 },
719 { VCMPEG2Prop, 0, 0, 0 },
720 { VCMPEGProp, 0, 0, 0 },
721 { VCMSNProp, 0, 0, 0 },
722 { VCNamePrefixesProp, 0, 0, 0 },
723 { VCNameProp, 0, nameFields, 0 },
724 { VCNameSuffixesProp, 0, 0, 0 },
725 { VCNoteProp, 0, 0, 0 },
726 { VCOrgNameProp, 0, 0, 0 },
727 { VCOrgProp, 0, orgFields, 0 },
728 { VCOrgUnit2Prop, 0, 0, 0 },
729 { VCOrgUnit3Prop, 0, 0, 0 },
730 { VCOrgUnit4Prop, 0, 0, 0 },
731 { VCOrgUnitProp, 0, 0, 0 },
732 { VCPagerProp, 0, 0, 0 },
733 { VCPAlarmProp, 0, PAlarmFields, 0 },
734 { VCParcelProp, 0, 0, 0 },
735 { VCPartProp, 0, 0, 0 },
736 { VCPCMProp, 0, 0, 0 },
737 { VCPDFProp, 0, 0, 0 },
738 { VCPGPProp, 0, 0, 0 },
739 { VCPhotoProp, 0, 0, 0 },
740 { VCPICTProp, 0, 0, 0 },
741 { VCPMBProp, 0, 0, 0 },
742 { VCPostalBoxProp, 0, 0, 0 },
743 { VCPostalCodeProp, 0, 0, 0 },
744 { VCPostalProp, 0, 0, 0 },
745 { VCPowerShareProp, 0, 0, 0 },
746 { VCPreferredProp, 0, 0, 0 },
747 { VCPriorityProp, 0, 0, 0 },
748 { VCProcedureNameProp, 0, 0, 0 },
749 { VCProdIdProp, 0, 0, 0 },
750 { VCProdigyProp, 0, 0, 0 },
751 { VCPronunciationProp, 0, 0, 0 },
752 { VCPSProp, 0, 0, 0 },
753 { VCPublicKeyProp, 0, 0, 0 },
754 { VCQPProp, VCQuotedPrintableProp, 0, 0 },
755 { VCQuickTimeProp, 0, 0, 0 },
756 { VCQuotedPrintableProp, 0, 0, 0 },
757 { VCRDateProp, 0, 0, 0 },
758 { VCRegionProp, 0, 0, 0 },
759 { VCRelatedToProp, 0, 0, 0 },
760 { VCRepeatCountProp, 0, 0, 0 },
761 { VCResourcesProp, 0, 0, 0 },
762 { VCRNumProp, 0, 0, 0 },
763 { VCRoleProp, 0, 0, 0 },
764 { VCRRuleProp, 0, 0, 0 },
765 { VCRSVPProp, 0, 0, 0 },
766 { VCRunTimeProp, 0, 0, 0 },
767 { VCSequenceProp, 0, 0, 0 },
768 { VCSnoozeTimeProp, 0, 0, 0 },
769 { VCStartProp, 0, 0, 0 },
770 { VCStatusProp, 0, 0, 0 },
771 { VCStreetAddressProp, 0, 0, 0 },
772 { VCSubTypeProp, 0, 0, 0 },
773 { VCSummaryProp, 0, 0, 0 },
774 { VCTelephoneProp, 0, 0, 0 },
775 { VCTIFFProp, 0, 0, 0 },
776 { VCTimeZoneProp, 0, 0, 0 },
777 { VCTitleProp, 0, 0, 0 },
778 { VCTLXProp, 0, 0, 0 },
779 { VCTodoProp, 0, 0, PD_BEGIN },
780 { VCTranspProp, 0, 0, 0 },
781 { VCUniqueStringProp, 0, 0, 0 },
782 { VCURLProp, 0, 0, 0 },
783 { VCURLValueProp, 0, 0, 0 },
784 { VCValueProp, 0, 0, 0 },
785 { VCVersionProp, 0, 0, 0 },
786 { VCVideoProp, 0, 0, 0 },
787 { VCVoiceProp, 0, 0, 0 },
788 { VCWAVEProp, 0, 0, 0 },
789 { VCWMFProp, 0, 0, 0 },
790 { VCWorkProp, 0, 0, 0 },
791 { VCX400Prop, 0, 0, 0 },
792 { VCX509Prop, 0, 0, 0 },
793 { VCXRuleProp, 0, 0, 0 },
794 { 0,0,0,0 }
795 };
796
797
798static struct PreDefProp* lookupPropInfo(const char* str)
799{
800 /* brute force for now, could use a hash table here. */
801 int i;
802
803 for (i = 0; propNames[i].name; i++)
804 if (qstricmp(str, propNames[i].name) == 0) {
805 return &propNames[i];
806 }
807
808 return 0;
809}
810
811
812DLLEXPORT(const char*) lookupProp_(const char* str)
813{
814 int i;
815
816 for (i = 0; propNames[i].name; i++)
817 if (qstricmp(str, propNames[i].name) == 0) {
818 const char* s;
819 s = propNames[i].alias?propNames[i].alias:propNames[i].name;
820 return lookupStr(s);
821 }
822 return lookupStr(str);
823}
824
825
826DLLEXPORT(const char*) lookupProp(const char* str)
827{
828 int i;
829
830 for (i = 0; propNames[i].name; i++)
831 if (qstricmp(str, propNames[i].name) == 0) {
832 const char *s;
833 fieldedProp = propNames[i].fields;
834 s = propNames[i].alias?propNames[i].alias:propNames[i].name;
835 return lookupStr(s);
836 }
837 fieldedProp = 0;
838 return lookupStr(str);
839}
840
841
842/*----------------------------------------------------------------------
843 APIs to Output text form.
844 ----------------------------------------------------------------------*/
845#define OFILE_REALLOC_SIZE 256
846typedef struct OFile {
847 FILE *fp;
848 char *s;
849 int len;
850 int limit;
851 int alloc:1;
852 int fail:1;
853 } OFile;
854
855#if 0
856static void appendsOFile(OFile *fp, const char *s)
857{
858 int slen;
859 if (fp->fail) return;
860 slen = strlen(s);
861 if (fp->fp) {
862 fwrite(s,1,slen,fp->fp);
863 }
864 else {
865stuff:
866 if (fp->len + slen < fp->limit) {
867 memcpy(fp->s+fp->len,s,slen);
868 fp->len += slen;
869 return;
870 }
871 else if (fp->alloc) {
872 fp->limit = fp->limit + OFILE_REALLOC_SIZE;
873 if (OFILE_REALLOC_SIZE <= slen) fp->limit += slen;
874 fp->s = (char *) realloc(fp->s,fp->limit);
875 if (fp->s) goto stuff;
876 }
877 if (fp->alloc)
878 free(fp->s);
879 fp->s = 0;
880 fp->fail = 1;
881 }
882}
883
884static void appendcOFile(OFile *fp, char c)
885{
886 if (fp->fail) return;
887 if (fp->fp) {
888 fputc(c,fp->fp);
889 }
890 else {
891stuff:
892 if (fp->len+1 < fp->limit) {
893 fp->s[fp->len] = c;
894 fp->len++;
895 return;
896 }
897 else if (fp->alloc) {
898 fp->limit = fp->limit + OFILE_REALLOC_SIZE;
899 fp->s = (char *) realloc(fp->s,fp->limit);
900 if (fp->s) goto stuff;
901 }
902 if (fp->alloc)
903 free(fp->s);
904 fp->s = 0;
905 fp->fail = 1;
906 }
907}
908#else
909static void appendcOFile_(OFile *fp, char c)
910{
911 if (fp->fail) return;
912 if (fp->fp) {
913 fputc(c,fp->fp);
914 }
915 else {
916stuff:
917 if (fp->len+1 < fp->limit) {
918 fp->s[fp->len] = c;
919 fp->len++;
920 return;
921 }
922 else if (fp->alloc) {
923 fp->limit = fp->limit + OFILE_REALLOC_SIZE;
924 fp->s = (char *)realloc(fp->s,fp->limit);
925 if (fp->s) goto stuff;
926 }
927 if (fp->alloc)
928 free(fp->s);
929 fp->s = 0;
930 fp->fail = 1;
931 }
932}
933
934static void appendcOFile(OFile *fp, char c)
935{
936 if (c == '\n') {
937 /* write out as <CR><LF> */
938 appendcOFile_(fp,0xd);
939 appendcOFile_(fp,0xa);
940 }
941 else
942 appendcOFile_(fp,c);
943}
944
945static void appendsOFile(OFile *fp, const char *s)
946{
947 int i, slen;
948 slen = strlen(s);
949 for (i=0; i<slen; i++) {
950 appendcOFile(fp,s[i]);
951 }
952}
953
954#endif
955
956static void initOFile(OFile *fp, FILE *ofp)
957{
958 fp->fp = ofp;
959 fp->s = 0;
960 fp->len = 0;
961 fp->limit = 0;
962 fp->alloc = 0;
963 fp->fail = 0;
964}
965
966static int writeBase64(OFile *fp, unsigned char *s, long len)
967{
968 long cur = 0;
969 int i, numQuads = 0;
970 unsigned long trip;
971 unsigned char b;
972 char quad[5];
973#define MAXQUADS 16
974
975 quad[4] = 0;
976
977 while (cur < len) {
978 // collect the triplet of bytes into 'trip'
979 trip = 0;
980 for (i = 0; i < 3; i++) {
981 b = (cur < len) ? *(s + cur) : 0;
982 cur++;
983 trip = trip << 8 | b;
984 }
985 // fill in 'quad' with the appropriate four characters
986 for (i = 3; i >= 0; i--) {
987 b = (unsigned char)(trip & 0x3F);
988 trip = trip >> 6;
989 if ((3 - i) < (cur - len))
990 quad[i] = '='; // pad char
991 else if (b < 26) quad[i] = (char)b + 'A';
992 else if (b < 52) quad[i] = (char)(b - 26) + 'a';
993 else if (b < 62) quad[i] = (char)(b - 52) + '0';
994 else if (b == 62) quad[i] = '+';
995 else quad[i] = '/';
996 }
997 // now output 'quad' with appropriate whitespace and line ending
998 appendsOFile(fp, (numQuads == 0 ? " " : ""));
999 appendsOFile(fp, quad);
1000 appendsOFile(fp, ((cur >= len)?"\n" :(numQuads==MAXQUADS-1?"\n" : "")));
1001 numQuads = (numQuads + 1) % MAXQUADS;
1002 }
1003 appendcOFile(fp,'\n');
1004
1005 return 1;
1006}
1007
1008static void writeQPString(OFile *fp, const char *s)
1009{
1010 const char *p = s;
1011 while (*p) {
1012 if (*p == '\n') {
1013 if (p[1]) appendsOFile(fp,"=0A=");
1014 }
1015 appendcOFile(fp,*p);
1016 p++;
1017 }
1018}
1019
1020
1021
1022static void writeVObject_(OFile *fp, VObject *o);
1023
1024static void writeValue(OFile *fp, VObject *o, unsigned long size)
1025{
1026 if (o == 0) return;
1027 switch (VALUE_TYPE(o)) {
1028 case VCVT_STRINGZ: {
1029 writeQPString(fp, STRINGZ_VALUE_OF(o));
1030 break;
1031 }
1032 case VCVT_UINT: {
1033 char buf[16];
1034 sprintf(buf,"%u", INTEGER_VALUE_OF(o));
1035 appendsOFile(fp,buf);
1036 break;
1037 }
1038 case VCVT_ULONG: {
1039 char buf[16];
1040 sprintf(buf,"%lu", LONG_VALUE_OF(o));
1041 appendsOFile(fp,buf);
1042 break;
1043 }
1044 case VCVT_RAW: {
1045 appendcOFile(fp,'\n');
1046 writeBase64(fp,(unsigned char*)(ANY_VALUE_OF(o)),size);
1047 break;
1048 }
1049 case VCVT_VOBJECT:
1050 appendcOFile(fp,'\n');
1051 writeVObject_(fp,VOBJECT_VALUE_OF(o));
1052 break;
1053 }
1054}
1055
1056static void writeAttrValue(OFile *fp, VObject *o)
1057{
1058 if (NAME_OF(o)) {
1059 struct PreDefProp *pi;
1060 pi = lookupPropInfo(NAME_OF(o));
1061 if (pi && ((pi->flags & PD_INTERNAL) != 0)) return;
1062 appendcOFile(fp,';');
1063 appendsOFile(fp,NAME_OF(o));
1064 }
1065 else
1066 appendcOFile(fp,';');
1067 if (VALUE_TYPE(o)) {
1068 appendcOFile(fp,'=');
1069 writeValue(fp,o,0);
1070 }
1071}
1072
1073static void writeGroup(OFile *fp, VObject *o)
1074{
1075 char buf1[256];
1076 char buf2[256];
1077 strcpy(buf1,NAME_OF(o));
1078 while ((o=isAPropertyOf(o,VCGroupingProp)) != 0) {
1079 strcpy(buf2,STRINGZ_VALUE_OF(o));
1080 strcat(buf2,".");
1081 strcat(buf2,buf1);
1082 strcpy(buf1,buf2);
1083 }
1084 appendsOFile(fp,buf1);
1085}
1086
1087static int inList(const char **list, const char *s)
1088{
1089 if (list == 0) return 0;
1090 while (*list) {
1091 if (qstricmp(*list,s) == 0) return 1;
1092 list++;
1093 }
1094 return 0;
1095}
1096
1097static void writeProp(OFile *fp, VObject *o)
1098{
1099 if (NAME_OF(o)) {
1100 struct PreDefProp *pi;
1101 VObjectIterator t;
1102 const char **fields_ = 0;
1103 pi = lookupPropInfo(NAME_OF(o));
1104 if (pi && ((pi->flags & PD_BEGIN) != 0)) {
1105 writeVObject_(fp,o);
1106 return;
1107 }
1108 if (isAPropertyOf(o,VCGroupingProp))
1109 writeGroup(fp,o);
1110 else
1111 appendsOFile(fp,NAME_OF(o));
1112 if (pi) fields_ = pi->fields;
1113 initPropIterator(&t,o);
1114 while (moreIteration(&t)) {
1115 const char *s;
1116 VObject *eachProp = nextVObject(&t);
1117 s = NAME_OF(eachProp);
1118 if (qstricmp(VCGroupingProp,s) && !inList(fields_,s))
1119 writeAttrValue(fp,eachProp);
1120 }
1121 if (fields_) {
1122 int i = 0, n = 0;
1123 const char** fields = fields_;
1124 /* output prop as fields */
1125 appendcOFile(fp,':');
1126 while (*fields) {
1127 VObject *t = isAPropertyOf(o,*fields);
1128 i++;
1129 if (t) n = i;
1130 fields++;
1131 }
1132 fields = fields_;
1133 for (i=0;i<n;i++) {
1134 writeValue(fp,isAPropertyOf(o,*fields),0);
1135 fields++;
1136 if (i<(n-1)) appendcOFile(fp,';');
1137 }
1138 }
1139 }
1140
1141 if (VALUE_TYPE(o)) {
1142 unsigned long size = 0;
1143 VObject *p = isAPropertyOf(o,VCDataSizeProp);
1144 if (p) size = LONG_VALUE_OF(p);
1145 appendcOFile(fp,':');
1146 writeValue(fp,o,size);
1147 }
1148
1149 appendcOFile(fp,'\n');
1150}
1151
1152static void writeVObject_(OFile *fp, VObject *o)
1153{
1154 if (NAME_OF(o)) {
1155 struct PreDefProp *pi;
1156 pi = lookupPropInfo(NAME_OF(o));
1157
1158 if (pi && ((pi->flags & PD_BEGIN) != 0)) {
1159 VObjectIterator t;
1160 const char *begin = NAME_OF(o);
1161 appendsOFile(fp,"BEGIN:");
1162 appendsOFile(fp,begin);
1163 appendcOFile(fp,'\n');
1164 initPropIterator(&t,o);
1165 while (moreIteration(&t)) {
1166 VObject *eachProp = nextVObject(&t);
1167 writeProp(fp, eachProp);
1168 }
1169 appendsOFile(fp,"END:");
1170 appendsOFile(fp,begin);
1171 appendsOFile(fp,"\n\n");
1172 }
1173 }
1174}
1175
1176void writeVObject(FILE *fp, VObject *o)
1177{
1178 OFile ofp;
1179 // #####
1180 //_setmode(_fileno(fp), _O_BINARY);
1181 initOFile(&ofp,fp);
1182 writeVObject_(&ofp,o);
1183}
1184
1185DLLEXPORT(void) writeVObjectToFile(char *fname, VObject *o)
1186{
1187 QFileDirect f( fname);
1188 if ( !f.open( IO_WriteOnly ) ) {
1189 qWarning("Unable to open vobject write %s", fname);
1190 return;
1191 }
1192
1193 writeVObject( f.directHandle(),o );
1194}
1195
1196DLLEXPORT(void) writeVObjectsToFile(char *fname, VObject *list)
1197{
1198 QFileDirect f( fname);
1199 if ( !f.open( IO_WriteOnly ) ) {
1200 qWarning("Unable to open vobject write %s", fname);
1201 return;
1202 }
1203
1204 while (list) {
1205 writeVObject(f.directHandle(),list);
1206 list = nextVObjectInList(list);
1207 }
1208}
1209
1210// end of source file vobject.c
diff --git a/library/backend/vobject_p.h b/library/backend/vobject_p.h
new file mode 100644
index 0000000..b6a2c0a
--- a/dev/null
+++ b/library/backend/vobject_p.h
@@ -0,0 +1,401 @@
1/***************************************************************************
2(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
3Business Machines Corporation and Siemens Rolm Communications Inc.
4
5For purposes of this license notice, the term Licensors shall mean,
6collectively, Apple Computer, Inc., AT&T Corp., International
7Business Machines Corporation and Siemens Rolm Communications Inc.
8The term Licensor shall mean any of the Licensors.
9
10Subject to acceptance of the following conditions, permission is hereby
11granted by Licensors without the need for written agreement and without
12license or royalty fees, to use, copy, modify and distribute this
13software for any purpose.
14
15The above copyright notice and the following four paragraphs must be
16reproduced in all copies of this software and any software including
17this software.
18
19THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
20ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
21MODIFICATIONS.
22
23IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
24INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
25OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26DAMAGE.
27
28EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
29INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
30IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31PURPOSE.
32
33The software is provided with RESTRICTED RIGHTS. Use, duplication, or
34disclosure by the government are subject to restrictions set forth in
35DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
36
37***************************************************************************/
38
39/*
40
41The vCard/vCalendar C interface is implemented in the set
42of files as follows:
43
44vcc.y, yacc source, and vcc.c, the yacc output you will use
45implements the core parser
46
47vobject.c implements an API that insulates the caller from
48the parser and changes in the vCard/vCalendar BNF
49
50port.h defines compilation environment dependent stuff
51
52vcc.h and vobject.h are header files for their .c counterparts
53
54vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions
55which you may find useful.
56
57test.c is a standalone test driver that exercises some of
58the features of the APIs provided. Invoke test.exe on a
59VCARD/VCALENDAR input text file and you will see the pretty
60print output of the internal representation (this pretty print
61output should give you a good idea of how the internal
62representation looks like -- there is one such output in the
63following too). Also, a file with the .out suffix is generated
64to show that the internal representation can be written back
65in the original text format.
66
67For more information on this API see the readme.txt file
68which accompanied this distribution.
69
70 Also visit:
71
72 http://www.versit.com
73 http://www.ralden.com
74
75*/
76
77
78#ifndef __VOBJECT_H__
79#define __VOBJECT_H__ 1
80
81#include <qstring.h>
82
83 #define vCardClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCard"
84 #define vCalendarClipboardFormat"+//ISBN 1-887687-00-9::versit::PDI//vCalendar"
85
86/* The above strings vCardClipboardFormat and vCalendarClipboardFormat
87are globally unique IDs which can be used to generate clipboard format
88ID's as per the requirements of a specific platform. For example, in
89Windows they are used as the parameter in a call to RegisterClipboardFormat.
90For example:
91
92 CLIPFORMAT foo = RegisterClipboardFormat(vCardClipboardFormat);
93
94*/
95
96 #define vCardMimeType "text/x-vCard"
97 #define vCalendarMimeType"text/x-vCalendar"
98
99#undef DLLEXPORT
100#include <qglobal.h>
101#if defined(Q_WS_WIN)
102#define DLLEXPORT(t) __declspec(dllexport) t
103#else
104#define DLLEXPORT(t) t
105#endif
106
107#ifndef FALSE
108 #define FALSE0
109#endif
110#ifndef TRUE
111 #define TRUE1
112#endif
113
114#include <stdlib.h>
115#include <stdio.h>
116
117
118 #define VC7bitProp "7BIT"
119 #define VC8bitProp "8BIT"
120 #define VCAAlarmProp "AALARM"
121 #define VCAdditionalNamesProp"ADDN"
122 #define VCAdrProp "ADR"
123 #define VCAgentProp "AGENT"
124 #define VCAIFFProp "AIFF"
125 #define VCAOLProp "AOL"
126 #define VCAppleLinkProp "APPLELINK"
127 #define VCAttachProp "ATTACH"
128 #define VCAttendeeProp "ATTENDEE"
129 #define VCATTMailProp "ATTMAIL"
130 #define VCAudioContentProp "AUDIOCONTENT"
131 #define VCAVIProp "AVI"
132 #define VCBase64Prop "BASE64"
133 #define VCBBSProp "BBS"
134 #define VCBirthDateProp "BDAY"
135 #define VCBMPProp "BMP"
136 #define VCBodyProp "BODY"
137 #define VCBusinessRoleProp "ROLE"
138 #define VCCalProp "VCALENDAR"
139 #define VCCaptionProp "CAP"
140 #define VCCardProp "VCARD"
141 #define VCCarProp "CAR"
142 #define VCCategoriesProp "CATEGORIES"
143 #define VCCellularProp "CELL"
144 #define VCCGMProp "CGM"
145 #define VCCharSetProp "CS"
146 #define VCCIDProp "CID"
147 #define VCCISProp "CIS"
148 #define VCCityProp "L"
149 #define VCClassProp "CLASS"
150 #define VCCommentProp "NOTE"
151 #define VCCompletedProp "COMPLETED"
152 #define VCContentIDProp "CONTENT-ID"
153 #define VCCountryNameProp "C"
154 #define VCDAlarmProp "DALARM"
155 #define VCDataSizeProp "DATASIZE"
156 #define VCDayLightProp "DAYLIGHT"
157 #define VCDCreatedProp "DCREATED"
158#define VCDeliveryLabelProp "LABEL"
159 #define VCDescriptionProp "DESCRIPTION"
160 #define VCDIBProp "DIB"
161 #define VCDisplayStringProp "DISPLAYSTRING"
162 #define VCDomesticProp "DOM"
163 #define VCDTendProp "DTEND"
164 #define VCDTstartProp "DTSTART"
165 #define VCDueProp "DUE"
166 #define VCEmailAddressProp "EMAIL"
167 #define VCEncodingProp "ENCODING"
168 #define VCEndProp "END"
169 #define VCEventProp "VEVENT"
170 #define VCEWorldProp "EWORLD"
171 #define VCExNumProp "EXNUM"
172 #define VCExpDateProp "EXDATE"
173 #define VCExpectProp "EXPECT"
174 #define VCExtAddressProp "EXT ADD"
175 #define VCFamilyNameProp "F"
176 #define VCFaxProp "FAX"
177 #define VCFullNameProp "FN"
178 #define VCGeoProp "GEO"
179 #define VCGeoLocationProp "GEO"
180 #define VCGIFProp "GIF"
181 #define VCGivenNameProp "G"
182 #define VCGroupingProp "Grouping"
183 #define VCHomeProp "HOME"
184 #define VCIBMMailProp "IBMMail"
185 #define VCInlineProp "INLINE"
186 #define VCInternationalProp "INTL"
187 #define VCInternetProp "INTERNET"
188 #define VCISDNProp "ISDN"
189 #define VCJPEGProp "JPEG"
190 #define VCLanguageProp "LANG"
191 #define VCLastModifiedProp "LAST-MODIFIED"
192 #define VCLastRevisedProp "REV"
193 #define VCLocationProp "LOCATION"
194 #define VCLogoProp "LOGO"
195 #define VCMailerProp "MAILER"
196 #define VCMAlarmProp "MALARM"
197 #define VCMCIMailProp "MCIMAIL"
198 #define VCMessageProp "MSG"
199 #define VCMETProp "MET"
200 #define VCModemProp "MODEM"
201 #define VCMPEG2Prop "MPEG2"
202 #define VCMPEGProp "MPEG"
203 #define VCMSNProp "MSN"
204 #define VCNamePrefixesProp "NPRE"
205 #define VCNameProp "N"
206 #define VCNameSuffixesProp "NSUF"
207 #define VCNoteProp "NOTE"
208 #define VCOrgNameProp "ORGNAME"
209 #define VCOrgProp "ORG"
210 #define VCOrgUnit2Prop "OUN2"
211 #define VCOrgUnit3Prop "OUN3"
212 #define VCOrgUnit4Prop "OUN4"
213 #define VCOrgUnitProp "OUN"
214 #define VCPagerProp "PAGER"
215 #define VCPAlarmProp "PALARM"
216 #define VCParcelProp "PARCEL"
217 #define VCPartProp "PART"
218 #define VCPCMProp "PCM"
219 #define VCPDFProp "PDF"
220 #define VCPGPProp "PGP"
221 #define VCPhotoProp "PHOTO"
222 #define VCPICTProp "PICT"
223 #define VCPMBProp "PMB"
224 #define VCPostalBoxProp "BOX"
225 #define VCPostalCodeProp "PC"
226 #define VCPostalProp "POSTAL"
227 #define VCPowerShareProp "POWERSHARE"
228 #define VCPreferredProp "PREF"
229 #define VCPriorityProp "PRIORITY"
230 #define VCProcedureNameProp "PROCEDURENAME"
231 #define VCProdIdProp "PRODID"
232 #define VCProdigyProp "PRODIGY"
233 #define VCPronunciationProp "SOUND"
234 #define VCPSProp "PS"
235 #define VCPublicKeyProp "KEY"
236 #define VCQPProp "QP"
237 #define VCQuickTimeProp "QTIME"
238 #define VCQuotedPrintableProp"QUOTED-PRINTABLE"
239 #define VCRDateProp "RDATE"
240 #define VCRegionProp "R"
241 #define VCRelatedToProp "RELATED-TO"
242 #define VCRepeatCountProp "REPEATCOUNT"
243 #define VCResourcesProp "RESOURCES"
244 #define VCRNumProp "RNUM"
245 #define VCRoleProp "ROLE"
246 #define VCRRuleProp "RRULE"
247 #define VCRSVPProp "RSVP"
248 #define VCRunTimeProp "RUNTIME"
249 #define VCSequenceProp "SEQUENCE"
250 #define VCSnoozeTimeProp "SNOOZETIME"
251 #define VCStartProp "START"
252 #define VCStatusProp "STATUS"
253 #define VCStreetAddressProp "STREET"
254 #define VCSubTypeProp "SUBTYPE"
255 #define VCSummaryProp "SUMMARY"
256 #define VCTelephoneProp "TEL"
257 #define VCTIFFProp "TIFF"
258 #define VCTimeZoneProp "TZ"
259 #define VCTitleProp "TITLE"
260 #define VCTLXProp "TLX"
261 #define VCTodoProp "VTODO"
262 #define VCTranspProp "TRANSP"
263 #define VCUniqueStringProp "UID"
264 #define VCURLProp "URL"
265 #define VCURLValueProp "URLVAL"
266 #define VCValueProp "VALUE"
267 #define VCVersionProp "VERSION"
268 #define VCVideoProp "VIDEO"
269 #define VCVoiceProp "VOICE"
270 #define VCWAVEProp "WAVE"
271 #define VCWMFProp "WMF"
272 #define VCWorkProp "WORK"
273 #define VCX400Prop "X400"
274 #define VCX509Prop "X509"
275 #define VCXRuleProp "XRULE"
276
277
278typedef struct VObject VObject;
279
280typedef struct VObjectIterator {
281 VObject* start;
282 VObject* next;
283 } VObjectIterator;
284
285extern DLLEXPORT(VObject*) newVObject(const char *id);
286extern DLLEXPORT(void) deleteVObject(VObject *p);
287extern DLLEXPORT(char*) dupStr(const char *s, unsigned int size);
288extern DLLEXPORT(void) deleteStr(const char *p);
289extern DLLEXPORT(void) unUseStr(const char *s);
290
291extern DLLEXPORT(void) setVObjectName(VObject *o, const char* id);
292extern DLLEXPORT(void) setVObjectStringZValue(VObject *o, const char *s);
293extern DLLEXPORT(void) setVObjectStringZValue_(VObject *o, const char *s);
294extern DLLEXPORT(void) setVObjectIntegerValue(VObject *o, unsigned int i);
295extern DLLEXPORT(void) setVObjectLongValue(VObject *o, unsigned long l);
296extern DLLEXPORT(void) setVObjectAnyValue(VObject *o, void *t);
297extern DLLEXPORT(VObject*) setValueWithSize(VObject *prop, void *val, unsigned int size);
298extern DLLEXPORT(VObject*) setValueWithSize_(VObject *prop, void *val, unsigned int size);
299
300extern DLLEXPORT(const char*) vObjectName(VObject *o);
301extern DLLEXPORT(const char*) vObjectStringZValue(VObject *o);
302extern DLLEXPORT(unsigned int) vObjectIntegerValue(VObject *o);
303extern DLLEXPORT(unsigned long) vObjectLongValue(VObject *o);
304extern DLLEXPORT(void*) vObjectAnyValue(VObject *o);
305extern DLLEXPORT(VObject*) vObjectVObjectValue(VObject *o);
306extern DLLEXPORT(void) setVObjectVObjectValue(VObject *o, VObject *p);
307
308extern DLLEXPORT(VObject*) addVObjectProp(VObject *o, VObject *p);
309extern DLLEXPORT(VObject*) addProp(VObject *o, const char *id);
310extern DLLEXPORT(VObject*) addProp_(VObject *o, const char *id);
311extern DLLEXPORT(VObject*) addPropValue(VObject *o, const char *p, const char *v);
312extern DLLEXPORT(VObject*) addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size);
313extern DLLEXPORT(VObject*) addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size);
314extern DLLEXPORT(VObject*) addGroup(VObject *o, const char *g);
315extern DLLEXPORT(void) addList(VObject **o, VObject *p);
316
317extern DLLEXPORT(VObject*) isAPropertyOf(VObject *o, const char *id);
318
319extern DLLEXPORT(VObject*) nextVObjectInList(VObject *o);
320extern DLLEXPORT(void) initPropIterator(VObjectIterator *i, VObject *o);
321extern DLLEXPORT(int) moreIteration(VObjectIterator *i);
322extern DLLEXPORT(VObject*) nextVObject(VObjectIterator *i);
323
324extern DLLEXPORT(const char*) lookupStr(const char *s);
325extern DLLEXPORT(void) cleanStrTbl();
326
327extern DLLEXPORT(void) cleanVObject(VObject *o);
328extern DLLEXPORT(void) cleanVObjects(VObject *list);
329
330extern DLLEXPORT(const char*) lookupProp(const char* str);
331extern DLLEXPORT(const char*) lookupProp_(const char* str);
332
333extern DLLEXPORT(void) writeVObjectToFile(char *fname, VObject *o);
334extern DLLEXPORT(void) writeVObjectsToFile(char *fname, VObject *list);
335
336extern DLLEXPORT(int) vObjectValueType(VObject *o);
337
338/* return type of vObjectValueType: */
339 #define VCVT_NOVALUE0
340 /* if the VObject has no value associated with it. */
341 #define VCVT_STRINGZ1
342 /* if the VObject has value set by setVObjectStringZValue. */
343 #define VCVT_UINT 2
344 /* if the VObject has value set by setVObjectIntegerValue. */
345 #define VCVT_ULONG 3
346 /* if the VObject has value set by setVObjectLongValue. */
347 #define VCVT_RAW 4
348 /* if the VObject has value set by setVObjectAnyValue. */
349 #define VCVT_VOBJECT5
350 /* if the VObject has value set by setVObjectVObjectValue. */
351
352extern const char** fieldedProp;
353
354/***************************************************
355 * The methods below are implemented in vcc.c (generated from vcc.y )
356 ***************************************************/
357
358/* NOTE regarding printVObject and writeVObject
359
360The functions below are not exported from the DLL because they
361take a FILE* as a parameter, which cannot be passed across a DLL
362interface (at least that is my experience). Instead you can use
363their companion functions which take file names or pointers
364to memory. However, if you are linking this code into
365your build directly then you may find them a more convenient API
366and you can go ahead and use them. If you try to use them with
367the DLL LIB you will get a link error.
368*/
369extern void writeVObject(FILE *fp, VObject *o);
370
371
372
373typedef void (*MimeErrorHandler)(char *);
374
375extern DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler);
376
377extern DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len);
378extern DLLEXPORT(VObject*) Parse_MIME_FromFileName(char* fname);
379
380
381/* NOTE regarding Parse_MIME_FromFile
382The function above, Parse_MIME_FromFile, comes in two flavors,
383neither of which is exported from the DLL. Each version takes
384a CFile or FILE* as a parameter, neither of which can be
385passed across a DLL interface (at least that is my experience).
386If you are linking this code into your build directly then
387you may find them a more convenient API that the other flavors
388that take a file name. If you use them with the DLL LIB you
389will get a link error.
390*/
391
392
393#if INCLUDEMFC
394extern VObject* Parse_MIME_FromFile(CFile *file);
395#else
396extern VObject* Parse_MIME_FromFile(FILE *file);
397#endif
398
399#endif /* __VOBJECT_H__ */
400
401