-rw-r--r-- | library/backend/.cvsignore | 2 | ||||
-rw-r--r-- | library/backend/categories.cpp | 701 | ||||
-rw-r--r-- | library/backend/categories.h | 232 | ||||
-rw-r--r-- | library/backend/contact.cpp | 909 | ||||
-rw-r--r-- | library/backend/contact.h | 217 | ||||
-rw-r--r-- | library/backend/event.cpp | 830 | ||||
-rw-r--r-- | library/backend/event.h | 229 | ||||
-rw-r--r-- | library/backend/palmtoprecord.cpp | 127 | ||||
-rw-r--r-- | library/backend/palmtoprecord.h | 94 | ||||
-rw-r--r-- | library/backend/palmtopuidgen.h | 83 | ||||
-rw-r--r-- | library/backend/qfiledirect_p.h | 36 | ||||
-rw-r--r-- | library/backend/qpcglobal.h | 50 | ||||
-rw-r--r-- | library/backend/recordfields.h | 135 | ||||
-rw-r--r-- | library/backend/stringutil.cpp | 415 | ||||
-rw-r--r-- | library/backend/stringutil.h | 57 | ||||
-rw-r--r-- | library/backend/task.cpp | 271 | ||||
-rw-r--r-- | library/backend/task.h | 77 | ||||
-rw-r--r-- | library/backend/timeconversion.cpp | 237 | ||||
-rw-r--r-- | library/backend/timeconversion.h | 45 | ||||
-rw-r--r-- | library/backend/vcc.y | 1199 | ||||
-rw-r--r-- | library/backend/vobject.cpp | 1210 | ||||
-rw-r--r-- | library/backend/vobject_p.h | 401 |
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 @@ | |||
1 | moc_* | ||
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 | |||
27 | using namespace Qtopia; | ||
28 | |||
29 | /*********************************************************** | ||
30 | * | ||
31 | * CategoryGroup | ||
32 | * | ||
33 | **********************************************************/ | ||
34 | |||
35 | #ifdef PALMTOPCENTER | ||
36 | UidGen CategoryGroup::sUidGen( UidGen::PalmtopCenter ); | ||
37 | #else | ||
38 | UidGen CategoryGroup::sUidGen( UidGen::Qtopia ); | ||
39 | #endif | ||
40 | |||
41 | int 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 | |||
54 | void CategoryGroup::insert( int uid, const QString &label ) | ||
55 | { | ||
56 | uidGen().store( uid ); | ||
57 | mIdLabelMap[uid] = label; | ||
58 | mLabelIdMap[label] = uid; | ||
59 | } | ||
60 | |||
61 | bool 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 | |||
76 | bool 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 | |||
88 | bool 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 | |||
100 | bool 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 | |||
116 | bool CategoryGroup::rename( const QString &oldLabel, const QString &newLabel ) | ||
117 | { | ||
118 | return rename( id(oldLabel), newLabel ); | ||
119 | } | ||
120 | |||
121 | bool CategoryGroup::contains(int uid) const | ||
122 | { | ||
123 | return ( mIdLabelMap.find( uid ) != mIdLabelMap.end() ); | ||
124 | } | ||
125 | |||
126 | bool 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 | */ | ||
134 | const 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 */ | ||
143 | int 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 | |||
151 | QStringList 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 | |||
162 | QStringList 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 | |||
174 | QArray<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 | |||
193 | QArray<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 | */ | ||
213 | int 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 | |||
237 | int 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 | |||
262 | int 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 | |||
269 | int 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 | */ | ||
282 | bool 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 | |||
301 | bool 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 | |||
315 | bool 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 | |||
326 | bool 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 | */ | ||
339 | QStringList 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 | |||
370 | QString 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 | |||
381 | QStringList 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 | */ | ||
394 | QString 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 | |||
420 | QArray<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 | |||
436 | QArray<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 | |||
449 | int 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 | */ | ||
463 | bool 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 | |||
481 | bool 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 | |||
492 | void 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 | |||
510 | bool 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 | */ | ||
518 | bool 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 | |||
530 | bool 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 | |||
542 | bool 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 | |||
576 | bool 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 | |||
646 | void Categories::clear() | ||
647 | { | ||
648 | mGlobalCats.clear(); | ||
649 | mAppCats.clear(); | ||
650 | } | ||
651 | |||
652 | void 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 | |||
664 | QStringList 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 | |||
674 | void 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 | |||
683 | void 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 | |||
33 | class CategoryGroup; | ||
34 | |||
35 | #if defined(QPC_TEMPLATEDLL) | ||
36 | // MOC_SKIP_BEGIN | ||
37 | template class QPC_EXPORT QMap<int, QString>; | ||
38 | template class QPC_EXPORT QMap<QString, int>; | ||
39 | template class QPC_EXPORT QMap< QString, CategoryGroup >; | ||
40 | // MOC_SKIP_END | ||
41 | #endif | ||
42 | |||
43 | class QPC_EXPORT CategoryGroup | ||
44 | { | ||
45 | friend class Categories; | ||
46 | public: | ||
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 | |||
80 | private: | ||
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 */ | ||
90 | class QPC_EXPORT Categories : public QObject | ||
91 | { | ||
92 | Q_OBJECT | ||
93 | public: | ||
94 | Categories( QObject *parent=0, const char *name = 0 ) | ||
95 | : QObject( parent, name ), mGlobalCats(), mAppCats() { } | ||
96 | Categories( const Categories ©From ) : 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 | |||
202 | signals: | ||
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 | |||
219 | private: | ||
220 | CategoryGroup mGlobalCats; | ||
221 | QMap< QString, CategoryGroup > mAppCats; | ||
222 | }; | ||
223 | |||
224 | class QPC_EXPORT CheckedListView : public QListView | ||
225 | { | ||
226 | public: | ||
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 | |||
35 | Qtopia::UidGen Contact::sUidGen( Qtopia::UidGen::Qtopia ); | ||
36 | |||
37 | Contact::Contact() | ||
38 | : Record(), mMap(), d( 0 ) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | Contact::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 | |||
55 | Contact::~Contact() | ||
56 | { | ||
57 | } | ||
58 | |||
59 | QMap<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 | */ | ||
69 | QString 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 | |||
232 | void 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 | |||
241 | void 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 | |||
250 | QString Contact::find( int key ) const | ||
251 | { | ||
252 | return mMap[key]; | ||
253 | } | ||
254 | |||
255 | QString 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 | |||
277 | QString Contact::displayBusinessAddress() const | ||
278 | { | ||
279 | return displayAddress( businessStreet(), businessCity(), | ||
280 | businessState(), businessZip(), | ||
281 | businessCountry() ); | ||
282 | } | ||
283 | |||
284 | QString Contact::displayHomeAddress() const | ||
285 | { | ||
286 | return displayAddress( homeStreet(), homeCity(), | ||
287 | homeState(), homeZip(), | ||
288 | homeCountry() ); | ||
289 | } | ||
290 | |||
291 | QString 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 | |||
323 | QStringList Contact::childrenList() const | ||
324 | { | ||
325 | return QStringList::split( " ", find( Qtopia::Children ) ); | ||
326 | } | ||
327 | |||
328 | QStringList Contact::emailList() const | ||
329 | { | ||
330 | return QStringList::split( ";", find( Qtopia::Emails ) ); | ||
331 | } | ||
332 | |||
333 | void 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 | |||
354 | void 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 | |||
378 | QStringList 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 | |||
432 | QStringList 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 | |||
486 | void Contact::setEmails( const QString &v ) | ||
487 | { | ||
488 | replace( Qtopia::Emails, v ); | ||
489 | if ( v.isEmpty() ) | ||
490 | setDefaultEmail( QString::null ); | ||
491 | } | ||
492 | |||
493 | void Contact::setChildren( const QString &v ) | ||
494 | { | ||
495 | replace( Qtopia::Children, v ); | ||
496 | } | ||
497 | |||
498 | // vcard conversion code | ||
499 | static 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 | |||
507 | static 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 | |||
515 | static 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 | |||
615 | static 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 | |||
844 | void 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 | |||
861 | void 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 | |||
877 | QValueList<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 | |||
897 | bool 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 | ||
31 | template class QPC_EXPORT QMap<int, QString>; | ||
32 | // MOC_SKIP_END | ||
33 | #endif | ||
34 | |||
35 | class ContactPrivate; | ||
36 | class QPC_EXPORT Contact : public Qtopia::Record | ||
37 | { | ||
38 | friend class DataSet; | ||
39 | public: | ||
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 | |||
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 | |||
199 | private: | ||
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 | |||
32 | using namespace Qtopia; | ||
33 | |||
34 | static 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 | |||
72 | Qtopia::UidGen Event::sUidGen( Qtopia::UidGen::Qtopia ); | ||
73 | |||
74 | Event::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 | |||
86 | Event::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 | |||
109 | Event::~Event() | ||
110 | { | ||
111 | } | ||
112 | |||
113 | int 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 | |||
127 | int 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 | |||
134 | int 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 | |||
145 | int Event::monthDiff( const QDate& first, const QDate& second ) | ||
146 | { | ||
147 | return ( second.year() - first.year() ) * 12 + | ||
148 | second.month() - first.month(); | ||
149 | } | ||
150 | |||
151 | QMap<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 | |||
177 | void Event::setRepeat( const RepeatPattern &p ) | ||
178 | { | ||
179 | setRepeat( p.type != NoRepeat, p ); | ||
180 | } | ||
181 | |||
182 | void Event::setDescription( const QString &s ) | ||
183 | { | ||
184 | descript = s; | ||
185 | } | ||
186 | |||
187 | void Event::setLocation( const QString &s ) | ||
188 | { | ||
189 | locat = s; | ||
190 | } | ||
191 | |||
192 | // void Event::setCategory( const QString &s ) | ||
193 | // { | ||
194 | // categ = s; | ||
195 | // } | ||
196 | |||
197 | void Event::setType( Type t ) | ||
198 | { | ||
199 | typ = t; | ||
200 | } | ||
201 | |||
202 | void Event::setStart( const QDateTime &d ) | ||
203 | { | ||
204 | startUTC = TimeConversion::toUTC( d ); | ||
205 | } | ||
206 | |||
207 | void Event::setStart( time_t time ) | ||
208 | { | ||
209 | startUTC = time; | ||
210 | } | ||
211 | |||
212 | void Event::setEnd( const QDateTime &d ) | ||
213 | { | ||
214 | endUTC = TimeConversion::toUTC( d ); | ||
215 | } | ||
216 | |||
217 | void Event::setEnd( time_t time ) | ||
218 | { | ||
219 | endUTC = time; | ||
220 | } | ||
221 | |||
222 | void Event::setTimeZone( const QString &z ) | ||
223 | { | ||
224 | tz = z; | ||
225 | } | ||
226 | |||
227 | void Event::setAlarm( bool b, int minutes, SoundTypeChoice s ) | ||
228 | { | ||
229 | hAlarm = b; | ||
230 | aMinutes = minutes; | ||
231 | aSound = s; | ||
232 | } | ||
233 | |||
234 | void Event::setRepeat( bool b, const RepeatPattern &p ) | ||
235 | { | ||
236 | hRepeat = b; | ||
237 | pattern = p; | ||
238 | } | ||
239 | |||
240 | void Event::setNotes( const QString &n ) | ||
241 | { | ||
242 | note = n; | ||
243 | } | ||
244 | |||
245 | const QString &Event::description() const | ||
246 | { | ||
247 | return descript; | ||
248 | } | ||
249 | |||
250 | const QString &Event::location() const | ||
251 | { | ||
252 | return locat; | ||
253 | } | ||
254 | |||
255 | // QString Event::category() const | ||
256 | // { | ||
257 | // return categ; | ||
258 | // } | ||
259 | |||
260 | Event::Type Event::type() const | ||
261 | { | ||
262 | return typ; | ||
263 | } | ||
264 | |||
265 | QDateTime 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 | |||
277 | QDateTime 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 | |||
289 | const QString &Event::timeZone() const | ||
290 | { | ||
291 | return tz; | ||
292 | } | ||
293 | |||
294 | bool Event::hasAlarm() const | ||
295 | { | ||
296 | return hAlarm; | ||
297 | } | ||
298 | |||
299 | int Event::alarmTime() const | ||
300 | { | ||
301 | return aMinutes; | ||
302 | } | ||
303 | |||
304 | Event::SoundTypeChoice Event::alarmSound() const | ||
305 | { | ||
306 | return aSound; | ||
307 | } | ||
308 | |||
309 | bool Event::hasRepeat() const | ||
310 | { | ||
311 | return doRepeat(); | ||
312 | } | ||
313 | |||
314 | const Event::RepeatPattern &Event::repeatPattern() const | ||
315 | { | ||
316 | return pattern; | ||
317 | } | ||
318 | |||
319 | Event::RepeatPattern &Event::repeatPattern() | ||
320 | { | ||
321 | return pattern; | ||
322 | } | ||
323 | |||
324 | const QString &Event::notes() const | ||
325 | { | ||
326 | return note; | ||
327 | } | ||
328 | |||
329 | bool 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 | |||
346 | void 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 | |||
381 | bool 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 | |||
394 | class EffectiveEventPrivate | ||
395 | { | ||
396 | public: | ||
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 | |||
404 | EffectiveEvent::EffectiveEvent() | ||
405 | { | ||
406 | mDate = QDate::currentDate(); | ||
407 | mStart = mEnd = QTime::currentTime(); | ||
408 | d = 0; | ||
409 | } | ||
410 | |||
411 | EffectiveEvent::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 | |||
427 | EffectiveEvent::~EffectiveEvent() | ||
428 | { | ||
429 | delete d; | ||
430 | } | ||
431 | |||
432 | EffectiveEvent::EffectiveEvent( const EffectiveEvent &e ) | ||
433 | { | ||
434 | d = 0; | ||
435 | *this = e; | ||
436 | } | ||
437 | |||
438 | EffectiveEvent& 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 | |||
464 | const QString &EffectiveEvent::description( ) const | ||
465 | { | ||
466 | return mEvent.description(); | ||
467 | } | ||
468 | |||
469 | const QString &EffectiveEvent::location( ) const | ||
470 | { | ||
471 | return mEvent.location(); | ||
472 | } | ||
473 | |||
474 | const QString &EffectiveEvent::notes() const | ||
475 | { | ||
476 | return mEvent.notes(); | ||
477 | } | ||
478 | |||
479 | const Event &EffectiveEvent::event() const | ||
480 | { | ||
481 | return mEvent; | ||
482 | } | ||
483 | |||
484 | const QTime &EffectiveEvent::end() const | ||
485 | { | ||
486 | return mEnd; | ||
487 | } | ||
488 | |||
489 | const QTime &EffectiveEvent::start() const | ||
490 | { | ||
491 | return mStart; | ||
492 | } | ||
493 | |||
494 | const QDate &EffectiveEvent::date() const | ||
495 | { | ||
496 | return mDate; | ||
497 | } | ||
498 | |||
499 | int EffectiveEvent::length() const | ||
500 | { | ||
501 | return (mEnd.hour() * 60 - mStart.hour() * 60) | ||
502 | + QABS(mStart.minute() - mEnd.minute() ); | ||
503 | } | ||
504 | |||
505 | void EffectiveEvent::setDate( const QDate &dt ) | ||
506 | { | ||
507 | mDate = dt; | ||
508 | } | ||
509 | |||
510 | void EffectiveEvent::setStart( const QTime &start ) | ||
511 | { | ||
512 | mStart = start; | ||
513 | } | ||
514 | |||
515 | void EffectiveEvent::setEnd( const QTime &end ) | ||
516 | { | ||
517 | mEnd = end; | ||
518 | } | ||
519 | |||
520 | void EffectiveEvent::setEvent( Event e ) | ||
521 | { | ||
522 | mEvent = e; | ||
523 | } | ||
524 | |||
525 | bool 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 | |||
535 | bool EffectiveEvent::operator<=( const EffectiveEvent &e ) const | ||
536 | { | ||
537 | return (mDate <= e.date() ); | ||
538 | } | ||
539 | |||
540 | bool 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 | |||
548 | bool EffectiveEvent::operator!=( const EffectiveEvent &e ) const | ||
549 | { | ||
550 | return !(*this == e); | ||
551 | } | ||
552 | |||
553 | bool EffectiveEvent::operator>( const EffectiveEvent &e ) const | ||
554 | { | ||
555 | return !(*this <= e ); | ||
556 | } | ||
557 | |||
558 | bool EffectiveEvent::operator>=(const EffectiveEvent &e) const | ||
559 | { | ||
560 | return !(*this < e); | ||
561 | } | ||
562 | |||
563 | void 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 | |||
576 | QDate 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 | |||
586 | QDate 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 | |||
596 | int 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 | ||
605 | static 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 | |||
613 | static 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 | |||
621 | static 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 | |||
655 | static 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 | |||
744 | void 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 | |||
762 | void 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 | |||
778 | QValueList<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 | |||
807 | bool 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 | |||
34 | class EventPrivate; | ||
35 | class QPC_EXPORT Event : public Qtopia::Record | ||
36 | { | ||
37 | public: | ||
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 ¬es() 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 | |||
128 | private: | ||
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 | |||
150 | class EffectiveEventPrivate; | ||
151 | class QPC_EXPORT EffectiveEvent | ||
152 | { | ||
153 | public: | ||
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 ¬es() 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 | |||
200 | private: | ||
201 | class EffectiveEventPrivate *d; | ||
202 | Event mEvent; | ||
203 | QDate mDate; | ||
204 | QTime mStart, | ||
205 | mEnd; | ||
206 | |||
207 | }; | ||
208 | |||
209 | #ifdef PALMTOPCENTER | ||
210 | class QPC_EXPORT EffectiveEventSizeSorter : public QSorter<EffectiveEvent> | ||
211 | { | ||
212 | public: | ||
213 | int compare( const EffectiveEvent& a, const EffectiveEvent& b ) const | ||
214 | { | ||
215 | return a.size() - b.size(); | ||
216 | } | ||
217 | }; | ||
218 | |||
219 | class QPC_EXPORT EffectiveEventTimeSorter : public QSorter<EffectiveEvent> | ||
220 | { | ||
221 | public: | ||
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 | |||
25 | namespace Qtopia { | ||
26 | |||
27 | Record &Record::operator=( const Record &c ) | ||
28 | { | ||
29 | mUid = c.mUid; | ||
30 | mCats = c.mCats; | ||
31 | customMap = c.customMap; | ||
32 | return *this; | ||
33 | } | ||
34 | |||
35 | void 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 | ||
44 | QString 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 | ||
57 | QArray<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 | */ | ||
74 | QString 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 | */ | ||
85 | void 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 | */ | ||
99 | void Record::removeCustomField(const QString &key) | ||
100 | { | ||
101 | customMap.remove(key); | ||
102 | } | ||
103 | |||
104 | QString 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 | |||
119 | void 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 | ||
33 | template class QPC_EXPORT QMap<QString, QString>; | ||
34 | // MOC_SKIP_END | ||
35 | #endif | ||
36 | |||
37 | class QRegExp; | ||
38 | namespace Qtopia { | ||
39 | |||
40 | class RecordPrivate; | ||
41 | class QPC_EXPORT Record | ||
42 | { | ||
43 | public: | ||
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 | |||
78 | protected: | ||
79 | virtual UidGen &uidGen() = 0; | ||
80 | |||
81 | virtual QString customToXml() const; | ||
82 | |||
83 | private: | ||
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 | ||
30 | template class QPC_EXPORT QMap< int, bool >; | ||
31 | // MOC_SKIP_END | ||
32 | #endif | ||
33 | |||
34 | namespace Qtopia { | ||
35 | |||
36 | |||
37 | class QPC_EXPORT UidGen | ||
38 | { | ||
39 | public: | ||
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 | |||
74 | private: | ||
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 | |||
27 | class QPC_EXPORT QFileDirect : public QFile | ||
28 | { | ||
29 | public: | ||
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" | ||
26 | namespace 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 | |||
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 | |||
26 | namespace 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 | |||
36 | static const char collationHack[] = { | ||
37 | 0x00, //C-@ | ||
38 | 0x01, //C-A | ||
39 | 0x02, //C-B | ||
40 | 0x03, //C-C | ||
41 | 0x04, //C-D | ||
42 | 0x05, //C-E | ||
43 | 0x06, //C-F | ||
44 | 0x07, //C-G | ||
45 | 0x08, //C-H | ||
46 | 0x09, //C-I | ||
47 | 0x0a, //C-J | ||
48 | 0x0b, //C-K | ||
49 | 0x0c, //C-L | ||
50 | 0x0d, //C-M | ||
51 | 0x0e, //C-N | ||
52 | 0x0f, //C-O | ||
53 | 0x10, //C-P | ||
54 | 0x11, //C-Q | ||
55 | 0x12, //C-R | ||
56 | 0x13, //C-S | ||
57 | 0x14, //C-T | ||
58 | 0x15, //C-U | ||
59 | 0x16, //C-V | ||
60 | 0x17, //C-W | ||
61 | 0x18, //C-X | ||
62 | 0x19, //C-Y | ||
63 | 0x1a, //C-Z | ||
64 | 0x1b, //C-[ | ||
65 | 0x1c, //C-\ | ||
66 | 0x1d, //C-] | ||
67 | 0x1e, //C-^ | ||
68 | 0x1f, //C-_ | ||
69 | ' ', // | ||
70 | '!', //! | ||
71 | '"', //" | ||
72 | '#', //# | ||
73 | '$', //$ | ||
74 | '%', //% | ||
75 | '&', //& | ||
76 | '\'', //' | ||
77 | '(', //( | ||
78 | ')', //) | ||
79 | '*', //* | ||
80 | '+', //+ | ||
81 | ',', //, | ||
82 | '-', //- | ||
83 | '.', //. | ||
84 | '/', /// | ||
85 | 0x80, //0 | ||
86 | 0x81, //1 | ||
87 | 0x82, //2 | ||
88 | 0x83, //3 | ||
89 | 0x84, //4 | ||
90 | 0x85, //5 | ||
91 | 0x86, //6 | ||
92 | 0x87, //7 | ||
93 | 0x88, //8 | ||
94 | 0x89, //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 | '', // | ||
165 | 0x80, //C-M-@ | ||
166 | 0x81, //C-M-A | ||
167 | 0x82, //C-M-B | ||
168 | 0x83, //C-M-C | ||
169 | 0x84, //C-M-D | ||
170 | 0x85, //C-M-E | ||
171 | 0x86, //C-M-F | ||
172 | 0x87, //C-M-G | ||
173 | 0x88, //C-M-H | ||
174 | 0x89, //C-M-I | ||
175 | 0x8a, //C-M-J | ||
176 | 0x8b, //C-M-K | ||
177 | 0x8c, //C-M-L | ||
178 | 0x8d, //C-M-M | ||
179 | 0x8e, //C-M-N | ||
180 | 0x8f, //C-M-O | ||
181 | 0x90, //C-M-P | ||
182 | 0x91, //C-M-Q | ||
183 | 0x92, //C-M-R | ||
184 | 0x93, //C-M-S | ||
185 | 0x94, //C-M-T | ||
186 | 0x95, //C-M-U | ||
187 | 0x96, //C-M-V | ||
188 | 0x97, //C-M-W | ||
189 | 0x98, //C-M-X | ||
190 | 0x99, //C-M-Y | ||
191 | 0x9a, //C-M-Z | ||
192 | 0x9b, //C-M-[ | ||
193 | 0x9c, //C-M-\ | ||
194 | 0x9d, //C-M-] | ||
195 | 0x9e, //C-M-^ | ||
196 | 0x9f, //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 | |||
299 | static 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 | |||
309 | QString buildSortKey( const QString & s ) | ||
310 | { | ||
311 | QString res = s; | ||
312 | hackString( res ); | ||
313 | return res; | ||
314 | } | ||
315 | |||
316 | QString buildSortKey( const QString & s1, const QString & s2 ) | ||
317 | { | ||
318 | QString res = s1 + QChar( '\0' ) + s2; | ||
319 | hackString( res ); | ||
320 | return res; | ||
321 | } | ||
322 | |||
323 | QString 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 | |||
331 | static inline QChar coll( QChar u ) | ||
332 | { | ||
333 | return u.row() ? u : QChar(collationHack[ u.cell() ]); | ||
334 | } | ||
335 | |||
336 | |||
337 | int 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 | |||
356 | QString 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 | |||
368 | QString 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, "&" ); | ||
377 | else if ( ch == '<' ) | ||
378 | tmp.replace( pos, 1, "<" ); | ||
379 | else if ( ch == '>' ) | ||
380 | tmp.replace( pos, 1, ">" ); | ||
381 | else if ( ch == '\"' ) | ||
382 | tmp.replace( pos, 1, """ ); | ||
383 | } | ||
384 | return tmp; | ||
385 | } | ||
386 | |||
387 | QString plainString( const char* escaped, unsigned int length ) | ||
388 | { | ||
389 | return plainString( QString::fromUtf8( escaped, length ) ); | ||
390 | } | ||
391 | |||
392 | QString plainString( const QCString& string ) | ||
393 | { | ||
394 | // We first have to pass it through a ::fromUtf8() | ||
395 | return plainString( string.data(), string.length() ); | ||
396 | } | ||
397 | |||
398 | QString 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( "&", pos ) == pos ) | ||
404 | tmp.replace( pos, 5, "&" ); | ||
405 | else if ( tmp.find( "<", pos ) == pos ) | ||
406 | tmp.replace( pos, 4, "<" ); | ||
407 | else if( tmp.find( ">", pos ) == pos ) | ||
408 | tmp.replace( pos, 4, ">" ); | ||
409 | else if ( tmp.find( """, 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 | |||
29 | namespace Qtopia | ||
30 | { | ||
31 | |||
32 | // Simplifies white space within each line but keeps the new line characters | ||
33 | QString QPC_EXPORT simplifyMultiLineSpace( const QString &multiLine ); | ||
34 | |||
35 | // Creates a QString which doesn't contain any "dangerous" | ||
36 | // characters (i.e. <, >, &, ") | ||
37 | QString 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 | ||
42 | QString QPC_EXPORT plainString( const char* escaped, unsigned int length ); | ||
43 | QString QPC_EXPORT plainString( const QCString& string ); | ||
44 | |||
45 | QString QPC_EXPORT plainString( const QString& string ); | ||
46 | |||
47 | |||
48 | // collation functions | ||
49 | int compare( const QString & s1, const QString & s2 ); | ||
50 | QString buildSortKey( const QString & s ); | ||
51 | QString buildSortKey( const QString & s1, const QString & s2 ); | ||
52 | QString 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 | |||
31 | using namespace Qtopia; | ||
32 | UidGen Task::sUidGen( UidGen::Qtopia ); | ||
33 | |||
34 | Task::Task() : Record(), mDue( FALSE ), | ||
35 | mDueDate( QDate::currentDate() ), | ||
36 | mCompleted( FALSE ), mPriority( 3 ), mDesc() | ||
37 | { | ||
38 | } | ||
39 | |||
40 | Task::Task( const QMap<int, QString> &m ) : Record(), mDue( FALSE ), | ||
41 | mDueDate( 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 | |||
57 | Task::~Task() | ||
58 | { | ||
59 | } | ||
60 | |||
61 | QMap<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 | |||
77 | void 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 | |||
119 | bool 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 | |||
133 | static 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 | |||
141 | static 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 | |||
150 | static 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 | |||
167 | static 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 | |||
210 | void 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 | |||
228 | void 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 | |||
244 | QValueList<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 | |||
29 | class TaskPrivate; | ||
30 | class QPC_EXPORT Task : public Qtopia::Record | ||
31 | { | ||
32 | public: | ||
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 | |||
65 | private: | ||
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 | |||
26 | QString 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 | |||
35 | QDate 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 | |||
51 | time_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 | |||
83 | QDateTime 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 | |||
100 | int TimeConversion::secsTo( const QDateTime &from, const QDateTime &to ) | ||
101 | { | ||
102 | return toUTC( to ) - toUTC( from ); | ||
103 | } | ||
104 | |||
105 | QCString 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 | |||
115 | QCString 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 | |||
127 | QDateTime 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 | |||
30 | class QPC_EXPORT TimeConversion | ||
31 | { | ||
32 | public: | ||
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 | ||
5 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
6 | |||
7 | For purposes of this license notice, the term Licensors shall mean, | ||
8 | collectively, Apple Computer, Inc., AT&T Corp., International | ||
9 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
10 | The term Licensor shall mean any of the Licensors. | ||
11 | |||
12 | Subject to acceptance of the following conditions, permission is hereby | ||
13 | granted by Licensors without the need for written agreement and without | ||
14 | license or royalty fees, to use, copy, modify and distribute this | ||
15 | software for any purpose. | ||
16 | |||
17 | The above copyright notice and the following four paragraphs must be | ||
18 | reproduced in all copies of this software and any software including | ||
19 | this software. | ||
20 | |||
21 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE | ||
22 | ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR | ||
23 | MODIFICATIONS. | ||
24 | |||
25 | IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, | ||
26 | INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT | ||
27 | OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
28 | DAMAGE. | ||
29 | |||
30 | EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, | ||
31 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE | ||
32 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
33 | PURPOSE. | ||
34 | |||
35 | The software is provided with RESTRICTED RIGHTS. Use, duplication, or | ||
36 | disclosure by the government are subject to restrictions set forth in | ||
37 | DFARS 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 ****/ | ||
138 | int mime_lineNum, mime_numErrors; /* yyerror() can use these */ | ||
139 | static VObject* vObjList; | ||
140 | static VObject *curProp; | ||
141 | static VObject *curObj; | ||
142 | static VObject* ObjStack[MAXLEVEL]; | ||
143 | static int ObjStackTop; | ||
144 | |||
145 | |||
146 | /* A helpful utility for the rest of the app. */ | ||
147 | #if __CPLUSPLUS__ | ||
148 | extern "C" { | ||
149 | #endif | ||
150 | |||
151 | extern void yyerror(char *s); | ||
152 | |||
153 | #if __CPLUSPLUS__ | ||
154 | }; | ||
155 | #endif | ||
156 | |||
157 | int yyparse(); | ||
158 | |||
159 | enum 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 ****/ | ||
171 | static int pushVObject(const char *prop); | ||
172 | static VObject* popVObject(); | ||
173 | static void lexPopMode(int top); | ||
174 | static int lexWithinMode(enum LexMode mode); | ||
175 | static void lexPushMode(enum LexMode mode); | ||
176 | static void enterProps(const char *s); | ||
177 | static void enterAttr(const char *s1, const char *s2); | ||
178 | static void enterValues(const char *value); | ||
179 | #define mime_error yyerror | ||
180 | void mime_error(char *s); | ||
181 | void 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 | |||
217 | mime: vobjects | ||
218 | ; | ||
219 | |||
220 | vobjects: vobjects vobject | ||
221 | { addList(&vObjList, $2); curObj = 0; } | ||
222 | | vobject | ||
223 | { addList(&vObjList, $1); curObj = 0; } | ||
224 | ; | ||
225 | |||
226 | vobject: vcard | ||
227 | | vcal | ||
228 | ; | ||
229 | |||
230 | vcard: | ||
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 | |||
253 | items: items item | ||
254 | | item | ||
255 | ; | ||
256 | |||
257 | item: 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 | |||
270 | prop: name | ||
271 | { | ||
272 | enterProps($1); | ||
273 | } | ||
274 | attr_params | ||
275 | | name | ||
276 | { | ||
277 | enterProps($1); | ||
278 | } | ||
279 | ; | ||
280 | |||
281 | attr_params: attr_params attr_param | ||
282 | | attr_param | ||
283 | ; | ||
284 | |||
285 | attr_param: SEMICOLON attr | ||
286 | ; | ||
287 | |||
288 | attr: name | ||
289 | { | ||
290 | enterAttr($1,0); | ||
291 | } | ||
292 | | name EQ name | ||
293 | { | ||
294 | enterAttr($1,$3); | ||
295 | |||
296 | } | ||
297 | ; | ||
298 | |||
299 | name: ID | ||
300 | ; | ||
301 | |||
302 | values: value SEMICOLON { enterValues($1); } values | ||
303 | | value | ||
304 | { enterValues($1); } | ||
305 | ; | ||
306 | |||
307 | value: STRING | ||
308 | | | ||
309 | { $$ = 0; } | ||
310 | ; | ||
311 | |||
312 | vcal: | ||
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 | |||
324 | calitems: calitems calitem | ||
325 | | calitem | ||
326 | ; | ||
327 | |||
328 | calitem: | ||
329 | eventitem | ||
330 | | todoitem | ||
331 | | items | ||
332 | ; | ||
333 | |||
334 | eventitem: | ||
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 | |||
358 | todoitem: | ||
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 | /*------------------------------------*/ | ||
384 | static 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. */ | ||
405 | static 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 | |||
419 | static 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 | |||
436 | static void enterProps(const char *s) | ||
437 | { | ||
438 | curProp = addGroup(curObj,s); | ||
439 | deleteStr(s); | ||
440 | } | ||
441 | |||
442 | static 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 | |||
468 | struct 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 | |||
494 | static 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 | |||
503 | static 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 | |||
513 | static 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 | |||
520 | static 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 | |||
537 | static int lexGeta() | ||
538 | { | ||
539 | ++lexBuf.len; | ||
540 | return (lexBuf.buf[lexBuf.getPtr] = lexGetc_()); | ||
541 | } | ||
542 | |||
543 | static int lexGeta_(int i) | ||
544 | { | ||
545 | ++lexBuf.len; | ||
546 | return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_()); | ||
547 | } | ||
548 | |||
549 | static 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 | |||
557 | static 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 | |||
583 | static 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 | |||
593 | static 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 | |||
600 | static void lexClearToken() | ||
601 | { | ||
602 | lexBuf.strsLen = 0; | ||
603 | } | ||
604 | |||
605 | static 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 | |||
618 | static char* lexStr() { | ||
619 | return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1); | ||
620 | } | ||
621 | |||
622 | static void lexSkipWhite() { | ||
623 | int c = lexLookahead(); | ||
624 | while (c == ' ' || c == '\t') { | ||
625 | lexSkipLookahead(); | ||
626 | c = lexLookahead(); | ||
627 | } | ||
628 | } | ||
629 | |||
630 | static 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 | |||
644 | static 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 | |||
655 | static 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 | ||
685 | static 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 | |||
721 | static 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 | |||
762 | static 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 | ||
778 | void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile) | ||
779 | #else | ||
780 | void 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 | |||
801 | static 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 | */ | ||
810 | static 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 | |||
911 | static 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 | |||
932 | static 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 | |||
984 | EndString: | ||
985 | lexAppendc(0); | ||
986 | return lexStr(); | ||
987 | } /* LexQuotedPrintable */ | ||
988 | |||
989 | static 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 | |||
1105 | static 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 | /*--------------------------------------------*/ | ||
1121 | DLLEXPORT(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 | |||
1130 | DLLEXPORT(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 | |||
1144 | VObject* 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 | |||
1157 | DLLEXPORT(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 | |||
1177 | static MimeErrorHandler mimeErrorHandler; | ||
1178 | |||
1179 | DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me) | ||
1180 | { | ||
1181 | mimeErrorHandler = me; | ||
1182 | } | ||
1183 | |||
1184 | void 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 | |||
1193 | void 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 | ||
3 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
4 | |||
5 | For purposes of this license notice, the term Licensors shall mean, | ||
6 | collectively, Apple Computer, Inc., AT&T Corp., International | ||
7 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
8 | The term Licensor shall mean any of the Licensors. | ||
9 | |||
10 | Subject to acceptance of the following conditions, permission is hereby | ||
11 | granted by Licensors without the need for written agreement and without | ||
12 | license or royalty fees, to use, copy, modify and distribute this | ||
13 | software for any purpose. | ||
14 | |||
15 | The above copyright notice and the following four paragraphs must be | ||
16 | reproduced in all copies of this software and any software including | ||
17 | this software. | ||
18 | |||
19 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE | ||
20 | ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR | ||
21 | MODIFICATIONS. | ||
22 | |||
23 | IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, | ||
24 | INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT | ||
25 | OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
26 | DAMAGE. | ||
27 | |||
28 | EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, | ||
29 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE | ||
30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
31 | PURPOSE. | ||
32 | |||
33 | The software is provided with RESTRICTED RIGHTS. Use, duplication, or | ||
34 | disclosure by the government are subject to restrictions set forth in | ||
35 | DFARS 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 | |||
65 | typedef union ValueItem { | ||
66 | const char *strs; | ||
67 | unsigned int i; | ||
68 | unsigned long l; | ||
69 | void *any; | ||
70 | VObject *vobj; | ||
71 | } ValueItem; | ||
72 | |||
73 | struct VObject { | ||
74 | VObject *next; | ||
75 | const char *id; | ||
76 | VObject *prop; | ||
77 | unsigned short valType; | ||
78 | ValueItem val; | ||
79 | }; | ||
80 | |||
81 | typedef struct StrItem StrItem; | ||
82 | |||
83 | struct StrItem { | ||
84 | StrItem *next; | ||
85 | const char *s; | ||
86 | unsigned int refCnt; | ||
87 | }; | ||
88 | |||
89 | const 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 | |||
103 | DLLEXPORT(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 | |||
114 | DLLEXPORT(VObject*) newVObject(const char *id) | ||
115 | { | ||
116 | return newVObject_(lookupStr(id)); | ||
117 | } | ||
118 | |||
119 | DLLEXPORT(void) deleteVObject(VObject *p) | ||
120 | { | ||
121 | unUseStr(p->id); | ||
122 | free(p); | ||
123 | } | ||
124 | |||
125 | DLLEXPORT(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 | |||
142 | DLLEXPORT(void) deleteStr(const char *p) | ||
143 | { | ||
144 | if (p) free((void*)p); | ||
145 | } | ||
146 | |||
147 | |||
148 | static 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 | |||
157 | static 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 | |||
167 | DLLEXPORT(const char*) vObjectName(VObject *o) | ||
168 | { | ||
169 | return NAME_OF(o); | ||
170 | } | ||
171 | |||
172 | DLLEXPORT(void) setVObjectName(VObject *o, const char* id) | ||
173 | { | ||
174 | NAME_OF(o) = id; | ||
175 | } | ||
176 | |||
177 | DLLEXPORT(const char*) vObjectStringZValue(VObject *o) | ||
178 | { | ||
179 | return STRINGZ_VALUE_OF(o); | ||
180 | } | ||
181 | |||
182 | DLLEXPORT(void) setVObjectStringZValue(VObject *o, const char *s) | ||
183 | { | ||
184 | STRINGZ_VALUE_OF(o) = dupStr(s,0); | ||
185 | VALUE_TYPE(o) = VCVT_STRINGZ; | ||
186 | } | ||
187 | |||
188 | DLLEXPORT(void) setVObjectStringZValue_(VObject *o, const char *s) | ||
189 | { | ||
190 | STRINGZ_VALUE_OF(o) = s; | ||
191 | VALUE_TYPE(o) = VCVT_STRINGZ; | ||
192 | } | ||
193 | |||
194 | DLLEXPORT(unsigned int) vObjectIntegerValue(VObject *o) | ||
195 | { | ||
196 | return INTEGER_VALUE_OF(o); | ||
197 | } | ||
198 | |||
199 | DLLEXPORT(void) setVObjectIntegerValue(VObject *o, unsigned int i) | ||
200 | { | ||
201 | INTEGER_VALUE_OF(o) = i; | ||
202 | VALUE_TYPE(o) = VCVT_UINT; | ||
203 | } | ||
204 | |||
205 | DLLEXPORT(unsigned long) vObjectLongValue(VObject *o) | ||
206 | { | ||
207 | return LONG_VALUE_OF(o); | ||
208 | } | ||
209 | |||
210 | DLLEXPORT(void) setVObjectLongValue(VObject *o, unsigned long l) | ||
211 | { | ||
212 | LONG_VALUE_OF(o) = l; | ||
213 | VALUE_TYPE(o) = VCVT_ULONG; | ||
214 | } | ||
215 | |||
216 | DLLEXPORT(void*) vObjectAnyValue(VObject *o) | ||
217 | { | ||
218 | return ANY_VALUE_OF(o); | ||
219 | } | ||
220 | |||
221 | DLLEXPORT(void) setVObjectAnyValue(VObject *o, void *t) | ||
222 | { | ||
223 | ANY_VALUE_OF(o) = t; | ||
224 | VALUE_TYPE(o) = VCVT_RAW; | ||
225 | } | ||
226 | |||
227 | DLLEXPORT(VObject*) vObjectVObjectValue(VObject *o) | ||
228 | { | ||
229 | return VOBJECT_VALUE_OF(o); | ||
230 | } | ||
231 | |||
232 | DLLEXPORT(void) setVObjectVObjectValue(VObject *o, VObject *p) | ||
233 | { | ||
234 | VOBJECT_VALUE_OF(o) = p; | ||
235 | VALUE_TYPE(o) = VCVT_VOBJECT; | ||
236 | } | ||
237 | |||
238 | DLLEXPORT(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 | |||
248 | DLLEXPORT(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 | |||
283 | DLLEXPORT(VObject*) addProp(VObject *o, const char *id) | ||
284 | { | ||
285 | return addVObjectProp(o,newVObject(id)); | ||
286 | } | ||
287 | |||
288 | DLLEXPORT(VObject*) addProp_(VObject *o, const char *id) | ||
289 | { | ||
290 | return addVObjectProp(o,newVObject_(id)); | ||
291 | } | ||
292 | |||
293 | DLLEXPORT(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 | |||
308 | DLLEXPORT(VObject*) nextVObjectInList(VObject *o) | ||
309 | { | ||
310 | return o->next; | ||
311 | } | ||
312 | |||
313 | DLLEXPORT(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 | |||
322 | DLLEXPORT(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 | |||
328 | DLLEXPORT(void) initPropIterator(VObjectIterator *i, VObject *o) | ||
329 | { | ||
330 | i->start = o->prop; | ||
331 | i->next = 0; | ||
332 | } | ||
333 | |||
334 | DLLEXPORT(void) initVObjectIterator(VObjectIterator *i, VObject *o) | ||
335 | { | ||
336 | i->start = o->next; | ||
337 | i->next = 0; | ||
338 | } | ||
339 | |||
340 | DLLEXPORT(int) moreIteration(VObjectIterator *i) | ||
341 | { | ||
342 | return (i->start && (i->next==0 || i->next!=i->start)); | ||
343 | } | ||
344 | |||
345 | DLLEXPORT(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 | |||
360 | DLLEXPORT(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 | |||
372 | DLLEXPORT(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 | |||
413 | DLLEXPORT(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 | |||
421 | DLLEXPORT(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 | |||
430 | DLLEXPORT(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 | |||
437 | DLLEXPORT(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 | |||
470 | DLLEXPORT(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 | |||
485 | static StrItem *strTbl[STRTBLSIZE]; | ||
486 | |||
487 | static 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 | |||
497 | DLLEXPORT(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 | |||
515 | DLLEXPORT(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 | |||
542 | DLLEXPORT(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 | |||
559 | struct 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 | |||
570 | static const char *adrFields[] = { | ||
571 | VCPostalBoxProp, | ||
572 | VCExtAddressProp, | ||
573 | VCStreetAddressProp, | ||
574 | VCCityProp, | ||
575 | VCRegionProp, | ||
576 | VCPostalCodeProp, | ||
577 | VCCountryNameProp, | ||
578 | 0 | ||
579 | }; | ||
580 | |||
581 | static const char *nameFields[] = { | ||
582 | VCFamilyNameProp, | ||
583 | VCGivenNameProp, | ||
584 | VCAdditionalNamesProp, | ||
585 | VCNamePrefixesProp, | ||
586 | VCNameSuffixesProp, | ||
587 | NULL | ||
588 | }; | ||
589 | |||
590 | static const char *orgFields[] = { | ||
591 | VCOrgNameProp, | ||
592 | VCOrgUnitProp, | ||
593 | VCOrgUnit2Prop, | ||
594 | VCOrgUnit3Prop, | ||
595 | VCOrgUnit4Prop, | ||
596 | NULL | ||
597 | }; | ||
598 | |||
599 | static 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 | |||
610 | static const char *DAlarmFields[] = { | ||
611 | VCRunTimeProp, | ||
612 | VCSnoozeTimeProp, | ||
613 | VCRepeatCountProp, | ||
614 | VCDisplayStringProp, | ||
615 | 0 | ||
616 | }; | ||
617 | |||
618 | static const char *MAlarmFields[] = { | ||
619 | VCRunTimeProp, | ||
620 | VCSnoozeTimeProp, | ||
621 | VCRepeatCountProp, | ||
622 | VCEmailAddressProp, | ||
623 | VCNoteProp, | ||
624 | 0 | ||
625 | }; | ||
626 | |||
627 | static const char *PAlarmFields[] = { | ||
628 | VCRunTimeProp, | ||
629 | VCSnoozeTimeProp, | ||
630 | VCRepeatCountProp, | ||
631 | VCProcedureNameProp, | ||
632 | 0 | ||
633 | }; | ||
634 | |||
635 | static 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 | |||
798 | static 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 | |||
812 | DLLEXPORT(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 | |||
826 | DLLEXPORT(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 | ||
846 | typedef 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 | ||
856 | static 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 { | ||
865 | stuff: | ||
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 | |||
884 | static void appendcOFile(OFile *fp, char c) | ||
885 | { | ||
886 | if (fp->fail) return; | ||
887 | if (fp->fp) { | ||
888 | fputc(c,fp->fp); | ||
889 | } | ||
890 | else { | ||
891 | stuff: | ||
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 | ||
909 | static void appendcOFile_(OFile *fp, char c) | ||
910 | { | ||
911 | if (fp->fail) return; | ||
912 | if (fp->fp) { | ||
913 | fputc(c,fp->fp); | ||
914 | } | ||
915 | else { | ||
916 | stuff: | ||
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 | |||
934 | static 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 | |||
945 | static 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 | |||
956 | static 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 | |||
966 | static 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 | |||
1008 | static 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 | |||
1022 | static void writeVObject_(OFile *fp, VObject *o); | ||
1023 | |||
1024 | static 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 | |||
1056 | static 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 | |||
1073 | static 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 | |||
1087 | static 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 | |||
1097 | static 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 | |||
1152 | static 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 | |||
1176 | void 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 | |||
1185 | DLLEXPORT(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 | |||
1196 | DLLEXPORT(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 | ||
3 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
4 | |||
5 | For purposes of this license notice, the term Licensors shall mean, | ||
6 | collectively, Apple Computer, Inc., AT&T Corp., International | ||
7 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
8 | The term Licensor shall mean any of the Licensors. | ||
9 | |||
10 | Subject to acceptance of the following conditions, permission is hereby | ||
11 | granted by Licensors without the need for written agreement and without | ||
12 | license or royalty fees, to use, copy, modify and distribute this | ||
13 | software for any purpose. | ||
14 | |||
15 | The above copyright notice and the following four paragraphs must be | ||
16 | reproduced in all copies of this software and any software including | ||
17 | this software. | ||
18 | |||
19 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE | ||
20 | ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR | ||
21 | MODIFICATIONS. | ||
22 | |||
23 | IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, | ||
24 | INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT | ||
25 | OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
26 | DAMAGE. | ||
27 | |||
28 | EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, | ||
29 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE | ||
30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
31 | PURPOSE. | ||
32 | |||
33 | The software is provided with RESTRICTED RIGHTS. Use, duplication, or | ||
34 | disclosure by the government are subject to restrictions set forth in | ||
35 | DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. | ||
36 | |||
37 | ***************************************************************************/ | ||
38 | |||
39 | /* | ||
40 | |||
41 | The vCard/vCalendar C interface is implemented in the set | ||
42 | of files as follows: | ||
43 | |||
44 | vcc.y, yacc source, and vcc.c, the yacc output you will use | ||
45 | implements the core parser | ||
46 | |||
47 | vobject.c implements an API that insulates the caller from | ||
48 | the parser and changes in the vCard/vCalendar BNF | ||
49 | |||
50 | port.h defines compilation environment dependent stuff | ||
51 | |||
52 | vcc.h and vobject.h are header files for their .c counterparts | ||
53 | |||
54 | vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions | ||
55 | which you may find useful. | ||
56 | |||
57 | test.c is a standalone test driver that exercises some of | ||
58 | the features of the APIs provided. Invoke test.exe on a | ||
59 | VCARD/VCALENDAR input text file and you will see the pretty | ||
60 | print output of the internal representation (this pretty print | ||
61 | output should give you a good idea of how the internal | ||
62 | representation looks like -- there is one such output in the | ||
63 | following too). Also, a file with the .out suffix is generated | ||
64 | to show that the internal representation can be written back | ||
65 | in the original text format. | ||
66 | |||
67 | For more information on this API see the readme.txt file | ||
68 | which 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 | ||
87 | are globally unique IDs which can be used to generate clipboard format | ||
88 | ID's as per the requirements of a specific platform. For example, in | ||
89 | Windows they are used as the parameter in a call to RegisterClipboardFormat. | ||
90 | For 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 | |||
278 | typedef struct VObject VObject; | ||
279 | |||
280 | typedef struct VObjectIterator { | ||
281 | VObject* start; | ||
282 | VObject* next; | ||
283 | } VObjectIterator; | ||
284 | |||
285 | extern DLLEXPORT(VObject*) newVObject(const char *id); | ||
286 | extern DLLEXPORT(void) deleteVObject(VObject *p); | ||
287 | extern DLLEXPORT(char*) dupStr(const char *s, unsigned int size); | ||
288 | extern DLLEXPORT(void) deleteStr(const char *p); | ||
289 | extern DLLEXPORT(void) unUseStr(const char *s); | ||
290 | |||
291 | extern DLLEXPORT(void) setVObjectName(VObject *o, const char* id); | ||
292 | extern DLLEXPORT(void) setVObjectStringZValue(VObject *o, const char *s); | ||
293 | extern DLLEXPORT(void) setVObjectStringZValue_(VObject *o, const char *s); | ||
294 | extern DLLEXPORT(void) setVObjectIntegerValue(VObject *o, unsigned int i); | ||
295 | extern DLLEXPORT(void) setVObjectLongValue(VObject *o, unsigned long l); | ||
296 | extern DLLEXPORT(void) setVObjectAnyValue(VObject *o, void *t); | ||
297 | extern DLLEXPORT(VObject*) setValueWithSize(VObject *prop, void *val, unsigned int size); | ||
298 | extern DLLEXPORT(VObject*) setValueWithSize_(VObject *prop, void *val, unsigned int size); | ||
299 | |||
300 | extern DLLEXPORT(const char*) vObjectName(VObject *o); | ||
301 | extern DLLEXPORT(const char*) vObjectStringZValue(VObject *o); | ||
302 | extern DLLEXPORT(unsigned int) vObjectIntegerValue(VObject *o); | ||
303 | extern DLLEXPORT(unsigned long) vObjectLongValue(VObject *o); | ||
304 | extern DLLEXPORT(void*) vObjectAnyValue(VObject *o); | ||
305 | extern DLLEXPORT(VObject*) vObjectVObjectValue(VObject *o); | ||
306 | extern DLLEXPORT(void) setVObjectVObjectValue(VObject *o, VObject *p); | ||
307 | |||
308 | extern DLLEXPORT(VObject*) addVObjectProp(VObject *o, VObject *p); | ||
309 | extern DLLEXPORT(VObject*) addProp(VObject *o, const char *id); | ||
310 | extern DLLEXPORT(VObject*) addProp_(VObject *o, const char *id); | ||
311 | extern DLLEXPORT(VObject*) addPropValue(VObject *o, const char *p, const char *v); | ||
312 | extern DLLEXPORT(VObject*) addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size); | ||
313 | extern DLLEXPORT(VObject*) addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size); | ||
314 | extern DLLEXPORT(VObject*) addGroup(VObject *o, const char *g); | ||
315 | extern DLLEXPORT(void) addList(VObject **o, VObject *p); | ||
316 | |||
317 | extern DLLEXPORT(VObject*) isAPropertyOf(VObject *o, const char *id); | ||
318 | |||
319 | extern DLLEXPORT(VObject*) nextVObjectInList(VObject *o); | ||
320 | extern DLLEXPORT(void) initPropIterator(VObjectIterator *i, VObject *o); | ||
321 | extern DLLEXPORT(int) moreIteration(VObjectIterator *i); | ||
322 | extern DLLEXPORT(VObject*) nextVObject(VObjectIterator *i); | ||
323 | |||
324 | extern DLLEXPORT(const char*) lookupStr(const char *s); | ||
325 | extern DLLEXPORT(void) cleanStrTbl(); | ||
326 | |||
327 | extern DLLEXPORT(void) cleanVObject(VObject *o); | ||
328 | extern DLLEXPORT(void) cleanVObjects(VObject *list); | ||
329 | |||
330 | extern DLLEXPORT(const char*) lookupProp(const char* str); | ||
331 | extern DLLEXPORT(const char*) lookupProp_(const char* str); | ||
332 | |||
333 | extern DLLEXPORT(void) writeVObjectToFile(char *fname, VObject *o); | ||
334 | extern DLLEXPORT(void) writeVObjectsToFile(char *fname, VObject *list); | ||
335 | |||
336 | extern 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 | |||
352 | extern 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 | |||
360 | The functions below are not exported from the DLL because they | ||
361 | take a FILE* as a parameter, which cannot be passed across a DLL | ||
362 | interface (at least that is my experience). Instead you can use | ||
363 | their companion functions which take file names or pointers | ||
364 | to memory. However, if you are linking this code into | ||
365 | your build directly then you may find them a more convenient API | ||
366 | and you can go ahead and use them. If you try to use them with | ||
367 | the DLL LIB you will get a link error. | ||
368 | */ | ||
369 | extern void writeVObject(FILE *fp, VObject *o); | ||
370 | |||
371 | |||
372 | |||
373 | typedef void (*MimeErrorHandler)(char *); | ||
374 | |||
375 | extern DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler); | ||
376 | |||
377 | extern DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len); | ||
378 | extern DLLEXPORT(VObject*) Parse_MIME_FromFileName(char* fname); | ||
379 | |||
380 | |||
381 | /* NOTE regarding Parse_MIME_FromFile | ||
382 | The function above, Parse_MIME_FromFile, comes in two flavors, | ||
383 | neither of which is exported from the DLL. Each version takes | ||
384 | a CFile or FILE* as a parameter, neither of which can be | ||
385 | passed across a DLL interface (at least that is my experience). | ||
386 | If you are linking this code into your build directly then | ||
387 | you may find them a more convenient API that the other flavors | ||
388 | that take a file name. If you use them with the DLL LIB you | ||
389 | will get a link error. | ||
390 | */ | ||
391 | |||
392 | |||
393 | #if INCLUDEMFC | ||
394 | extern VObject* Parse_MIME_FromFile(CFile *file); | ||
395 | #else | ||
396 | extern VObject* Parse_MIME_FromFile(FILE *file); | ||
397 | #endif | ||
398 | |||
399 | #endif /* __VOBJECT_H__ */ | ||
400 | |||
401 | |||