-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 @@ +moc_* +*.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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included +** in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A +** PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include "categories.h" +#include <qfile.h> +#include <qcstring.h> +#include <qtextstream.h> +#include "stringutil.h" + +using namespace Qtopia; + +/*********************************************************** + * + * CategoryGroup + * + **********************************************************/ + +#ifdef PALMTOPCENTER +UidGen CategoryGroup::sUidGen( UidGen::PalmtopCenter ); +#else +UidGen CategoryGroup::sUidGen( UidGen::Qtopia ); +#endif + +int CategoryGroup::add( const QString &label ) +{ + if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") ) + return 0; + + QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label ); + if ( findIt != mLabelIdMap.end() ) + return 0; + int newUid = uidGen().generate(); + insert( newUid, label ); + return newUid; +} + +void CategoryGroup::insert( int uid, const QString &label ) +{ + uidGen().store( uid ); + mIdLabelMap[uid] = label; + mLabelIdMap[label] = uid; +} + +bool CategoryGroup::add( int uid, const QString &label ) +{ + if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") ) + return FALSE; + + QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label ); + if ( labelIt != mLabelIdMap.end() ) + return FALSE; + QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid ); + if ( idIt != mIdLabelMap.end() ) + return FALSE; + insert( uid, label ); + return TRUE; +} + +bool CategoryGroup::remove( const QString &label ) +{ + QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label ); + if ( findIt == mLabelIdMap.end() ) + return FALSE; + + mIdLabelMap.remove( *findIt ); + mLabelIdMap.remove( findIt ); + + return TRUE; +} + +bool CategoryGroup::remove( int uid ) +{ + QMap<int,QString>::Iterator idIt = mIdLabelMap.find( uid ); + if ( idIt == mIdLabelMap.end() ) + return FALSE; + + mLabelIdMap.remove( *idIt ); + mIdLabelMap.remove( idIt ); + + return TRUE; +} + +bool CategoryGroup::rename( int uid, const QString &newLabel ) +{ + if ( newLabel == QObject::tr("All") || newLabel == QObject::tr("Unfiled") ) + return FALSE; + + QMap<int, QString>::Iterator idIt = mIdLabelMap.find( uid ); + if ( idIt == mIdLabelMap.end() ) + return FALSE; + + mLabelIdMap.remove( *idIt ); + mLabelIdMap[newLabel] = uid; + *idIt = newLabel; + + return TRUE; +} + +bool CategoryGroup::rename( const QString &oldLabel, const QString &newLabel ) +{ + return rename( id(oldLabel), newLabel ); +} + +bool CategoryGroup::contains(int uid) const +{ + return ( mIdLabelMap.find( uid ) != mIdLabelMap.end() ); +} + +bool CategoryGroup::contains(const QString &label) const +{ + return ( mLabelIdMap.find( label ) != mLabelIdMap.end() ); +} + +/** Returns label associated with the uid or QString::null if + * not found + */ +const QString &CategoryGroup::label(int uid) const +{ + QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid ); + if ( idIt == mIdLabelMap.end() ) + return QString::null; + return *idIt; +} + +/** Returns the uid associated with label or 0 if not found */ +int CategoryGroup::id(const QString &label) const +{ + QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label ); + if ( labelIt == mLabelIdMap.end() ) + return 0; + return *labelIt; +} + +QStringList CategoryGroup::labels() const +{ + QStringList labels; + for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin(); + it != mIdLabelMap.end(); ++it ) + labels += *it; + // ### I don't think this is the place for this... +// labels.sort(); + return labels; +} + +QStringList CategoryGroup::labels(const QArray<int> &catids ) const +{ + QStringList labels; + if ( catids.count() == 0 ) + return labels; + for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin(); + it != mIdLabelMap.end(); ++it ) + if ( catids.find( it.key() ) != -1 ) + labels += *it; + return labels; +} + +QArray<int> CategoryGroup::ids( const QStringList &cats ) const +{ + QArray<int> results; + + for ( QStringList::ConstIterator catIt = cats.begin(); + catIt != cats.end(); ++catIt ) { + if ( *catIt == QObject::tr("All") || *catIt == QObject::tr("Unfiled") ) + continue; + int value = id( *catIt ); + if ( value != 0 ) { + int tmp = results.size(); + results.resize( tmp + 1 ); + results[ tmp ] = value; + } + } + + return results; +} + +QArray<int> CategoryGroup::ids() const +{ + QArray<int> results( mIdLabelMap.count() ); + int i = 0; + for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin(); + it != mIdLabelMap.end(); ++it ) + results[i++] = it.key(); + + return results; +} + +/*********************************************************** + * + * Categories + * + **********************************************************/ + +/** Add the category name as long as it doesn't already exist locally + * or globally. Return TRUE if added, FALSE if conflicts. + */ +int Categories::addCategory( const QString &appname, + const QString &catname, + int uid ) +{ + if ( mGlobalCats.contains(catname) ) + return 0; + + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + + if ( appIt == mAppCats.end() ) { + CategoryGroup newgroup; + newgroup.add( uid, catname ); + mAppCats.insert( appname, newgroup ); + emit categoryAdded( *this, appname, uid ); + return uid; + } + + CategoryGroup &cats = *appIt; + cats.add( uid, catname ); + emit categoryAdded( *this, appname, uid ); + return uid; +} + +int Categories::addCategory( const QString &appname, + const QString &catname ) +{ + if ( mGlobalCats.contains(catname) ) + return 0; + + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + + if ( appIt == mAppCats.end() ) { + CategoryGroup newgroup; + int uid = newgroup.add( catname ); + mAppCats.insert( appname, newgroup ); + emit categoryAdded( *this, appname, uid ); + return uid; + } + + CategoryGroup &cats = *appIt; + int uid = cats.add( catname ); + if ( !uid ) + return 0; + emit categoryAdded( *this, appname, uid ); + return uid; +} + +int Categories::addGlobalCategory( const QString &catname, int uid ) +{ + mGlobalCats.add( uid, catname ); + emit categoryAdded( *this, QString::null, uid ); + return uid; +} + +int Categories::addGlobalCategory( const QString &catname ) +{ + int uid = mGlobalCats.add( catname ); + if ( !uid ) + return 0; + emit categoryAdded( *this, QString::null, uid ); + return uid; +} + +/** Removes the category from the application; if it is not found + * in the application, then it attempts to remove it from + * the global list + */ +bool Categories::removeCategory( const QString &appname, + const QString &catname, + bool checkGlobal ) +{ + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + if ( appIt != mAppCats.end() ) { + CategoryGroup &cats = *appIt; + int uid = cats.id( catname ); + if ( cats.remove( uid ) ) { + emit categoryRemoved( *this, appname, uid ); + return TRUE; + } + } + if ( !checkGlobal ) + return FALSE; + return removeGlobalCategory( catname ); +} + +bool Categories::removeCategory( const QString &appname, int uid ) +{ + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + if ( appIt != mAppCats.end() ) { + CategoryGroup &cats = *appIt; + if ( cats.remove( uid ) ) { + emit categoryRemoved( *this, appname, uid ); + return TRUE; + } + } + return FALSE; +} + +bool Categories::removeGlobalCategory( const QString &catname ) +{ + int uid = mGlobalCats.id( catname ); + if ( mGlobalCats.remove( uid ) ) { + emit categoryRemoved( *this, QString::null, uid ); + return TRUE; + } + return FALSE; +} + + +bool Categories::removeGlobalCategory( int uid ) +{ + if ( mGlobalCats.remove( uid ) ) { + emit categoryRemoved( *this, QString::null, uid ); + return TRUE; + } + return FALSE; +} + +/** Returns the sorted list of all categories that are associated with + * the app. If includeGlobal parameter is TRUE then the returned + * categories will include the global category items. + */ +QStringList Categories::labels( const QString &app, + bool includeGlobal, + ExtraLabels extra ) const +{ + QMap< QString, CategoryGroup >::ConstIterator + appIt = mAppCats.find( app ); + QStringList cats; + switch ( extra ) { + case NoExtra: break; + case AllUnfiled: + cats.append( tr("All") ); + cats.append( tr("Unfiled") ); + break; + case AllLabel: + cats.append( tr("All") ); + break; + case UnfiledLabel: + cats.append( tr("Unfiled") ); + break; + } + if ( appIt != mAppCats.end() ) + cats += (*appIt).labels(); + else qDebug("Categories::labels didn't find app %s", app.latin1() ); + if ( includeGlobal ) + cats += mGlobalCats.labels(); + // I don't think a sorted list is useful, the user might find prefer + // it in the original order. +// cats.sort(); + return cats; +} + +QString Categories::label( const QString &app, int id ) const +{ + if ( mGlobalCats.contains( id ) ) + return mGlobalCats.label( id ); + QMap< QString, CategoryGroup >::ConstIterator + appIt = mAppCats.find( app ); + if ( appIt == mAppCats.end() ) + return QString::null; + return (*appIt).label( id ); +} + +QStringList Categories::labels( const QString & app, + const QArray<int> &catids ) const +{ + QStringList strs = mGlobalCats.labels( catids ); + strs += mAppCats[app].labels( catids ); + return strs; +} + +/** Returns a single string associated with the cat ids for display in + * a combobox or any area that requires one string. If catids are empty + * then "Unfiled" will be returned. If multiple categories are assigned + * the first cat id is shown with " (multi)" appended to the string. + */ +QString Categories::displaySingle( const QString &app, + const QArray<int> &catids, + DisplaySingle display ) const +{ + QStringList strs = labels( app, catids ); + if ( !strs.count() ) + return tr("Unfiled"); + strs.sort(); + QString r; + if ( strs.count() > 1 ) { + switch ( display ) { + case ShowFirst: + r = strs.first(); + break; + case ShowMulti: + r = strs.first() + tr(" (multi.)"); + break; + case ShowAll: + r = strs.join(" "); + break; + } + } + else r = strs.first(); + return r; +} + +QArray<int> Categories::ids( const QString &app ) const +{ + QArray<int> allIds = mGlobalCats.ids(); + QArray<int> appIds = mAppCats[app].ids(); + + // we should make the guarentee that the ids are in the + // same order as the labels, (i.e. app cats then global) + // otherwise there is no point in having these two separate functions. + uint appSize = appIds.size(); + appIds.resize( appSize + allIds.size() ); + for ( uint i = appSize; i < appIds.size(); ++i ) + appIds[int(i)] = allIds[int(i - appSize)]; + + return appIds; +} + +QArray<int> Categories::ids( const QString &app, const QStringList &cats ) const +{ + QArray<int> allIds = mGlobalCats.ids( cats ); + QArray<int> appIds = mAppCats[app].ids( cats ); + + uint appSize = appIds.size(); + appIds.resize( appSize + allIds.size() ); + for ( uint i = appSize; i < appIds.size(); ++i ) + appIds[int(i)] = allIds[int(i - appSize)]; + + return appIds; +} + +int Categories::id( const QString &app, const QString &cat ) const +{ + if ( cat == tr("Unfiled") || cat.contains( tr(" (multi.)") ) ) + return 0; + int uid = mGlobalCats.id( cat ); + if ( uid != 0 ) + return uid; + return mAppCats[app].id( cat ); +} + + +/** Return TRUE if renaming succeeded; FALSE if app name not found, + * or if there was a name conflict + */ +bool Categories::renameCategory( const QString &appname, + const QString &oldName, + const QString &newName ) +{ + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + + if ( appIt != mAppCats.end() ) { + CategoryGroup &cats = *appIt; + int id = cats.id( oldName ); + if ( id != 0 && cats.rename( id, newName ) ) { + emit categoryRenamed( *this, appname, id ); + return TRUE; + } + } + return renameGlobalCategory( oldName, newName ); +} + +bool Categories::renameGlobalCategory( const QString &oldName, + const QString &newName ) +{ + int uid = mGlobalCats.id( oldName ); + if ( uid != 0 && mGlobalCats.rename( uid, newName ) ) { + emit categoryRenamed( *this, QString::null, uid ); + return TRUE; + } + return FALSE; +} + +void Categories::setGlobal( const QString &appname, + const QString &catname, + bool global ) +{ + // if in global and should be in app; then move it + if ( mGlobalCats.contains( catname ) && !global ) { + mGlobalCats.remove( catname ); + addCategory( appname, catname ); + return ; + } + + // if in app and should be in global, then move it + if ( !global ) + return; + if ( removeCategory( appname, catname, FALSE ) ) + addGlobalCategory( catname ); +} + +bool Categories::isGlobal( const QString &catname ) const +{ + return mGlobalCats.contains( catname ); +} + + +/** Returns true if the catname is associated with any application + */ +bool Categories::exists( const QString &catname ) const +{ + if ( isGlobal(catname) ) + return TRUE; + + for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt ) + if ( exists( appsIt.key(), catname ) ) + return TRUE; + + return FALSE; +} + +bool Categories::exists( const QString &appname, + const QString &catname) const +{ + QMap< QString, CategoryGroup >::ConstIterator + appIt = mAppCats.find( appname ); + + if ( appIt == mAppCats.end() ) + return FALSE; + + return (*appIt).contains( catname ); +} + +bool Categories::save( const QString &fname ) const +{ + QFile file( fname ); + if ( !file.open( IO_WriteOnly ) ) { + qWarning("Unable to write to %s", fname.latin1()); + return FALSE; + } + + QTextStream ts( &file ); + ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + ts << "<!DOCTYPE CategoryList>" << endl; + + ts << "<Categories>" << endl; + for ( QMap<int, QString>::ConstIterator git = mGlobalCats.idMap().begin(); + git != mGlobalCats.idMap().end(); ++git ) + ts << "<Category id=\"" << git.key() << "\"" + << " name=\"" << escapeString(*git) << "\" />" << endl; + + for ( QMap<QString, CategoryGroup>::ConstIterator appsIt=mAppCats.begin(); + appsIt != mAppCats.end(); ++appsIt ) { + const QString &app = appsIt.key(); + const QMap<int, QString> &appcats = (*appsIt).idMap(); + for ( QMap<int, QString>::ConstIterator appcatit = appcats.begin(); + appcatit != appcats.end(); ++appcatit ) + ts << "<Category id=\"" << appcatit.key() << "\"" + << " app=\"" << escapeString(app) << "\"" + << " name=\"" << escapeString(*appcatit) << "\" />" << endl; + } + ts << "</Categories>" << endl; + + file.close(); + return TRUE; +} + +bool Categories::load( const QString &fname ) +{ + QFile file( fname ); + if ( !file.open( IO_ReadOnly ) ) { + qWarning("Unable to open %s", fname.latin1()); + return FALSE; + } + + clear(); + QByteArray ba = file.readAll(); + QString data = QString::fromUtf8( ba.data(), ba.size() ); + QChar *uc = (QChar *)data.unicode(); + int len = data.length(); + + // QTime t; + // t.start(); + QString name; + QString id; + QString app; + int i = 0; + while ( (i = data.find( "<Category ", i)) != -1 ) { + + i += 10; + name = QString::null; + app = QString::null; + while ( 1 ) { + // skip white space + while ( i < len && + (uc[i] == ' ' || uc[i] == '\n' || uc[i] == '\r') ) + i++; + // if at the end, then done + if ( i >= len-2 || (uc[i] == '/' && uc[i+1] == '>') ) + break; + // we have another attribute read it. + int j = i; + while ( j < len && uc[j] != '=' ) + j++; + QString attr = QConstString( uc+i, j-i ).string(); + i = ++j; // skip = + while ( i < len && uc[i] != '"' ) + i++; + j = ++i; + while ( j < len && uc[j] != '"' ) + j++; + QString value = Qtopia::plainString( QConstString( uc+i, j-i ).string() ); + i = j + 1; + +// qDebug("attr='%s' value='%s'", attr.latin1(), value.latin1() ); + if ( attr == "id" ) + id = value; + else if ( attr == "app" ) + app = value; + + else if ( attr == "name" ) + name = value; + } + + if ( name.isNull() || id.isNull() ) { + qWarning("No name or id in the category"); + continue; + } + if ( app.isNull() ) + mGlobalCats.add( id.toInt(), name ); + else + mAppCats[ app ].add( id.toInt(), name ); + } + + return TRUE; +} + +void Categories::clear() +{ + mGlobalCats.clear(); + mAppCats.clear(); +} + +void Categories::dump() const +{ + qDebug("\tglobal categories = %s", mGlobalCats.labels().join(", ").latin1() ); + for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt ) { + const QString &app = appsIt.key(); + QStringList appcats = (*appsIt).labels(); + qDebug("\tapp = %s\tcategories = %s", app.latin1(), + appcats.join(", ").latin1() ); + + } +} + +QStringList CheckedListView::checked() const +{ + QStringList strs; + for ( QCheckListItem *i = (QCheckListItem *) firstChild(); + i; i = (QCheckListItem *)i->nextSibling() ) + if ( i->isOn() ) + strs += i->text( 0 ); + return strs; +} + +void CheckedListView::addCheckableList( const QStringList &options ) +{ + for ( QStringList::ConstIterator it = options.begin(); + it != options.end(); ++it ) { + (void) new QCheckListItem( this, *it, + QCheckListItem::CheckBox ); + } +} + +void CheckedListView::setChecked( const QStringList &checked ) +{ + // iterate over all items + bool showingChecked = FALSE; + for ( QCheckListItem *i = (QCheckListItem *) firstChild(); + i; i = (QCheckListItem *)i->nextSibling() ) + // see if the item should be checked by searching the + // checked list + if ( checked.find( i->text( 0 ) ) != checked.end() ) { + i->setOn( TRUE ); + // make sure it is showing at least one checked item + if ( !showingChecked ) { + ensureItemVisible( i ); + showingChecked = TRUE; + } + } + else + i->setOn( FALSE ); +} 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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included +** in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A +** PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QTPALMTOP_CATEGORIES_H +#define QTPALMTOP_CATEGORIES_H + +#include <qstring.h> +#include <qstringlist.h> +#include <qmap.h> +#include <qlistview.h> +#include <qarray.h> +#include "qpcglobal.h" +#include "palmtopuidgen.h" + +class CategoryGroup; + +#if defined(QPC_TEMPLATEDLL) +// MOC_SKIP_BEGIN +template class QPC_EXPORT QMap<int, QString>; +template class QPC_EXPORT QMap<QString, int>; +template class QPC_EXPORT QMap< QString, CategoryGroup >; +// MOC_SKIP_END +#endif + +class QPC_EXPORT CategoryGroup +{ + friend class Categories; +public: + CategoryGroup(): mIdLabelMap(), mLabelIdMap() { } + CategoryGroup( const CategoryGroup &c ) : + mIdLabelMap( c.mIdLabelMap), mLabelIdMap( c.mLabelIdMap ) { } + + void clear() { mIdLabelMap.clear(); mLabelIdMap.clear(); } + + int add( const QString &label ); + bool add( int uid, const QString &label ); + + bool remove( const QString &label ); + bool remove( int uid ); + + bool rename( int uid, const QString &newLabel ); + bool rename( const QString &oldLabel, const QString &newLabel ); + + bool contains(int id) const; + bool contains(const QString &label) const; + + /** Returns label associated with the uid or QString::null if + * not found + */ + const QString &label(int id) const; + /** Returns the uid associated with label or 0 if not found */ + int id(const QString &label) const; + + /** Returns a sorted list of labels */ + QStringList labels() const; + QArray<int> ids( const QStringList &cats ) const; + QArray<int> ids() const; + QStringList labels( const QArray<int> &catids ) const; + + const QMap<int, QString> &idMap() const { return mIdLabelMap; } + +private: + void insert( int uid, const QString &label ); + QMap<int, QString> mIdLabelMap; + QMap<QString, int> mLabelIdMap; + + static Qtopia::UidGen &uidGen() { return sUidGen; } + static Qtopia::UidGen sUidGen; +}; + +/** Map from application name to categories */ +class QPC_EXPORT Categories : public QObject +{ + Q_OBJECT +public: + Categories( QObject *parent=0, const char *name = 0 ) + : QObject( parent, name ), mGlobalCats(), mAppCats() { } + Categories( const Categories ©From ) : QObject( copyFrom.parent() ), + mGlobalCats( copyFrom.mGlobalCats ), + mAppCats( copyFrom.mAppCats ) { } + virtual ~Categories() { } + + Categories &operator= ( const Categories &c ) +{ mAppCats = c.mAppCats; mGlobalCats = c.mGlobalCats; return *this; } + + void clear(); + + /** Add the category name as long as it doesn't already exist + * locally or globally. Return UID if added, 0 if conflicts + * (error). + */ + int addCategory( const QString &appname, const QString &catname); + /** Add the category name as long as it doesn't already exist + * locally or globally. Return UID if added, 0 if conflicts + * (error). + */ + int addCategory( const QString &appname, const QString &catname, int uid); + /** Add the global category just checking that it doesn't + * already exist globally. Return UID if added, 0 if conflicts. + */ + int addGlobalCategory( const QString &catname ); + /** Add the global category just checking that it doesn't + * already exist globally. Return UID if added, 0 if conflicts. + */ + int addGlobalCategory( const QString &catname, int uid ); + /** Removes the category from the application; if it is not found + * in the application, then it removes it from the global list + */ + bool removeCategory( const QString &appName, const QString &catName, + bool checkGlobal = TRUE); + bool removeCategory( const QString &appName, int uid ); + bool removeGlobalCategory( const QString &catName ); + bool removeGlobalCategory( int uid ); + + QArray<int> ids( const QString &app ) const; + QArray<int> ids( const QString &app, + const QStringList &cats ) const; + /** Returns the id associated with the app */ + int id( const QString &app, const QString &cat ) const; + /** Returns the label associated with the id */ + QString label( const QString &app, int id ) const; + + enum ExtraLabels { NoExtra, AllUnfiled, AllLabel, UnfiledLabel }; + /** Returns the sorted list of all categories that are + * associated with the app. + * If includeGlobal parameter is TRUE then the returned + * categories will include the global category items. + * If extra = NoExtra, then + * If extra = AllUnfiled, then All and Unfiled will be prepended to + * the list + * If extra = AllLabel, then All is prepended + * If extra = UnfiledLabel, then Unfiled is prepended + */ + QStringList labels( const QString &app, + bool includeGlobal = TRUE, + ExtraLabels extra = NoExtra ) const; + + /** Returns the labels of the categories associated with the uids */ + QStringList labels( const QString & app, + const QArray<int> &catids ) const; + + enum DisplaySingle { ShowMulti, ShowAll, ShowFirst }; + + /** Returns a single string associated with the cat ids for display in + * a combobox or any area that requires one string. If catids are empty + * then "Unfiled" will be returned. If multiple categories are assigned + * then the behavior depends on the DisplaySingle type. + * If /a display is set to ShowMulti then " (multi)" appended to the + * first string. If /a display is set to ShowAll, then a space seperated + * string is returned with all categories. If ShowFirst is returned, + * the just the first string is returned. + */ + QString displaySingle( const QString &app, + const QArray<int> &catids, + DisplaySingle display ) const; + + QStringList globalCategories() const { return mGlobalCats.labels();} + + bool renameCategory( const QString &appname, + const QString &oldName, + const QString &newName ); + bool renameGlobalCategory( const QString &oldName, + const QString &newName ); + + void setGlobal( const QString &appname, const QString &catname, + bool value ); + bool isGlobal( const QString &catname ) const; + + + /** Returns true if the catname is associated with any application + */ + bool exists( const QString &catname ) const; + bool exists( const QString &appname, const QString &catname) const; + + bool save( const QString &fname ) const; + bool load( const QString &fname ); + + // for debugging + void dump() const; + + const QMap<QString, CategoryGroup> &appGroupMap() const{ return mAppCats; } + const CategoryGroup &globalGroup() const { return mGlobalCats; } + +signals: + /** emitted if added a category; + * the second param is the application the category was added to + * or null if global + * the third param is the uid of the newly added category + */ + void categoryAdded( const Categories &, const QString &, int ); + /** emitted if removed a category + * the second param is the application the category was removed from + * or null if global + * the third param is the uid of the removed category + */ + void categoryRemoved( const Categories &, const QString &, int ); + /** emitted if a category is renamed; the second param is the uid of + * the removed category */ + void categoryRenamed( const Categories &, const QString &, int ); + +private: + CategoryGroup mGlobalCats; + QMap< QString, CategoryGroup > mAppCats; +}; + +class QPC_EXPORT CheckedListView : public QListView +{ +public: + void addCheckableList( const QStringList &options ); + void setChecked( const QStringList &checked ); + QStringList checked() const; +}; + +#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 @@ +/********************************************************************** +** Copyright (C) 2001 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "contact.h" +#include "vobject_p.h"
+#include "qfiledirect_p.h"
+ +#include <qpe/stringutil.h> +#include <qpe/timeconversion.h> + +#include <qobject.h> +#include <qregexp.h> +#include <qstylesheet.h> +#include <qfileinfo.h> + +#include <stdio.h> + +Qtopia::UidGen Contact::sUidGen( Qtopia::UidGen::Qtopia ); + +Contact::Contact() + : Record(), mMap(), d( 0 ) +{ +} + +Contact::Contact( const QMap<int, QString> &fromMap ) : + Record(), mMap( fromMap ), d( 0 ) +{ + QString cats = mMap[ Qtopia::AddressCategory ]; + if ( !cats.isEmpty() ) + setCategories( idsFromString( cats ) ); + QString uidStr = find( Qtopia::AddressUid ); + if ( uidStr.isEmpty() ) + setUid( uidGen().generate() ); + else + setUid( uidStr.toInt() ); +} + +Contact::~Contact() +{ +} + +QMap<int, QString> Contact::toMap() const +{ + QMap<int, QString> map = mMap; + map.insert( Qtopia::AddressCategory, idsToString( categories() )); + return map; +} + +/*! + Returns a rich text formatted QString of the Contact. +*/ +QString Contact::toRichText() const +{ + QString text; + QString value, comp, state; + + // name, jobtitle and company + if ( !(value = fullName()).isEmpty() ) + text += "<b>" + Qtopia::escapeString(value) + "</b><br>"; + if ( !(value = jobTitle()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + + comp = company(); + if ( !(value = department()).isEmpty() ) { + text += Qtopia::escapeString(value); + if ( comp ) + text += ", "; + else + text += "<br>"; + } + if ( !comp.isEmpty() ) + text += Qtopia::escapeString(comp) + "<br>"; + + // business address + if ( !businessStreet().isEmpty() || !businessCity().isEmpty() || + !businessZip().isEmpty() || !businessCountry().isEmpty() ) { + text += "<br>"; + text += QObject::tr( "<b>Work Address:</b>" ); + text += "<br>"; + } + + if ( !(value = businessStreet()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + state = businessState(); + if ( !(value = businessCity()).isEmpty() ) { + text += Qtopia::escapeString(value); + if ( state ) + text += ", " + Qtopia::escapeString(state); + text += "<br>"; + } else if ( !state.isEmpty() ) + text += Qtopia::escapeString(state) + "<br>"; + if ( !(value = businessZip()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + if ( !(value = businessCountry()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + + // home address + if ( !homeStreet().isEmpty() || !homeCity().isEmpty() || + !homeZip().isEmpty() || !homeCountry().isEmpty() ) { + text += "<br>"; + text += QObject::tr( "<b>Home Address:</b>" ); + text += "<br>"; + } + + if ( !(value = homeStreet()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + state = homeState(); + if ( !(value = homeCity()).isEmpty() ) { + text += Qtopia::escapeString(value); + if ( !state.isEmpty() ) + text += ", " + Qtopia::escapeString(state); + text += "<br>"; + } else if (!state.isEmpty()) + text += Qtopia::escapeString(state) + "<br>"; + if ( !(value = homeZip()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + if ( !(value = homeCountry()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + + // the others... + QString str; + str = emails(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Email Addresses: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = homePhone(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Home Phone: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = homeFax(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Home Fax: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = homeMobile(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Home Mobile: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = homeWebpage(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Home Web Page: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessWebpage(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Web Page: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = office(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Office: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessPhone(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Phone: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessFax(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Fax: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessMobile(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Mobile: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessPager(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Pager: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = profession(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Profession: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = assistant(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Assistant: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = manager(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Manager: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = gender(); + if ( !str.isEmpty() && str.toInt() != 0 ) { + if ( str.toInt() == 1 ) + str = QObject::tr( "Male" ); + else if ( str.toInt() == 2 ) + str = QObject::tr( "Female" ); + text += "<b>" + QObject::tr("Gender: ") + "</b>" + str + "<br>"; + } + str = spouse(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Spouse: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = birthday(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Birthday: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = anniversary(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Anniversary: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = nickname(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Nickname: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + + // notes last + if ( (value = notes()) ) { + QRegExp reg("\n"); + + //QString tmp = Qtopia::escapeString(value); + QString tmp = QStyleSheet::convertFromPlainText(value); + //tmp.replace( reg, "<br>" ); + text += "<br>" + tmp + "<br>"; + } + return text; +} + +void Contact::insert( int key, const QString &v ) +{ + QString value = v.stripWhiteSpace(); + if ( value.isEmpty() ) + mMap.remove( key ); + else + mMap.insert( key, value ); +} + +void Contact::replace( int key, const QString & v ) +{ + QString value = v.stripWhiteSpace(); + if ( value.isEmpty() ) + mMap.remove( key ); + else + mMap.replace( key, value ); +} + +QString Contact::find( int key ) const +{ + return mMap[key]; +} + +QString Contact::displayAddress( const QString &street, + const QString &city, + const QString &state, + const QString &zip, + const QString &country ) const +{ + QString s = street; + if ( !street.isEmpty() ) + s+= "\n"; + s += city; + if ( !city.isEmpty() && !state.isEmpty() ) + s += ", "; + s += state; + if ( !state.isEmpty() && !zip.isEmpty() ) + s += " "; + s += zip; + if ( !country.isEmpty() && !s.isEmpty() ) + s += "\n"; + s += country; + return s; +} + +QString Contact::displayBusinessAddress() const +{ + return displayAddress( businessStreet(), businessCity(), + businessState(), businessZip(), + businessCountry() ); +} + +QString Contact::displayHomeAddress() const +{ + return displayAddress( homeStreet(), homeCity(), + homeState(), homeZip(), + homeCountry() ); +} + +QString Contact::fullName() const +{ + QString title = find( Qtopia::Title ); + QString firstName = find( Qtopia::FirstName ); + QString middleName = find( Qtopia::MiddleName ); + QString lastName = find( Qtopia::LastName ); + QString suffix = find( Qtopia::Suffix ); + + QString name = title; + if ( !firstName.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += firstName; + } + if ( !middleName.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += middleName; + } + if ( !lastName.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += lastName; + } + if ( !suffix.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += suffix; + } + return name.simplifyWhiteSpace(); +} + +QStringList Contact::childrenList() const +{ + return QStringList::split( " ", find( Qtopia::Children ) ); +} + +QStringList Contact::emailList() const +{ + return QStringList::split( ";", find( Qtopia::Emails ) ); +} + +void Contact::setFileAs() +{ + QString lastName, firstName, middleName, fileas; + + lastName = find( Qtopia::LastName ); + firstName = find( Qtopia::FirstName ); + middleName = find( Qtopia::MiddleName ); + if ( !lastName.isEmpty() && !firstName.isEmpty() + && !middleName.isEmpty() ) + fileas = lastName + ", " + firstName + " " + middleName; + else if ( !lastName.isEmpty() && !firstName.isEmpty() ) + fileas = lastName + ", " + firstName; + else if ( !lastName.isEmpty() || !firstName.isEmpty() || + !middleName.isEmpty() ) + fileas = firstName + ( firstName.isEmpty() ? "" : " " ) + + middleName + ( middleName.isEmpty() ? "" : " " ) + + lastName; + + replace( Qtopia::FileAs, fileas ); +} + +void Contact::save( QString &buf ) const +{ + static const QStringList SLFIELDS = fields(); + // I'm expecting "<Contact " in front of this... + for ( QMap<int, QString>::ConstIterator it = mMap.begin(); + it != mMap.end(); ++it ) { + const QString &value = it.data(); + int key = it.key(); + if ( !value.isEmpty() ) { + if ( key == Qtopia::AddressCategory || key == Qtopia::AddressUid) + continue; + + key -= Qtopia::AddressCategory+1; + buf += SLFIELDS[key]; + buf += "=\"" + Qtopia::escapeString(value) + "\" "; + } + } + buf += customToXml(); + if ( categories().count() > 0 ) + buf += "Categories=\"" + idsToString( categories() ) + "\" "; + buf += "Uid=\"" + QString::number( uid() ) + "\" "; + // You need to close this yourself +} + +QStringList Contact::fields() +{ + QStringList list; + + list.append( "Title" ); // Not Used! + list.append( "FirstName" ); + list.append( "MiddleName" ); + list.append( "LastName" ); + list.append( "Suffix" ); + list.append( "FileAs" ); + + list.append( "DefaultEmail" ); + list.append( "Emails" ); + + list.append( "HomeStreet" ); + list.append( "HomeCity" ); + list.append( "HomeState" ); + list.append( "HomeZip" ); + list.append( "HomeCountry" ); + list.append( "HomePhone" ); + list.append( "HomeFax" ); + list.append( "HomeMobile" ); + list.append( "HomeWebPage" ); + + list.append( "Company" ); + list.append( "BusinessStreet" ); + list.append( "BusinessCity" ); + list.append( "BusinessState" ); + list.append( "BusinessZip" ); + list.append( "BusinessCountry" ); + list.append( "BusinessWebPage" ); + list.append( "JobTitle" ); + list.append( "Department" ); + list.append( "Office" ); + list.append( "BusinessPhone" ); + list.append( "BusinessFax" ); + list.append( "BusinessMobile" ); + list.append( "BusinessPager" ); + list.append( "Profession" ); + list.append( "Assistant" ); + list.append( "Manager" ); + + list.append( "Spouse" ); + list.append( "Gender" ); + list.append( "Birthday" ); + list.append( "Anniversary" ); + list.append( "Nickname" ); + + list.append( "Children" ); + list.append( "Notes" ); + + return list; +} + +QStringList Contact::trfields() +{ + QStringList list; + + list.append( QObject::tr( "Name Title") ); + list.append( QObject::tr( "First Name" ) ); + list.append( QObject::tr( "Middle Name" ) ); + list.append( QObject::tr( "Last Name" ) ); + list.append( QObject::tr( "Suffix" ) ); + list.append( QObject::tr( "File As" ) ); + + list.append( QObject::tr( "Default Email" ) ); + list.append( QObject::tr( "Emails" ) ); + + list.append( QObject::tr( "Home Street" ) ); + list.append( QObject::tr( "Home City" ) ); + list.append( QObject::tr( "Home State" ) ); + list.append( QObject::tr( "Home Zip" ) ); + list.append( QObject::tr( "Home Country" ) ); + list.append( QObject::tr( "Home Phone" ) ); + list.append( QObject::tr( "Home Fax" ) ); + list.append( QObject::tr( "Home Mobile" ) ); + list.append( QObject::tr( "Home Web Page" ) ); + + list.append( QObject::tr( "Company" ) ); + list.append( QObject::tr( "Business Street" ) ); + list.append( QObject::tr( "Business City" ) ); + list.append( QObject::tr( "Business State" ) ); + list.append( QObject::tr( "Business Zip" ) ); + list.append( QObject::tr( "Business Country" ) ); + list.append( QObject::tr( "Business WebPage" ) ); + list.append( QObject::tr( "Job Title" ) ); + list.append( QObject::tr( "Department" ) ); + list.append( QObject::tr( "Office" ) ); + list.append( QObject::tr( "Business Phone" ) ); + list.append( QObject::tr( "Business Fax" ) ); + list.append( QObject::tr( "Business Mobile" ) ); + list.append( QObject::tr( "Business Pager" ) ); + list.append( QObject::tr( "Profession" ) ); + list.append( QObject::tr( "Assistant" ) ); + list.append( QObject::tr( "Manager" ) ); + + list.append( QObject::tr( "Spouse" ) ); + list.append( QObject::tr( "Gender" ) ); + list.append( QObject::tr( "Birthday" ) ); + list.append( QObject::tr( "Anniversary" ) ); + list.append( QObject::tr( "Nickname" ) ); + + list.append( QObject::tr( "Children" ) ); + list.append( QObject::tr( "Notes" ) ); + + return list; +} + +void Contact::setEmails( const QString &v ) +{ + replace( Qtopia::Emails, v ); + if ( v.isEmpty() ) + setDefaultEmail( QString::null ); +} + +void Contact::setChildren( const QString &v ) +{ + replace( Qtopia::Children, v ); +} + +// vcard conversion code +static inline VObject *safeAddPropValue( VObject *o, const char *prop, const QString &value ) +{ + VObject *ret = 0; + if ( o && !value.isEmpty() ) + ret = addPropValue( o, prop, value.latin1() ); + return ret; +} + +static inline VObject *safeAddProp( VObject *o, const char *prop) +{ + VObject *ret = 0; + if ( o ) + ret = addProp( o, prop ); + return ret; +} + +static VObject *createVObject( const Contact &c ) +{ + VObject *vcard = newVObject( VCCardProp ); + safeAddPropValue( vcard, VCVersionProp, "2.1" ); + safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) ); + safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) ); + + // full name + safeAddPropValue( vcard, VCFullNameProp, c.fullName() ); + + // name properties + VObject *name = safeAddProp( vcard, VCNameProp ); + safeAddPropValue( name, VCFamilyNameProp, c.lastName() ); + safeAddPropValue( name, VCGivenNameProp, c.firstName() ); + safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() ); + safeAddPropValue( name, VCNamePrefixesProp, c.title() ); + safeAddPropValue( name, VCNameSuffixesProp, c.suffix() ); + + // home properties + VObject *home_adr= safeAddProp( vcard, VCAdrProp ); + safeAddProp( home_adr, VCHomeProp ); + safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() ); + safeAddPropValue( home_adr, VCCityProp, c.homeCity() ); + safeAddPropValue( home_adr, VCRegionProp, c.homeState() ); + safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() ); + safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() ); + + VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() ); + safeAddProp( home_phone, VCHomeProp ); + home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() ); + safeAddProp( home_phone, VCHomeProp ); + safeAddProp( home_phone, VCCellularProp ); + home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() ); + safeAddProp( home_phone, VCHomeProp ); + safeAddProp( home_phone, VCFaxProp ); + + VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() ); + safeAddProp( url, VCHomeProp ); + + // work properties + VObject *work_adr= safeAddProp( vcard, VCAdrProp ); + safeAddProp( work_adr, VCWorkProp ); + safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() ); + safeAddPropValue( work_adr, VCCityProp, c.businessCity() ); + safeAddPropValue( work_adr, VCRegionProp, c.businessState() ); + safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() ); + safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() ); + + VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() ); + safeAddProp( work_phone, VCWorkProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCCellularProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCFaxProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCPagerProp ); + + url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() ); + safeAddProp( url, VCWorkProp ); + + VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() ); + safeAddProp( title, VCWorkProp ); + + + QStringList emails = c.emailList(); + emails.prepend( c.defaultEmail() ); + for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { + VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it ); + safeAddProp( email, VCInternetProp ); + } + + safeAddPropValue( vcard, VCNoteProp, c.notes() ); + + safeAddPropValue( vcard, VCBirthDateProp, c.birthday() ); + + if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) { + VObject *org = safeAddProp( vcard, VCOrgProp ); + safeAddPropValue( org, VCOrgNameProp, c.company() ); + safeAddPropValue( org, VCOrgUnitProp, c.department() ); + safeAddPropValue( org, VCOrgUnit2Prop, c.office() ); + } + + // some values we have to export as custom fields + safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() ); + safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() ); + safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() ); + + safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() ); + safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() ); + safeAddPropValue( vcard, "X-Qtopia-Anniversary", c.anniversary() ); + safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() ); + safeAddPropValue( vcard, "X-Qtopia-Children", c.children() ); + + return vcard; +} + + +static Contact parseVObject( VObject *obj ) +{ + Contact c; + + bool haveDefaultEmail = FALSE; + + VObjectIterator it; + initPropIterator( &it, obj ); + while( moreIteration( &it ) ) { + VObject *o = nextVObject( &it ); + QCString name = vObjectName( o ); + QCString value = vObjectStringZValue( o ); + if ( name == VCNameProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCNamePrefixesProp ) + c.setTitle( value ); + else if ( name == VCNameSuffixesProp ) + c.setSuffix( value ); + else if ( name == VCFamilyNameProp ) + c.setLastName( value ); + else if ( name == VCGivenNameProp ) + c.setFirstName( value ); + else if ( name == VCAdditionalNamesProp ) + c.setMiddleName( value ); + } + } + else if ( name == VCAdrProp ) { + bool work = TRUE; // default address is work address + QString street; + QString city; + QString region; + QString postal; + QString country; + + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCHomeProp ) + work = FALSE; + else if ( name == VCWorkProp ) + work = TRUE; + else if ( name == VCStreetAddressProp ) + street = value; + else if ( name == VCCityProp ) + city = value; + else if ( name == VCRegionProp ) + region = value; + else if ( name == VCPostalCodeProp ) + postal = value; + else if ( name == VCCountryNameProp ) + country = value; + } + if ( work ) { + c.setBusinessStreet( street ); + c.setBusinessCity( city ); + c.setBusinessCountry( country ); + c.setBusinessZip( postal ); + c.setBusinessState( region ); + } else { + c.setHomeStreet( street ); + c.setHomeCity( city ); + c.setHomeCountry( country ); + c.setHomeZip( postal ); + c.setHomeState( region ); + } + } + else if ( name == VCTelephoneProp ) { + enum { + HOME = 0x01, + WORK = 0x02, + VOICE = 0x04, + CELL = 0x08, + FAX = 0x10, + PAGER = 0x20, + UNKNOWN = 0x80 + }; + int type = 0; + + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + if ( name == VCHomeProp ) + type |= HOME; + else if ( name == VCWorkProp ) + type |= WORK; + else if ( name == VCVoiceProp ) + type |= VOICE; + else if ( name == VCCellularProp ) + type |= CELL; + else if ( name == VCFaxProp ) + type |= FAX; + else if ( name == VCPagerProp ) + type |= PAGER; + else if ( name == VCPreferredProp ) + ; + else + type |= UNKNOWN; + } + if ( (type & UNKNOWN) != UNKNOWN ) { + if ( ( type & (HOME|WORK) ) == 0 ) // default + type |= HOME; + if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default + type |= VOICE; + + if ( (type & (VOICE|HOME) ) == (VOICE|HOME) ) + c.setHomePhone( value ); + if ( ( type & (FAX|HOME) ) == (FAX|HOME) ) + c.setHomeFax( value ); + if ( ( type & (CELL|HOME) ) == (CELL|HOME) ) + c.setHomeMobile( value ); + if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) ) + c.setBusinessPhone( value ); + if ( ( type & (FAX|WORK) ) == (FAX|WORK) ) + c.setBusinessFax( value ); + if ( ( type & (CELL|WORK) ) == (CELL|WORK) ) + c.setBusinessMobile( value ); + if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) ) + c.setBusinessPager( value ); + } + } + else if ( name == VCEmailAddressProp ) { + QString email = vObjectStringZValue( o ); + bool valid = TRUE; + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + if ( name != VCInternetProp && name != VCHomeProp && + name != VCWorkProp && + name != VCPreferredProp ) + // ### preffered should map to default email + valid = FALSE; + } + if ( valid ) { + if ( haveDefaultEmail ) { + QString str = c.emails(); + if ( !str.isEmpty() ) + str += ","+email; + c.setEmails( str ); + } else { + c.setDefaultEmail( email ); + } + } + } + else if ( name == VCURLProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + if ( name == VCHomeProp ) + c.setHomeWebpage( value ); + else if ( name == VCWorkProp ) + c.setBusinessWebpage( value ); + } + } + else if ( name == VCOrgProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCOrgNameProp ) + c.setCompany( value ); + else if ( name == VCOrgUnitProp ) + c.setDepartment( value ); + else if ( name == VCOrgUnit2Prop ) + c.setOffice( value ); + } + } + else if ( name == VCTitleProp ) { + c.setJobTitle( value ); + } + else if ( name == "X-Qtopia-Profession" ) { + c.setProfession( value ); + } + else if ( name == "X-Qtopia-Manager" ) { + c.setManager( value ); + } + else if ( name == "X-Qtopia-Assistant" ) { + c.setAssistant( value ); + } + else if ( name == "X-Qtopia-Spouse" ) { + c.setSpouse( value ); + } + else if ( name == "X-Qtopia-Gender" ) { + c.setGender( value ); + } + else if ( name == "X-Qtopia-Anniversary" ) { + c.setAnniversary( value ); + } + else if ( name == "X-Qtopia-Nickname" ) { + c.setNickname( value ); + } + else if ( name == "X-Qtopia-Children" ) { + c.setChildren( value ); + } + + +#if 0 + else { + printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + printf(" subprop: %s = %s\n", name.data(), value.latin1() ); + } + } +#endif + } + c.setFileAs(); + return c; +} + +void Contact::writeVCard( const QString &filename, const QValueList<Contact> &contacts) +{
+ QFileDirect f( filename.utf8().data() );
+ if ( !f.open( IO_WriteOnly ) ) {
+ qWarning("Unable to open vcard write");
+ return;
+ }
+ + QValueList<Contact>::ConstIterator it; + for( it = contacts.begin(); it != contacts.end(); ++it ) { + VObject *obj = createVObject( *it ); + writeVObject(f.directHandle() , obj ); + cleanVObject( obj ); + } + cleanStrTbl(); +} + +void Contact::writeVCard( const QString &filename, const Contact &contact) +{
+ QFileDirect f( filename.utf8().data() );
+ if ( !f.open( IO_WriteOnly ) ) {
+ qWarning("Unable to open vcard write");
+ return;
+ }
+ + VObject *obj = createVObject( contact ); + writeVObject( f.directHandle() , obj ); + cleanVObject( obj ); + + cleanStrTbl(); +} + + +QValueList<Contact> Contact::readVCard( const QString &filename ) +{ + qDebug("trying to open %s, exists=%d", filename.utf8().data(), QFileInfo( filename.utf8().data() ).size() ); + VObject *obj = Parse_MIME_FromFileName( (char *)filename.utf8().data() ); + + qDebug("vobject = %p", obj ); + + QValueList<Contact> contacts; + + while ( obj ) { + contacts.append( parseVObject( obj ) ); + + VObject *t = obj; + obj = nextVObjectInList(obj); + cleanVObject( t ); + } + + return contacts; +} + +bool Contact::match( const QRegExp &r ) const +{ + bool match; + match = false; + QMap<int, QString>::ConstIterator it; + for ( it = mMap.begin(); it != mMap.end(); ++it ) { + if ( (*it).find( r ) > -1 ) { + match = true; + break; + } + } + return match; +} 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 @@ +/********************************************************************** +** Copyright (C) 2001 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef __CONTACT_H__ +#define __CONTACT_H__ + +#include <qpe/palmtoprecord.h> +#include <qpe/recordfields.h> + +#include <qstringlist.h> + +#if defined(QPC_TEMPLATEDLL) +// MOC_SKIP_BEGIN +template class QPC_EXPORT QMap<int, QString>; +// MOC_SKIP_END +#endif + +class ContactPrivate; +class QPC_EXPORT Contact : public Qtopia::Record +{ + friend class DataSet; +public: + Contact(); + Contact( const QMap<int, QString> &fromMap ); + virtual ~Contact(); + + static void writeVCard( const QString &filename, const QValueList<Contact> &contacts); + static void writeVCard( const QString &filename, const Contact &c ); + static QValueList<Contact> readVCard( const QString &filename ); + + enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; + + void setTitle( const QString &v ) { replace( Qtopia::Title, v ); } + void setFirstName( const QString &v ) { replace( Qtopia::FirstName, v ); } + void setMiddleName( const QString &v ) { replace( Qtopia::MiddleName, v ); } + void setLastName( const QString &v ) { replace( Qtopia::LastName, v ); } + void setSuffix( const QString &v ) { replace( Qtopia::Suffix, v ); } + void setFileAs( const QString &v ) { replace( Qtopia::FileAs, v ); } + void setFileAs(); + + // default email address + void setDefaultEmail( const QString &v ) { replace( Qtopia::DefaultEmail, v ); } + // the emails should be seperated by a semicolon + void setEmails( const QString &v ); + + // home + void setHomeStreet( const QString &v ) { replace( Qtopia::HomeStreet, v ); } + void setHomeCity( const QString &v ) { replace( Qtopia::HomeCity, v ); } + void setHomeState( const QString &v ) { replace( Qtopia::HomeState, v ); } + void setHomeZip( const QString &v ) { replace( Qtopia::HomeZip, v ); } + void setHomeCountry( const QString &v ) { replace( Qtopia::HomeCountry, v ); } + void setHomePhone( const QString &v ) { replace( Qtopia::HomePhone, v ); } + void setHomeFax( const QString &v ) { replace( Qtopia::HomeFax, v ); } + void setHomeMobile( const QString &v ) { replace( Qtopia::HomeMobile, v ); } + void setHomeWebpage( const QString &v ) { replace( Qtopia::HomeWebPage, v ); } + + // business + void setCompany( const QString &v ) { replace( Qtopia::Company, v ); } + void setBusinessStreet( const QString &v ) { replace( Qtopia::BusinessStreet, v ); } + void setBusinessCity( const QString &v ) { replace( Qtopia::BusinessCity, v ); } + void setBusinessState( const QString &v ) { replace( Qtopia::BusinessState, v ); } + void setBusinessZip( const QString &v ) { replace( Qtopia::BusinessZip, v ); } + void setBusinessCountry( const QString &v ) { replace( Qtopia::BusinessCountry, v ); } + void setBusinessWebpage( const QString &v ) { replace( Qtopia::BusinessWebPage, v ); } + void setJobTitle( const QString &v ) { replace( Qtopia::JobTitle, v ); } + void setDepartment( const QString &v ) { replace( Qtopia::Department, v ); } + void setOffice( const QString &v ) { replace( Qtopia::Office, v ); } + void setBusinessPhone( const QString &v ) { replace( Qtopia::BusinessPhone, v ); } + void setBusinessFax( const QString &v ) { replace( Qtopia::BusinessFax, v ); } + void setBusinessMobile( const QString &v ) { replace( Qtopia::BusinessMobile, v ); } + void setBusinessPager( const QString &v ) { replace( Qtopia::BusinessPager, v ); } + void setProfession( const QString &v ) { replace( Qtopia::Profession, v ); } + void setAssistant( const QString &v ) { replace( Qtopia::Assistant, v ); } + void setManager( const QString &v ) { replace( Qtopia::Manager, v ); } + + // personal + void setSpouse( const QString &v ) { replace( Qtopia::Spouse, v ); } + void setGender( const QString &v ) { replace( Qtopia::Gender, v ); } + void setBirthday( const QString &v ) { replace( Qtopia::Birthday, v ); } + void setAnniversary( const QString &v ) { replace( Qtopia::Anniversary, v ); } + void setNickname( const QString &v ) { replace( Qtopia::Nickname, v ); } + void setChildren( const QString &v ); + + // other + void setNotes( const QString &v ) { replace( Qtopia::Notes, v); } + + bool match( const QRegExp &r ) const; + +// // custom +// void setCustomField( const QString &key, const QString &v ) +// { replace(Custom- + key, v ); } + + // name + QString fullName() const; + QString title() const { return find( Qtopia::Title ); } + QString firstName() const { return find( Qtopia::FirstName ); } + QString middleName() const { return find( Qtopia::MiddleName ); } + QString lastName() const { return find( Qtopia::LastName ); } + QString suffix() const { return find( Qtopia::Suffix ); } + QString fileAs() const { return find( Qtopia::FileAs ); } + + // email + QString defaultEmail() const { return find( Qtopia::DefaultEmail ); } + QString emails() const { return find( Qtopia::Emails ); } + QStringList emailList() const; + + // home + QString homeStreet() const { return find( Qtopia::HomeStreet ); } + QString homeCity() const { return find( Qtopia::HomeCity ); } + QString homeState() const { return find( Qtopia::HomeState ); } + QString homeZip() const { return find( Qtopia::HomeZip ); } + QString homeCountry() const { return find( Qtopia::HomeCountry ); } + QString homePhone() const { return find( Qtopia::HomePhone ); } + QString homeFax() const { return find( Qtopia::HomeFax ); } + QString homeMobile() const { return find( Qtopia::HomeMobile ); } + QString homeWebpage() const { return find( Qtopia::HomeWebPage ); } + /** Multi line string containing all non-empty address info in the form + * Street + * City, State Zip + * Country + */ + QString displayHomeAddress() const; + + // business + QString company() const { return find( Qtopia::Company ); } + QString businessStreet() const { return find( Qtopia::BusinessStreet ); } + QString businessCity() const { return find( Qtopia::BusinessCity ); } + QString businessState() const { return find( Qtopia::BusinessState ); } + QString businessZip() const { return find( Qtopia::BusinessZip ); } + QString businessCountry() const { return find( Qtopia::BusinessCountry ); } + QString businessWebpage() const { return find( Qtopia::BusinessWebPage ); } + QString jobTitle() const { return find( Qtopia::JobTitle ); } + QString department() const { return find( Qtopia::Department ); } + QString office() const { return find( Qtopia::Office ); } + QString businessPhone() const { return find( Qtopia::BusinessPhone ); } + QString businessFax() const { return find( Qtopia::BusinessFax ); } + QString businessMobile() const { return find( Qtopia::BusinessMobile ); } + QString businessPager() const { return find( Qtopia::BusinessPager ); } + QString profession() const { return find( Qtopia::Profession ); } + QString assistant() const { return find( Qtopia::Assistant ); } + QString manager() const { return find( Qtopia::Manager ); } + /** Multi line string containing all non-empty address info in the form + * Street + * City, State Zip + * Country + */ + QString displayBusinessAddress() const; + + //personal + QString spouse() const { return find( Qtopia::Spouse ); } + QString gender() const { return find( Qtopia::Gender ); } + QString birthday() const { return find( Qtopia::Birthday ); } + QString anniversary() const { return find( Qtopia::Anniversary ); } + QString nickname() const { return find( Qtopia::Nickname ); } + QString children() const { return find( Qtopia::Children ); } + QStringList childrenList() const; + + // other + QString notes() const { return find( Qtopia::Notes ); } + QString groups() const { return find( Qtopia::Groups ); } + QStringList groupList() const; + +// // custom +// const QString &customField( const QString &key ) +// { return find( Custom- + key ); } + + static QStringList fields(); + static QStringList trfields(); + + QString toRichText() const; + QMap<int, QString> toMap() const; + QString field( int key ) const { return find( key ); } + + + // journaling... + void saveJournal( journal_action action, const QString &key = QString::null ); + void save( QString &buf ) const; + + void setUid( int i ) +{ Record::setUid(i); replace( Qtopia::AddressUid , QString::number(i)); } + +private: + friend class AbTable; + void insert( int key, const QString &value ); + void replace( int key, const QString &value ); + QString find( int key ) const; + + QString displayAddress( const QString &street, + const QString &city, + const QString &state, + const QString &zip, + const QString &country ) const; + + Qtopia::UidGen &uidGen() { return sUidGen; } + static Qtopia::UidGen sUidGen; + QMap<int, QString> mMap; + ContactPrivate *d; +}; + +#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 @@ +/********************************************************************** +** Copyright (C) 2001 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "event.h"
+#include "qfiledirect_p.h" +#include <qpe/timeconversion.h> +#include <qpe/stringutil.h> +#include <qpe/recordfields.h> +#include <qbuffer.h> +#include <time.h> +#include "vobject_p.h" + +#include <stdio.h> + +using namespace Qtopia; + +static void write( QString& buf, const Event::RepeatPattern &r ) +{ + buf += " rtype=\""; + switch ( r.type ) { + case Event::Daily: + buf += "Daily"; + break; + case Event::Weekly: + buf += "Weekly"; + break; + case Event::MonthlyDay: + buf += "MonthlyDay"; + break; + case Event::MonthlyDate: + buf += "MonthlyDate"; + break; + case Event::Yearly: + buf += "Yearly"; + break; + default: + buf += "NoRepeat"; + break; + } + buf += "\""; + if ( r.days > 0 ) + buf += " rweekdays=\"" + QString::number( static_cast<int>( r.days ) ) + "\""; + if ( r.position != 0 ) + buf += " rposition=\"" + QString::number( r.position ) + "\""; + + buf += " rfreq=\"" + QString::number( r.frequency ) + "\""; + buf += " rhasenddate=\"" + QString::number( static_cast<int>( r.hasEndDate ) ) + "\""; + if ( r.hasEndDate ) + buf += " enddt=\"" + + QString::number( r.endDateUTC ? r.endDateUTC : time( 0 ) ) + + "\""; + buf += " created=\"" + QString::number( r.createTime ) + "\""; +} + +Qtopia::UidGen Event::sUidGen( Qtopia::UidGen::Qtopia ); + +Event::Event() : Record() +{ + startUTC = endUTC = time( 0 ); + typ = Normal; + hAlarm = FALSE; + hRepeat = FALSE; + aMinutes = 0; + aSound = Silent; + pattern.type = NoRepeat; + pattern.frequency = -1; +} + +Event::Event( const QMap<int, QString> &map ) +{ + setDescription( map[DatebookDescription] ); + setLocation( map[Location] ); + setCategories( idsFromString( map[DatebookCategory] ) ); + setTimeZone( map[TimeZone] ); + setNotes( map[Note] ); + setStart( TimeConversion::fromUTC( map[StartDateTime].toUInt() ) ); + setEnd( TimeConversion::fromUTC( map[EndDateTime].toUInt() ) ); + setType( (Event::Type) map[DatebookType].toInt() ); + setAlarm( ( map[HasAlarm] == "1" ? TRUE : FALSE ), map[AlarmTime].toInt(), (Event::SoundTypeChoice)map[SoundType].toInt() ); + Event::RepeatPattern p; + p.type = (Event::RepeatType) map[ RepeatPatternType ].toInt(); + p.frequency = map[ RepeatPatternFrequency ].toInt(); + p.position = map[ RepeatPatternPosition ].toInt(); + p.days = map[ RepeatPatternDays ].toInt(); + p.hasEndDate = map[ RepeatPatternHasEndDate ].toInt(); + p.endDateUTC = map[ RepeatPatternEndDate ].toUInt(); + setRepeat( p ); + + setUid( map[ DatebookUid ].toInt() ); +} + +Event::~Event() +{ +} + +int Event::week( const QDate& date ) +{ + // Calculates the week this date is in within that + // month. Equals the "row" is is in in the month view + int week = 1; + QDate tmp( date.year(), date.month(), 1 ); + + if ( date.dayOfWeek() < tmp.dayOfWeek() ) + ++week; + + week += ( date.day() - 1 ) / 7; + return week; +} + +int Event::occurrence( const QDate& date ) +{ + // calculates the number of occurrances of this day of the + // week till the given date (e.g 3rd Wednesday of the month) + return ( date.day() - 1 ) / 7 + 1; +} + +int Event::dayOfWeek( char day ) +{ + int dayOfWeek = 1; + char i = Event::MON; + while ( !( i & day ) && i <= Event::SUN ) { + i <<= 1; + ++dayOfWeek; + } + return dayOfWeek; +} + +int Event::monthDiff( const QDate& first, const QDate& second ) +{ + return ( second.year() - first.year() ) * 12 + + second.month() - first.month(); +} + +QMap<int, QString> Event::toMap() const +{ + QMap<int, QString> m; + m.insert( DatebookDescription, description() ); + m.insert ( Location, location() ); + m.insert ( DatebookCategory, idsToString( categories() ) ); + m.insert ( TimeZone, timeZone() ); + m.insert ( Note, notes() ); + m.insert ( StartDateTime, QString::number( TimeConversion::toUTC( start() ) ) ); + m.insert ( EndDateTime, QString::number( TimeConversion::toUTC( end() ) ) ); + m.insert ( DatebookType, QString::number( (int)type() ) ); + m.insert ( HasAlarm, ( hasAlarm() ? "1" : "0" ) ); + m.insert ( SoundType, QString::number( (int)alarmSound() ) ); + m.insert ( AlarmTime, QString::number( alarmTime() ) ); + m.insert ( RepeatPatternType, QString::number( static_cast<int>( repeatPattern().type ) ) ); + m.insert ( RepeatPatternFrequency, QString::number( repeatPattern().frequency ) ); + m.insert ( RepeatPatternPosition, QString::number( repeatPattern().position ) ); + m.insert ( RepeatPatternDays, QString::number( repeatPattern().days ) ); + m.insert ( RepeatPatternHasEndDate, QString::number( static_cast<int>( repeatPattern().hasEndDate ) ) ); + m.insert ( RepeatPatternEndDate, QString::number( repeatPattern().endDateUTC ) ); + + m.insert( DatebookUid, QString::number( uid()) ); + + return m; +} + +void Event::setRepeat( const RepeatPattern &p ) +{ + setRepeat( p.type != NoRepeat, p ); +} + +void Event::setDescription( const QString &s ) +{ + descript = s; +} + +void Event::setLocation( const QString &s ) +{ + locat = s; +} + +// void Event::setCategory( const QString &s ) +// { +// categ = s; +// } + +void Event::setType( Type t ) +{ + typ = t; +} + +void Event::setStart( const QDateTime &d ) +{ + startUTC = TimeConversion::toUTC( d ); +} + +void Event::setStart( time_t time ) +{ + startUTC = time; +} + +void Event::setEnd( const QDateTime &d ) +{ + endUTC = TimeConversion::toUTC( d ); +} + +void Event::setEnd( time_t time ) +{ + endUTC = time; +} + +void Event::setTimeZone( const QString &z ) +{ + tz = z; +} + +void Event::setAlarm( bool b, int minutes, SoundTypeChoice s ) +{ + hAlarm = b; + aMinutes = minutes; + aSound = s; +} + +void Event::setRepeat( bool b, const RepeatPattern &p ) +{ + hRepeat = b; + pattern = p; +} + +void Event::setNotes( const QString &n ) +{ + note = n; +} + +const QString &Event::description() const +{ + return descript; +} + +const QString &Event::location() const +{ + return locat; +} + +// QString Event::category() const +// { +// return categ; +// } + +Event::Type Event::type() const +{ + return typ; +} + +QDateTime Event::start( bool actual ) const +{ + QDateTime dt = (startUTC > 0) ? TimeConversion::fromUTC( startUTC ) : QDateTime::currentDateTime(); + + if ( actual && typ == AllDay ) { + QTime t = dt.time(); + t.setHMS( 0, 0, 0 ); + dt.setTime( t ); + } + return dt; +} + +QDateTime Event::end( bool actual ) const +{ + QDateTime dt = (endUTC > 0) ? TimeConversion::fromUTC( endUTC ) : QDateTime::currentDateTime(); + + if ( actual && typ == AllDay ) { + QTime t = dt.time(); + t.setHMS( 23, 59, 59 ); + dt.setTime( t ); + } + return dt; +} + +const QString &Event::timeZone() const +{ + return tz; +} + +bool Event::hasAlarm() const +{ + return hAlarm; +} + +int Event::alarmTime() const +{ + return aMinutes; +} + +Event::SoundTypeChoice Event::alarmSound() const +{ + return aSound; +} + +bool Event::hasRepeat() const +{ + return doRepeat(); +} + +const Event::RepeatPattern &Event::repeatPattern() const +{ + return pattern; +} + +Event::RepeatPattern &Event::repeatPattern() +{ + return pattern; +} + +const QString &Event::notes() const +{ + return note; +} + +bool Event::operator==( const Event &e ) const +{ + return ( e.descript == descript && + e.locat == locat && + e.categ == categ && + e.typ == typ && + e.startUTC == startUTC && + e.endUTC == endUTC && + e.tz == tz && + e.hAlarm == hAlarm && + e.aMinutes == aMinutes && + e.aSound == aSound && + e.hRepeat == hRepeat && + e.pattern == pattern && + e.note == note ); +} + +void Event::save( QString& buf ) +{ + buf += " description=\"" + Qtopia::escapeString(descript) + "\""; + if ( !locat.isEmpty() ) + buf += " location=\"" + Qtopia::escapeString(locat) + "\""; + // save the categoies differently.... + QString strCats = idsToString( categories() ); + buf += " categories=\"" + Qtopia::escapeString(strCats) + "\""; + buf += " uid=\"" + QString::number( uid() ) + "\""; + if ( (Type)typ != Normal ) + buf += " type=\"AllDay\""; + if ( hAlarm ) { + buf += " alarm=\"" + QString::number( aMinutes ) + "\" sound=\""; + if ( aSound == Event::Loud ) + buf += "loud"; + else + buf += "silent"; + buf += "\""; + } + if ( hRepeat ) + write( buf, pattern ); + + buf += " start=\"" + + QString::number( startUTC ) + + "\""; + + buf += " end=\"" + + QString::number( endUTC ) + + "\""; + + if ( !note.isEmpty() ) + buf += " note=\"" + Qtopia::escapeString( note ) + "\""; + buf += customToXml(); +} + +bool Event::RepeatPattern::operator==( const Event::RepeatPattern &right ) const +{ + // *sigh* + return ( type == right.type + && frequency == right.frequency + && position == right.position + && days == right.days + && hasEndDate == right.hasEndDate + && endDateUTC == right.endDateUTC + && createTime == right.createTime ); +} + + +class EffectiveEventPrivate +{ +public: + //currently the existence of the d pointer means multi-day repeating, + //msut be changed if we use the d pointer for anything else. + QDate startDate; + QDate endDate; +}; + + +EffectiveEvent::EffectiveEvent() +{ + mDate = QDate::currentDate(); + mStart = mEnd = QTime::currentTime(); + d = 0; +} + +EffectiveEvent::EffectiveEvent( const Event &e, const QDate &date, Position pos ) +{ + mEvent = e; + mDate = date; + if ( pos & Start ) + mStart = e.start( TRUE ).time(); + else + mStart = QTime( 0, 0, 0 ); + + if ( pos & End ) + mEnd = e.end( TRUE ).time(); + else + mEnd = QTime( 23, 59, 59 ); + d = 0; +} + +EffectiveEvent::~EffectiveEvent() +{ + delete d; +} + +EffectiveEvent::EffectiveEvent( const EffectiveEvent &e ) +{ + d = 0; + *this = e; +} + +EffectiveEvent& EffectiveEvent::operator=( const EffectiveEvent & e ) +{ + if ( &e == this ) + return *this; + delete d; + if ( e.d ) { + d = new EffectiveEventPrivate; + d->startDate = e.d->startDate; + d->endDate = e.d->endDate; + } else { + d = 0; + } + mEvent = e.mEvent; + mDate = e.mDate; + mStart = e.mStart; + mEnd = e.mEnd; + + return *this; + +} + +// QString EffectiveEvent::category() const +// { +// return mEvent.category(); +// } + +const QString &EffectiveEvent::description( ) const +{ + return mEvent.description(); +} + +const QString &EffectiveEvent::location( ) const +{ + return mEvent.location(); +} + +const QString &EffectiveEvent::notes() const +{ + return mEvent.notes(); +} + +const Event &EffectiveEvent::event() const +{ + return mEvent; +} + +const QTime &EffectiveEvent::end() const +{ + return mEnd; +} + +const QTime &EffectiveEvent::start() const +{ + return mStart; +} + +const QDate &EffectiveEvent::date() const +{ + return mDate; +} + +int EffectiveEvent::length() const +{ + return (mEnd.hour() * 60 - mStart.hour() * 60) + + QABS(mStart.minute() - mEnd.minute() ); +} + +void EffectiveEvent::setDate( const QDate &dt ) +{ + mDate = dt; +} + +void EffectiveEvent::setStart( const QTime &start ) +{ + mStart = start; +} + +void EffectiveEvent::setEnd( const QTime &end ) +{ + mEnd = end; +} + +void EffectiveEvent::setEvent( Event e ) +{ + mEvent = e; +} + +bool EffectiveEvent::operator<( const EffectiveEvent &e ) const +{ + if ( mDate < e.date() ) + return TRUE; + if ( mDate == e.date() ) + return ( mStart < e.start() ); + else + return FALSE; +} + +bool EffectiveEvent::operator<=( const EffectiveEvent &e ) const +{ + return (mDate <= e.date() ); +} + +bool EffectiveEvent::operator==( const EffectiveEvent &e ) const +{ + return ( mDate == e.date() + && mStart == e.start() + && mEnd == e.end() + && mEvent == e.event() ); +} + +bool EffectiveEvent::operator!=( const EffectiveEvent &e ) const +{ + return !(*this == e); +} + +bool EffectiveEvent::operator>( const EffectiveEvent &e ) const +{ + return !(*this <= e ); +} + +bool EffectiveEvent::operator>=(const EffectiveEvent &e) const +{ + return !(*this < e); +} + +void EffectiveEvent::setEffectiveDates( const QDate &from, const QDate &to ) +{ + if ( !from.isValid() ) { + delete d; + d = 0; + return; + } + if ( !d ) + d = new EffectiveEventPrivate; + d->startDate = from; + d->endDate = to; +} + +QDate EffectiveEvent::startDate() const +{ + if ( d ) + return d->startDate; + else if ( mEvent.hasRepeat() ) + return mDate; // single day, since multi-day should have a d pointer + else + return mEvent.start().date(); +} + +QDate EffectiveEvent::endDate() const +{ + if ( d ) + return d->endDate; + else if ( mEvent.hasRepeat() ) + return mDate; // single day, since multi-day should have a d pointer + else + return mEvent.end().date(); +} + +int EffectiveEvent::size() const +{ + return ( mEnd.hour() - mStart.hour() ) * 3600 + + (mEnd.minute() - mStart.minute() * 60 + + mEnd.second() - mStart.second() ); +} + + +// vcal conversion code +static inline VObject *safeAddPropValue( VObject *o, const char *prop, const QString &value ) +{ + VObject *ret = 0; + if ( o && !value.isEmpty() ) + ret = addPropValue( o, prop, value.latin1() ); + return ret; +} + +static inline VObject *safeAddProp( VObject *o, const char *prop) +{ + VObject *ret = 0; + if ( o ) + ret = addProp( o, prop ); + return ret; +} + +static VObject *createVObject( const Event &e ) +{ + VObject *vcal = newVObject( VCCalProp ); + safeAddPropValue( vcal, VCVersionProp, "1.0" ); + VObject *event = safeAddProp( vcal, VCEventProp ); + + safeAddPropValue( event, VCDTstartProp, TimeConversion::toISO8601( e.start() ) ); + safeAddPropValue( event, VCDTendProp, TimeConversion::toISO8601( e.end() ) ); + safeAddPropValue( event, "X-Qtopia-NOTES", e.description() ); + safeAddPropValue( event, VCDescriptionProp, e.description() ); + safeAddPropValue( event, VCLocationProp, e.location() ); + + if ( e.hasAlarm() ) { + VObject *alarm = safeAddProp( event, VCAAlarmProp ); + QDateTime dt = e.start(); + dt = dt.addSecs( -e.alarmTime()*60 ); + safeAddPropValue( alarm, VCRunTimeProp, TimeConversion::toISO8601( dt ) ); + safeAddPropValue( alarm, VCAudioContentProp, + (e.alarmSound() == Event::Silent ? "silent" : "alarm" ) ); + } + + safeAddPropValue( event, "X-Qtopia-TIMEZONE", e.timeZone() ); + + if ( e.type() == Event::AllDay ) + safeAddPropValue( event, "X-Qtopia-AllDay", e.timeZone() ); + + // ### repeat missing + + // ### categories missing + + return vcal; +} + + +static Event parseVObject( VObject *obj ) +{ + Event e; + + bool haveAlarm = FALSE; + bool haveStart = FALSE; + bool haveEnd = FALSE; + QDateTime alarmTime; + Event::SoundTypeChoice soundType = Event::Silent; + + VObjectIterator it; + initPropIterator( &it, obj ); + while( moreIteration( &it ) ) { + VObject *o = nextVObject( &it ); + QCString name = vObjectName( o ); + QCString value = vObjectStringZValue( o ); + if ( name == VCDTstartProp ) { + e.setStart( TimeConversion::fromISO8601( value ) ); + haveStart = TRUE; + } + else if ( name == VCDTendProp ) { + e.setEnd( TimeConversion::fromISO8601( value ) ); + haveEnd = TRUE; + } + else if ( name == "X-Qtopia-NOTES" ) { + e.setNotes( value ); + } + else if ( name == VCDescriptionProp ) { + e.setDescription( value ); + } + else if ( name == VCLocationProp ) { + e.setLocation( value ); + } + else if ( name == VCAudioContentProp ) { + haveAlarm = TRUE; + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QCString value = vObjectStringZValue( o ); + if ( name == VCRunTimeProp ) + alarmTime = TimeConversion::fromISO8601( value ); + else if ( name == VCAudioContentProp ) { + if ( value == "silent" ) + soundType = Event::Silent; + else + soundType = Event::Loud; + } + } + } + else if ( name == "X-Qtopia-TIMEZONE") { + e.setTimeZone( value ); + } + else if ( name == "X-Qtopia-AllDay" ) { + e.setType( Event::AllDay ); + } +#if 0 + else { + printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + printf(" subprop: %s = %s\n", name.data(), value.latin1() ); + } + } +#endif + } + + if ( !haveStart && !haveEnd ) + e.setStart( QDateTime::currentDateTime() ); + + if ( !haveEnd ) { + e.setType( Event::AllDay ); + e.setEnd( e.start() ); + } + + if ( haveAlarm ) { + int minutes = alarmTime.secsTo( e.start() ) / 60; + e.setAlarm( TRUE, minutes, soundType ); + } + return e; +} + + + +void Event::writeVCalendar( const QString &filename, const QValueList<Event> &events) +{
+ QFileDirect f( filename.utf8().data() );
+ if ( !f.open( IO_WriteOnly ) ) {
+ qWarning("Unable to open vcard write");
+ return;
+ }
+ + QValueList<Event>::ConstIterator it; + for( it = events.begin(); it != events.end(); ++it ) { + VObject *obj = createVObject( *it ); + writeVObject( f.directHandle() , obj ); + cleanVObject( obj ); + }
+ + cleanStrTbl(); +} + +void Event::writeVCalendar( const QString &filename, const Event &event) +{
+ QFileDirect f( filename.utf8().data() );
+ if ( !f.open( IO_WriteOnly ) ) {
+ qWarning("Unable to open vcard write");
+ return;
+ }
+ + VObject *obj = createVObject( event ); + writeVObject( f.directHandle() , obj ); + cleanVObject( obj ); + + cleanStrTbl(); +} + + +QValueList<Event> Event::readVCalendar( const QString &filename ) +{ + VObject *obj = Parse_MIME_FromFileName( (char *)filename.utf8().data() ); + + QValueList<Event> events; + + while ( obj ) { + QCString name = vObjectName( obj ); + if ( name == VCCalProp ) { + VObjectIterator nit; + initPropIterator( &nit, obj ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + if ( name == VCEventProp ) + events.append( parseVObject( o ) ); + } + } else if ( name == VCEventProp ) { + // shouldn't happen, but just to be sure + events.append( parseVObject( obj ) ); + } + VObject *t = obj; + obj = nextVObjectInList(obj); + cleanVObject( t ); + } + + return events; +} + +bool Event::match( const QRegExp &r ) const +{ + bool returnMe; + returnMe = false; + + if ( descript.find( r ) > -1 ) + returnMe = true; + else if ( locat.find( r ) > -1 ) + returnMe = true; + else if ( TimeConversion::fromUTC( startUTC ).toString().find( r ) > -1 ) + returnMe = true; + else if ( TimeConversion::fromUTC( endUTC ).toString().find( r ) > -1 ) + returnMe = true; + else if ( tz.find( r ) > -1 ) + returnMe = true; + else if ( note.find( r ) > -1 ) + returnMe = true; + else if ( doRepeat() ) { + if ( pattern.hasEndDate ) + if ( TimeConversion::fromUTC( pattern.endDateUTC ).toString().find(r) > -1 ) + returnMe = true; + } + return returnMe; +} 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 @@ +/********************************************************************** +** Copyright (C) 2001 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef __EVENT_H__ +#define __EVENT_H__ + +#include <qdatetime.h> +#include <qvaluelist.h> + +#ifdef PALMTOPCENTER +#include <qpc/qsorter.h> +#endif +#include <qpe/palmtoprecord.h> + +#include <qpe/timeconversion.h> + +class EventPrivate; +class QPC_EXPORT Event : public Qtopia::Record +{ +public: + enum RepeatType { NoRepeat = -1, Daily, Weekly, MonthlyDay, + MonthlyDate, Yearly }; + enum Days { MON = 0x01, TUE = 0x02, WED = 0x04, THU = 0x08, + FRI = 0x10, SAT = 0x20, SUN = 0x40 }; + struct QPC_EXPORT RepeatPattern + { + RepeatPattern() { + type = NoRepeat; frequency = -1; days = 0; position = 0; createTime = -1; + hasEndDate = FALSE; endDateUTC = 0; } + bool operator ==( const RepeatPattern &right ) const; + + RepeatType type; + int frequency; + int position; // the posistion in the month (e.g. the first sunday, etc) positive, count from the front negative count from the end... + char days; // a mask for days OR in your days! + bool hasEndDate; + QDate endDate() const { return TimeConversion::fromUTC( endDateUTC ).date(); } + void setEndDate( const QDate &dt ) { endDateUTC = TimeConversion::toUTC( dt ); } + time_t endDateUTC; + time_t createTime; + }; + + Event(); + Event( const QMap<int, QString > & map ); + virtual ~Event(); + + QMap<int, QString> toMap() const; + + static void writeVCalendar( const QString &filename, const QValueList<Event> &events); + static void writeVCalendar( const QString &filename, const Event &event); + static QValueList<Event> readVCalendar( const QString &filename ); + + enum Type { Normal, AllDay }; + enum SoundTypeChoice { Silent, Loud }; + + bool operator<( const Event &e1) const { return start() < e1.start(); }; + bool operator<=( const Event &e1 ) const { return start() <= e1.start(); }; + bool operator!=( const Event &e1 ) const { return !( *this == e1 ); }; + bool operator>( const Event &e1 ) const { return start() > e1.start(); }; + bool operator>=(const Event &e1 ) const { return start() >= e1.start(); }; + bool operator==( const Event &e ) const; + + void setDescription( const QString &s ); + const QString &description() const; + + void setLocation( const QString &s ); + const QString &location() const; + + void setType( Type t ); + Type type() const; + void setStart( const QDateTime &d ); + void setStart( time_t time ); + QDateTime start( bool actual = FALSE ) const; + time_t startTime() const { return startUTC; } + void setEnd( const QDateTime &e ); + void setEnd( time_t time ); + QDateTime end( bool actual = FALSE ) const; + time_t endTime() const { return endUTC; } + void setTimeZone( const QString & ); + const QString &timeZone() const; + void setAlarm( bool b, int minutes, SoundTypeChoice ); + bool hasAlarm() const; + int alarmTime() const; + SoundTypeChoice alarmSound() const; + void setRepeat( bool b, const RepeatPattern &p ); + void setRepeat( const RepeatPattern &p ); + bool hasRepeat() const; + const RepeatPattern &repeatPattern() const; + RepeatPattern &repeatPattern(); + void setNotes( const QString &n ); + const QString ¬es() const; + bool doRepeat() const { return pattern.type != NoRepeat; } + + void save( QString& buf ); + //void load( Node *n ); + + // helper function to calculate the week of the given date + static int week( const QDate& date ); + // calculates the number of occurrences of the week day of + // the given date from the start of the month + static int occurrence( const QDate& date ); + // returns a proper days-char for a given dayOfWeek() + static char day( int dayOfWeek ) { return 1 << ( dayOfWeek - 1 ); } + // returns the dayOfWeek for the *first* day it finds (ignores + // any further days!). Returns 1 (Monday) if there isn't any day found + static int dayOfWeek( char day ); + // returns the difference of months from first to second. + static int monthDiff( const QDate& first, const QDate& second ); + bool match( const QRegExp &r ) const; + +private: + Qtopia::UidGen &uidGen() { return sUidGen; } + static Qtopia::UidGen sUidGen; + + QString descript, locat, categ; + Type typ : 4; + bool startTimeDirty : 1; + bool endTimeDirty : 1; + time_t startUTC, endUTC; + QString tz; + bool hAlarm, hRepeat; + int aMinutes; + SoundTypeChoice aSound; + RepeatPattern pattern; + QString note; + EventPrivate *d; +}; + +// Since an event spans multiple day, it is better to have this +// class to represent a day instead of creating many +// dummy events... + +class EffectiveEventPrivate; +class QPC_EXPORT EffectiveEvent +{ +public: + // If we calculate the effective event of a multi-day event + // we have to figure out whether we are at the first day, + // at the end, or anywhere else ("middle"). This is important + // for the start/end times (00:00/23:59) + // MidWay: 00:00 -> 23:59, as we are "in the middle" of a multi- + // day event + // Start: start time -> 23:59 + // End: 00:00 -> end time + // Start | End == StartEnd: for single-day events (default) + // here we draw start time -> end time + enum Position { MidWay = 0, Start = 1, End = 2, StartEnd = 3 }; + + EffectiveEvent(); + EffectiveEvent( const Event &event, const QDate &startDate, Position pos = StartEnd ); + EffectiveEvent( const EffectiveEvent & ); + EffectiveEvent& operator=( const EffectiveEvent & ); + ~EffectiveEvent(); + + + bool operator<( const EffectiveEvent &e ) const; + bool operator<=( const EffectiveEvent &e ) const; + bool operator==( const EffectiveEvent &e ) const; + bool operator!=( const EffectiveEvent &e ) const; + bool operator>( const EffectiveEvent &e ) const; + bool operator>= ( const EffectiveEvent &e ) const; + + void setStart( const QTime &start ); + void setEnd( const QTime &end ); + void setEvent( Event e ); + void setDate( const QDate &date ); + void setEffectiveDates( const QDate &from, const QDate &to ); + + // QString category() const; + const QString &description() const; + const QString &location() const; + const QString ¬es() const; + const Event &event() const; + const QTime &start() const; + const QTime &end() const; + const QDate &date() const; + int length() const; + int size() const; + + QDate startDate() const; + QDate endDate() const; + +private: + class EffectiveEventPrivate *d; + Event mEvent; + QDate mDate; + QTime mStart, + mEnd; + +}; + +#ifdef PALMTOPCENTER +class QPC_EXPORT EffectiveEventSizeSorter : public QSorter<EffectiveEvent> +{ +public: + int compare( const EffectiveEvent& a, const EffectiveEvent& b ) const + { + return a.size() - b.size(); + } +}; + +class QPC_EXPORT EffectiveEventTimeSorter : public QSorter<EffectiveEvent> +{ +public: + int compare( const EffectiveEvent& a, const EffectiveEvent& b ) const + { + return a.start().secsTo( b.start() ); + } +}; +#endif + +#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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included +** in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A +** PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include "palmtoprecord.h" +#include "stringutil.h" +#include <qstringlist.h> + +namespace Qtopia { + +Record &Record::operator=( const Record &c ) +{ + mUid = c.mUid; + mCats = c.mCats; + customMap = c.customMap; + return *this; +} + +void Record::setCategories( int single ) +{ + if ( single == 0 ) + return; + mCats.resize(1); + mCats[0] = single; +} + +// convenience methods provided for loading and saving to xml +QString Record::idsToString( const QArray<int> &cats ) +{ + QString str; + for ( uint i = 0; i < cats.size(); i++ ) + if ( i == 0 ) + str = QString::number( cats[int(i)] ); + else + str += ";" + QString::number( cats[int(i)] ); + + return str; +} + +// convenience methods provided for loading and saving to xml +QArray<int> Record::idsFromString( const QString &str ) +{ + QStringList catStrs = QStringList::split( ";", str ); + QArray<int> cats( catStrs.count() ); + uint i = 0; + for ( QStringList::ConstIterator it = catStrs.begin(); + it != catStrs.end(); ++it ) { + cats[int(i)] = (*it).toInt(); + i++; + } + return cats; +} + +/*! + Returns the string stored for the custom field \a key. + Returns a null string if the field does not exist. + */ +QString Record::customField( const QString &key) const +{ + if (customMap.contains(key)) + return customMap[key]; + + return QString::null; +} + +/*! + Sets the string stored for the custom field \a key to \a value. + */ +void Record::setCustomField( const QString &key, const QString &value) +{ + qWarning("setting custom " + key + " to " + value); + if (customMap.contains(key)) + customMap.replace(key, value); + else + customMap.insert(key, value); + + qWarning(QString("custom size %1").arg(customMap.count())); +} + +/*! + Removes the custom field \a key. + */ +void Record::removeCustomField(const QString &key) +{ + customMap.remove(key); +} + +QString Record::customToXml() const +{ + //qWarning(QString("writing custom %1").arg(customMap.count())); + QString buf(" "); + for ( QMap<QString, QString>::ConstIterator cit = customMap.begin(); + cit != customMap.end(); ++cit) { + qWarning(".ITEM."); + buf += cit.key(); + buf += "=\""; + buf += escapeString(cit.data()); + buf += "\" "; + } + return buf; +} + +void Record::dump( const QMap<int, QString> &map ) +{ + QMap<int, QString>::ConstIterator it; + for( it = map.begin(); it != map.end(); ++it ) + qDebug("%d : %s", it.key(), it.data().local8Bit().data() ); +} + +} + 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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included +** in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A +** PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QTPALMTOP_RECORD_H +#define QTPALMTOP_RECORD_H + +#include <qglobal.h> +#include "qpcglobal.h" +#include "palmtopuidgen.h" +#include <qarray.h> +#include <qmap.h> + +#if defined(QPC_TEMPLATEDLL) +// MOC_SKIP_BEGIN +template class QPC_EXPORT QMap<QString, QString>; +// MOC_SKIP_END +#endif + +class QRegExp; +namespace Qtopia { + +class RecordPrivate; +class QPC_EXPORT Record +{ +public: + Record() : mUid(0), mCats() { } + Record( const Record &c ) : mUid( c.mUid ), mCats ( c.mCats ), customMap(c.customMap) { } + virtual ~Record() { } + + Record &operator=( const Record &c ); + + virtual bool match( const QRegExp & ) const { return FALSE; } + + void setCategories( const QArray<int> &v ) { mCats = v; } + void setCategories( int single ); + const QArray<int> &categories() const { return mCats; } + + int uid() const { return mUid; }; + virtual void setUid( int i ) { mUid = i; uidGen().store( mUid ); } + bool isValidUid() const { return mUid != 0; } + void assignUid() { setUid( uidGen().generate() ); } + + virtual QString customField(const QString &) const; + virtual void setCustomField(const QString &, const QString &); + virtual void removeCustomField(const QString &); + + virtual bool operator == ( const Record &r ) const +{ return mUid == r.mUid; } + virtual bool operator != ( const Record &r ) const +{ return mUid != r.mUid; } + + // convenience methods provided for loading and saving to xml + static QString idsToString( const QArray<int> &ids ); + // convenience methods provided for loading and saving to xml + static QArray<int> idsFromString( const QString &str ); + + // for debugging + static void dump( const QMap<int, QString> &map ); + +protected: + virtual UidGen &uidGen() = 0; + + virtual QString customToXml() const; + +private: + int mUid; + QArray<int> mCats; + + QMap<QString, QString> customMap; + + RecordPrivate *d; +}; + +} + +#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 @@ +#ifndef QTPALMTOP_UIDGEN_H +#define QTPALMTOP_UIDGEN_H +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** Licensees holding valid Qtopia Developer license may use this +** file in accordance with the Qtopia Developer License Agreement +** provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +** PURPOSE. +** +** email sales@trolltech.com for information about Qtopia License +** Agreements. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include <time.h> +#include <qmap.h> +#include "qpcglobal.h" + +#if defined(QPC_TEMPLATEDLL) +// MOC_SKIP_BEGIN +template class QPC_EXPORT QMap< int, bool >; +// MOC_SKIP_END +#endif + +namespace Qtopia { + + +class QPC_EXPORT UidGen +{ +public: + enum Type { Qtopia, PalmtopCenter }; + + UidGen() : type( Qtopia ), sign( -1 ), ids() +{ +#ifdef PALMTOPCENTER + type = PalmtopCenter; + sign = 1; +#endif +} + UidGen( Type t ) : type(t), sign(1), ids() +{ + if ( t == Qtopia ) + sign = -1; +} + + virtual ~UidGen() { } + + int generate() const +{ + int id = sign * (int) ::time(NULL); + while ( ids.contains( id ) ) { + id += sign; + + // check for overflow cases; if so, wrap back to beginning of + // set ( -1 or 1 ) + if ( sign == -1 && id > 0 || sign == 1 && id < 0 ) + id = sign; + } + return id; +} + + void store(int id) { ids.insert(id, TRUE); } + bool isUnique(int id) const { return (!ids.contains(id)); } + +private: + Type type; + int sign; + QMap<int, bool> ids; + +}; + +} + +#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 @@ +/**********************************************************************
+** Copyright (C) 2001 Trolltech AS. All rights reserved.
+**
+** This file is part of the Qtopia Environment.
+**
+** Licensees holding valid Qtopia Developer license may use this
+** file in accordance with the Qtopia Developer License Agreement
+** provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
+** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+** PURPOSE.
+**
+** email sales@trolltech.com for information about Qtopia License
+** Agreements.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef QFILE_DIRECT_H
+#define QFILE_DIRECT_H
+#include <qfile.h>
+#include <qpe/qpcglobal.h>
+
+class QPC_EXPORT QFileDirect : public QFile
+{
+public:
+ QFileDirect() : QFile() { }
+ QFileDirect( const QString &name ) : QFile(name) { }
+
+ FILE *directHandle() { return fh; }
+};
+
+#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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** Licensees holding valid Qtopia Developer license may use this +** file in accordance with the Qtopia Developer License Agreement +** provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +** PURPOSE. +** +** email sales@trolltech.com for information about Qtopia License +** Agreements. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QPC_GLOBAL_H +#define QPC_GLOBAL_H + +#if ( defined(Q_OS_WIN32) || defined(Q_OS_WIN64) ) && defined(PALMTOPCENTER) +#include <qglobal.h> +// # if defined(QT_NODLL) +//# undef QPC_MAKEDLL +//# undef QPC_DLL +# if defined(QPC_MAKEDLL) /* create a Qt DLL library */ +# if defined(QPC_DLL) +# undef QPC_DLL +# endif +# define QPC_EXPORT __declspec(dllexport) +# define QPC_TEMPLATEDLL +# undef QPC_DISABLE_COPY /* avoid unresolved externals */ +# elif defined(QPC_DLL) /* use a Qt DLL library */ +# define QPC_EXPORT __declspec(dllimport) +# define QPC_TEMPLATEDLL +# undef QPC_DISABLE_COPY /* avoid unresolved externals */ +# endif +#else +# undef QPC_MAKEDLL /* ignore these for other platforms */ +# undef QPC_DLL +#endif +#endif + +#ifndef QPC_EXPORT +# define QPC_EXPORT +#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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** Licensees holding valid Qtopia Developer license may use this +** file in accordance with the Qtopia Developer License Agreement +** provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +** PURPOSE. +** +** email sales@trolltech.com for information about Qtopia License +** Agreements. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef QPC_RECORD_FIELDS_H +#define QPC_RECORD_FIELDS_H +#include "qpcglobal.h" + +// dataset = "addressbook" +namespace Qtopia +{ + static const int UID_ID = 0; + static const int CATEGORY_ID = 1; + + enum AddressBookFields { + AddressUid = UID_ID, + AddressCategory = CATEGORY_ID, + + Title, + FirstName, + MiddleName, + LastName, + Suffix, + FileAs, + + // email + DefaultEmail, + Emails, + + // home + HomeStreet, + HomeCity, + HomeState, + HomeZip, + HomeCountry, + HomePhone, + HomeFax, + HomeMobile, + HomeWebPage, + + // business + Company, + BusinessStreet, + BusinessCity, + BusinessState, + BusinessZip, + BusinessCountry, + BusinessWebPage, + JobTitle, + Department, + Office, + BusinessPhone, + BusinessFax, + BusinessMobile, + BusinessPager, + Profession, + Assistant, + Manager, + + //personal + Spouse, + Gender, + Birthday, + Anniversary, + Nickname, + Children, + + // other + Notes, + Groups + }; + + // dataset = "todolist" + enum TaskFields { + TaskUid = UID_ID, + TaskCategory = CATEGORY_ID, + + HasDate, + Completed, + TaskDescription, + Priority, + Date + }; + + // dataset = "categories" for todos + enum CategoryFields { + CatUid = UID_ID, + CatName, + CatAppGroup + }; + + +// dataset = "datebook" + enum DatebookFields { + DatebookUid = UID_ID, + DatebookCategory = CATEGORY_ID, + + DatebookDescription, + Location, + TimeZone, + Note, + StartDateTime, + EndDateTime, + DatebookType, + HasAlarm, + SoundType, + AlarmTime, + + RepeatPatternType, + RepeatPatternFrequency, + RepeatPatternPosition, + RepeatPatternDays, + RepeatPatternHasEndDate, + RepeatPatternEndDate, + }; +}; + + +#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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included +** in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A +** PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "stringutil.h" +#include <qregexp.h> +#include <qstringlist.h> + +namespace Qtopia +{ + + + +/* + Very, very simple Latin-1 only collation guaranteed to displease anyone + who actually uses the non-ASCII characters. + */ + +static const char collationHack[] = { +0x00, //C-@ +0x01, //C-A +0x02, //C-B +0x03, //C-C +0x04, //C-D +0x05, //C-E +0x06, //C-F +0x07, //C-G +0x08, //C-H +0x09, //C-I +0x0a, //C-J +0x0b, //C-K +0x0c, //C-L +0x0d, //C-M +0x0e, //C-N +0x0f, //C-O +0x10, //C-P +0x11, //C-Q +0x12, //C-R +0x13, //C-S +0x14, //C-T +0x15, //C-U +0x16, //C-V +0x17, //C-W +0x18, //C-X +0x19, //C-Y +0x1a, //C-Z +0x1b, //C-[ +0x1c, //C-\ +0x1d, //C-] +0x1e, //C-^ +0x1f, //C-_ +' ', // +'!', //! +'"', //" +'#', //# +'$', //$ +'%', //% +'&', //& +'\'', //' +'(', //( +')', //) +'*', //* +'+', //+ +',', //, +'-', //- +'.', //. +'/', /// +0x80, //0 +0x81, //1 +0x82, //2 +0x83, //3 +0x84, //4 +0x85, //5 +0x86, //6 +0x87, //7 +0x88, //8 +0x89, //9 +':', //: +';', //; +'<', //< +'=', //= +'>', //> +'?', //? +'@', //@ +'A', //A +'B', //B +'C', //C +'D', //D +'E', //E +'F', //F +'G', //G +'H', //H +'I', //I +'J', //J +'K', //K +'L', //L +'M', //M +'N', //N +'O', //O +'P', //P +'Q', //Q +'R', //R +'S', //S +'T', //T +'U', //U +'V', //V +'W', //W +'X', //X +'Y', //Y +'Z', //Z +'[', //[ +'\\', //\ +']', //] +'^', //^ +'_', //_ +'`', //` +'A', //a +'B', //b +'C', //c +'D', //d +'E', //e +'F', //f +'G', //g +'H', //h +'I', //i +'J', //j +'K', //k +'L', //l +'M', //m +'N', //n +'O', //o +'P', //p +'Q', //q +'R', //r +'S', //s +'T', //t +'U', //u +'V', //v +'W', //w +'X', //x +'Y', //y +'Z', //z +'{', //{ +'|', //| +'}', //} +'~', //~ +'', // +0x80, //C-M-@ +0x81, //C-M-A +0x82, //C-M-B +0x83, //C-M-C +0x84, //C-M-D +0x85, //C-M-E +0x86, //C-M-F +0x87, //C-M-G +0x88, //C-M-H +0x89, //C-M-I +0x8a, //C-M-J +0x8b, //C-M-K +0x8c, //C-M-L +0x8d, //C-M-M +0x8e, //C-M-N +0x8f, //C-M-O +0x90, //C-M-P +0x91, //C-M-Q +0x92, //C-M-R +0x93, //C-M-S +0x94, //C-M-T +0x95, //C-M-U +0x96, //C-M-V +0x97, //C-M-W +0x98, //C-M-X +0x99, //C-M-Y +0x9a, //C-M-Z +0x9b, //C-M-[ +0x9c, //C-M-\ +0x9d, //C-M-] +0x9e, //C-M-^ +0x9f, //C-M-_ +' ', // +'¡', //¡ +'¢', //¢ +'£', //£ +'¤', //¤ +'¥', //¥ +'¦', //¦ +'§', //§ +'¨', //¨ +'©', //© +'A', //ª +'«', //« +'¬', //¬ +'', // +'®', //® +'¯', //¯ +'O', //° +'±', //± +'²', //² +'³', //³ +'´', //´ +'µ', //µ +'P', //¶ +'·', //· +'¸', //¸ +'¹', //¹ +'O', //º +'»', //» +'¼', //¼ +'½', //½ +'¾', //¾ +'¿', //¿ +'A', //À +'A', //Á +'A', //Â +'A', //Ã +'A', //Ä +'A', //Å +'A', //Æ +'C', //Ç +'E', //È +'E', //É +'E', //Ê +'E', //Ë +'I', //Ì +'I', //Í +'I', //Î +'I', //Ï +'D', //Ð +'N', //Ñ +'O', //Ò +'O', //Ó +'O', //Ô +'O', //Õ +'O', //Ö +'×', //× +'O', //Ø +'U', //Ù +'U', //Ú +'U', //Û +'U', //Ü +'Y', //Ý +'T', //Þ +'S', //ß +'A', //à +'A', //á +'A', //â +'A', //ã +'A', //ä +'A', //å +'A', //æ +'C', //ç +'E', //è +'E', //é +'E', //ê +'E', //ë +'I', //ì +'I', //í +'I', //î +'I', //ï +'D', //ð +'N', //ñ +'O', //ò +'O', //ó +'O', //ô +'O', //õ +'O', //ö +'÷', //÷ +'O', //ø +'U', //ù +'U', //ú +'U', //û +'U', //ü +'Y', //ý +'T', //þ +'Y', //ÿ +}; + + + + + +static void hackString ( QString &s ) +{ + int len = s.length(); + const QChar* uc = s.unicode(); + for ( int i = 0; i < len; i++ ) { + if ( !uc++->row() ) + s[i] = collationHack[s[i].cell()]; + } +} + +QString buildSortKey( const QString & s ) +{ + QString res = s; + hackString( res ); + return res; +} + +QString buildSortKey( const QString & s1, const QString & s2 ) +{ + QString res = s1 + QChar( '\0' ) + s2; + hackString( res ); + return res; +} + +QString buildSortKey( const QString & s1, const QString & s2, + const QString & s3 ) +{ + QString res = s1 + QChar( '\0' ) + s2 + QChar( '\0' ) + s3; + hackString( res ); + return res; +} + +static inline QChar coll( QChar u ) +{ + return u.row() ? u : QChar(collationHack[ u.cell() ]); +} + + +int compare( const QString & s1, const QString & s2 ) +{ + const QChar* u1 = s1.unicode(); + const QChar* u2 = s2.unicode(); + + if ( u1 == u2 ) + return 0; + if ( u1 == 0 ) + return 1; + if ( u2 == 0 ) + return -1; + int l=QMIN(s1.length(),s2.length()); + while ( l-- && coll(*u1) == coll(*u2) ) + u1++,u2++; + if ( l==-1 ) + return ( s1.length()-s2.length() ); + return u1->unicode() - u2->unicode(); +} + +QString simplifyMultiLineSpace( const QString &multiLine ) +{ + QString result; + QStringList lines = QStringList::split("\n", multiLine); + for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) { + if ( it != lines.begin() ) + result += "\n"; + result += (*it).simplifyWhiteSpace(); + } + return result; +} + +QString escapeString( const QString& plain ) +{ + QString tmp(plain); + int pos = tmp.length(); + const QChar *uc = plain.unicode(); + while ( pos-- ) { + unsigned char ch = uc[pos].latin1(); + if ( ch == '&' ) + tmp.replace( pos, 1, "&" ); + else if ( ch == '<' ) + tmp.replace( pos, 1, "<" ); + else if ( ch == '>' ) + tmp.replace( pos, 1, ">" ); + else if ( ch == '\"' ) + tmp.replace( pos, 1, """ ); + } + return tmp; +} + +QString plainString( const char* escaped, unsigned int length ) +{ + return plainString( QString::fromUtf8( escaped, length ) ); +} + +QString plainString( const QCString& string ) +{ + // We first have to pass it through a ::fromUtf8() + return plainString( string.data(), string.length() ); +} + +QString plainString( const QString& string ) +{ + QString tmp( string ); + int pos = -1; + while ( (pos = tmp.find( "&", pos +1 ) ) != -1 ) { + if ( tmp.find( "&", pos ) == pos ) + tmp.replace( pos, 5, "&" ); + else if ( tmp.find( "<", pos ) == pos ) + tmp.replace( pos, 4, "<" ); + else if( tmp.find( ">", pos ) == pos ) + tmp.replace( pos, 4, ">" ); + else if ( tmp.find( """, pos ) == pos ) + tmp.replace( pos, 6, "\"" ); + } + return tmp; +} + +} // 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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included +** in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A +** PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +#ifndef QTPALMTOP_stringutil_h__ +#define QTPALMTOP_stringutil_h__ + +#include <qstring.h> +#include "qpcglobal.h" + +namespace Qtopia +{ + +// Simplifies white space within each line but keeps the new line characters +QString QPC_EXPORT simplifyMultiLineSpace( const QString &multiLine ); + +// Creates a QString which doesn't contain any "dangerous" +// characters (i.e. <, >, &, ") +QString QPC_EXPORT escapeString( const QString& plain ); + +// Takes a UTF-8!! string and removes all the XML thingies (entities?) +// from the string and also calls fromUtf8() on it... so make sure +// to pass a QCString/const char* with UTF-8 data only +QString QPC_EXPORT plainString( const char* escaped, unsigned int length ); +QString QPC_EXPORT plainString( const QCString& string ); + +QString QPC_EXPORT plainString( const QString& string ); + + +// collation functions +int compare( const QString & s1, const QString & s2 ); +QString buildSortKey( const QString & s ); +QString buildSortKey( const QString & s1, const QString & s2 ); +QString buildSortKey( const QString & s1, const QString & s2, + const QString & s3 ); + +} + +#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 @@ +/********************************************************************** +** Copyright (C) 2001 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include <qpe/task.h> +#include <qregexp.h> +#include <qstring.h> +#include <qpe/recordfields.h> +#include "vobject_p.h" +#include "timeconversion.h" +#include "qfiledirect_p.h" + +#include <stdio.h> + +using namespace Qtopia; +UidGen Task::sUidGen( UidGen::Qtopia ); + +Task::Task() : Record(), mDue( FALSE ), +mDueDate( QDate::currentDate() ), +mCompleted( FALSE ), mPriority( 3 ), mDesc() +{ +} + +Task::Task( const QMap<int, QString> &m ) : Record(), mDue( FALSE ), +mDueDate( QDate::currentDate() ), mCompleted( FALSE ), mPriority( 3 ), mDesc() +{ + //qDebug("Task::Task fromMap"); + //dump( m ); + for ( QMap<int,QString>::ConstIterator it = m.begin(); it != m.end();++it ) + switch ( (TaskFields) it.key() ) { + case HasDate: if ( *it == "1" ) mDue = TRUE; break; + case Completed: setCompleted( *it == "1" ); break; + case TaskCategory: setCategories( idsFromString( *it ) ); break; + case TaskDescription: setDescription( *it ); break; + case Priority: setPriority( (*it).toInt() ); break; + case Date: mDueDate = TimeConversion::fromString( (*it) ); break; + case TaskUid: setUid( (*it).toInt() ); break; + } +} + +Task::~Task() +{ +} + +QMap<int, QString> Task::toMap() const +{ + QMap<int, QString> m; + m.insert( HasDate, hasDueDate() ? "1" : "0" ); + m.insert( Completed, isCompleted() ? "1" : "0" ); + m.insert( TaskCategory, idsToString( categories() ) ); + m.insert( TaskDescription, description() ); + m.insert( Priority, QString::number( priority() ) ); + m.insert( Date, TimeConversion::toString( dueDate() ) ); + m.insert( TaskUid, QString::number(uid()) ); + + //qDebug("Task::toMap"); + //dump( m ); + return m; +} + +void Task::save( QString& buf ) const +{ + buf += " Completed=\""; + // qDebug( "writing %d", complete ); + buf += QString::number( (int)mCompleted ); + buf += "\""; + buf += " HasDate=\""; + // qDebug( "writing %d", ); + buf += QString::number( (int)mDue ); + buf += "\""; + buf += " Priority=\""; + // qDebug ("writing %d", prior ); + buf += QString::number( mPriority ); + buf += "\""; + buf += " Categories=\""; + buf += Qtopia::Record::idsToString( categories() ); + buf += "\""; + buf += " Description=\""; + // qDebug( "writing note %s", note.latin1() ); + buf += Qtopia::escapeString( mDesc ); + buf += "\""; + if ( mDue ) { + // qDebug("saving ymd %d %d %d", mDueDate.year(), mDueDate.month(), + // mDueDate.day() ); + buf += " DateYear=\""; + buf += QString::number( mDueDate.year() ); + buf += "\""; + buf += " DateMonth=\""; + buf += QString::number( mDueDate.month() ); + buf += "\""; + buf += " DateDay=\""; + buf += QString::number( mDueDate.day() ); + buf += "\""; + } + buf += customToXml(); + // qDebug ("writing uid %d", uid() ); + buf += " Uid=\""; + buf += QString::number( uid() ); + // terminate it in the application... + buf += "\""; +} + +bool Task::match ( const QRegExp &r ) const +{ + // match on priority, description on due date... + bool match; + match = false; + if ( QString::number( mPriority ).find( r ) > -1 ) + match = true; + else if ( mDue && mDueDate.toString().find( r ) > -1 ) + match = true; + else if ( mDesc.find( r ) > -1 ) + match = true; + return match; +} + +static inline VObject *safeAddPropValue( VObject *o, const char *prop, const QString &value ) +{ + VObject *ret = 0; + if ( o && !value.isEmpty() ) + ret = addPropValue( o, prop, value.latin1() ); + return ret; +} + +static inline VObject *safeAddProp( VObject *o, const char *prop) +{ + VObject *ret = 0; + if ( o ) + ret = addProp( o, prop ); + return ret; +} + + +static VObject *createVObject( const Task &t ) +{ + VObject *vcal = newVObject( VCCalProp ); + safeAddPropValue( vcal, VCVersionProp, "1.0" ); + VObject *task = safeAddProp( vcal, VCTodoProp ); + + if ( t.hasDueDate() ) + safeAddPropValue( task, VCDueProp, TimeConversion::toISO8601( t.dueDate() ) ); + safeAddPropValue( task, VCDescriptionProp, t.description() ); + if ( t.isCompleted() ) + safeAddPropValue( task, VCStatusProp, "COMPLETED" ); + safeAddPropValue( task, VCPriorityProp, QString::number( t.priority() ) ); + + return vcal; +} + + +static Task parseVObject( VObject *obj ) +{ + Task t; + + VObjectIterator it; + initPropIterator( &it, obj ); + while( moreIteration( &it ) ) { + VObject *o = nextVObject( &it ); + QCString name = vObjectName( o ); + QCString value = vObjectStringZValue( o ); + if ( name == VCDueProp ) { + t.setDueDate( TimeConversion::fromISO8601( value ).date(), TRUE ); + } + else if ( name == VCDescriptionProp ) { + t.setDescription( value ); + } + else if ( name == VCStatusProp ) { + if ( value == "COMPLETED" ) + t.setCompleted( TRUE ); + } + else if ( name == VCPriorityProp ) { + t.setPriority( value.toInt() ); + } +#if 0 + else { + printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + printf(" subprop: %s = %s\n", name.data(), value.latin1() ); + } + } +#endif + } + + return t; +} + + + +void Task::writeVCalendar( const QString &filename, const QValueList<Task> &tasks) +{ + QFileDirect f( filename.utf8().data() ); + if ( !f.open( IO_WriteOnly ) ) { + qWarning("Unable to open vcard write"); + return; + } + + QValueList<Task>::ConstIterator it; + for( it = tasks.begin(); it != tasks.end(); ++it ) { + VObject *obj = createVObject( *it ); + writeVObject(f.directHandle() , obj ); + cleanVObject( obj ); + } + + cleanStrTbl(); +} + +void Task::writeVCalendar( const QString &filename, const Task &task) +{ + QFileDirect f( filename.utf8().data() ); + if ( !f.open( IO_WriteOnly ) ) { + qWarning("Unable to open vcard write"); + return; + } + + VObject *obj = createVObject( task ); + writeVObject(f.directHandle() , obj ); + cleanVObject( obj ); + + cleanStrTbl(); +} + + +QValueList<Task> Task::readVCalendar( const QString &filename ) +{ + VObject *obj = Parse_MIME_FromFileName( (char *)filename.utf8().data() ); + + QValueList<Task> tasks; + + while ( obj ) { + QCString name = vObjectName( obj ); + if ( name == VCCalProp ) { + VObjectIterator nit; + initPropIterator( &nit, obj ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + if ( name == VCTodoProp ) + tasks.append( parseVObject( o ) ); + } + } else if ( name == VCTodoProp ) { + // shouldn't happen, but just to be sure + tasks.append( parseVObject( obj ) ); + } + VObject *t = obj; + obj = nextVObjectInList(obj); + cleanVObject( t ); + } + + return tasks; +} 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 @@ +/********************************************************************** +** Copyright (C) 2001 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef __TASK_H__ +#define __TASK_H__ + +#include <qpe/palmtoprecord.h> +#include <qpe/stringutil.h> + +#include <qvaluelist.h> +#include <qdatetime.h> + +class TaskPrivate; +class QPC_EXPORT Task : public Qtopia::Record +{ +public: + Task(); + Task( const QMap<int, QString> &fromMap ); + ~Task(); + + QMap<int, QString> toMap() const; + + static void writeVCalendar( const QString &filename, const QValueList<Task> &tasks); + static void writeVCalendar( const QString &filename, const Task &task); + static QValueList<Task> readVCalendar( const QString &filename ); + + void setPriority( int priority ) { mPriority = priority; } + int priority() const { return mPriority; } + +// void setCategory( const QString& category ) +// { mCategory = category.stripWhiteSpace(); } +// const QString &category() const { return mCategory; } + + void setDescription( const QString& description ) + { mDesc = Qtopia::simplifyMultiLineSpace(description); } + const QString &description() const { return mDesc; } + + void setDueDate( const QDate& date, bool hasDue ) { mDueDate = date; mDue = hasDue; } + const QDate &dueDate() const { return mDueDate; } + bool hasDueDate() const { return mDue; } + void setHasDueDate( bool b ) { mDue = b; } + + void setCompleted( bool b ) { mCompleted = b; } + bool isCompleted() const { return mCompleted; } + + void save( QString& buf ) const; + bool match( const QRegExp &r ) const; + +private: + Qtopia::UidGen &uidGen() { return sUidGen; } + static Qtopia::UidGen sUidGen; + + bool mDue; + QDate mDueDate; + bool mCompleted; + int mPriority; + QString mDesc; + TaskPrivate *d; +}; + +#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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include <qglobal.h> +#include "timeconversion.h" +#include <qregexp.h> +#include <stdlib.h> + +QString TimeConversion::toString( const QDate &d ) +{ + QString r = QString::number( d.day() ) + "." + + QString::number( d.month() ) + "." + + QString::number( d.year() ); + //qDebug("TimeConversion::toString %s", r.latin1()); + return r; +} + +QDate TimeConversion::fromString( const QString &datestr ) +{ + int monthPos = datestr.find('.'); + int yearPos = datestr.find('.', monthPos+1 ); + if ( monthPos == -1 || yearPos == -1 ) { + qDebug("fromString didn't find . in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, yearPos ); + return QDate(); + } + int d = datestr.left( monthPos ).toInt(); + int m = datestr.mid( monthPos+1, yearPos - monthPos - 1 ).toInt(); + int y = datestr.mid( yearPos+1 ).toInt(); + QDate date ( y,m,d ); + //qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, yearPos); + return date; +} + +time_t TimeConversion::toUTC( const QDateTime& dt ) +{ + time_t tmp; + struct tm *lt; + +#if defined(_OS_WIN32) || defined (Q_OS_WIN32) || defined (Q_OS_WIN64) + _tzset(); +#else + tzset(); +#endif + + // get a tm structure from the system to get the correct tz_name + tmp = time( 0 ); + lt = localtime( &tmp ); + + lt->tm_sec = dt.time().second(); + lt->tm_min = dt.time().minute(); + lt->tm_hour = dt.time().hour(); + lt->tm_mday = dt.date().day(); + lt->tm_mon = dt.date().month() - 1; // 0-11 instead of 1-12 + lt->tm_year = dt.date().year() - 1900; // year - 1900 + //lt->tm_wday = dt.date().dayOfWeek(); ignored anyway + //lt->tm_yday = dt.date().dayOfYear(); ignored anyway + lt->tm_wday = -1; + lt->tm_yday = -1; + // tm_isdst negative -> mktime will find out about DST + lt->tm_isdst = -1; + // keep tm_zone and tm_gmtoff + tmp = mktime( lt ); + return tmp; +} + +QDateTime TimeConversion::fromUTC( time_t time ) +{ + struct tm *lt; + +#if defined(_OS_WIN32) || defined (Q_OS_WIN32) || defined (Q_OS_WIN64) + _tzset(); +#else + tzset(); +#endif + lt = localtime( &time ); + QDateTime dt; + dt.setDate( QDate( lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday ) ); + dt.setTime( QTime( lt->tm_hour, lt->tm_min, lt->tm_sec ) ); + return dt; +} + + +int TimeConversion::secsTo( const QDateTime &from, const QDateTime &to ) +{ + return toUTC( to ) - toUTC( from ); +} + +QCString TimeConversion::toISO8601( const QDate &d ) +{ + time_t tmp = toUTC( d ); + struct tm *utc = gmtime( &tmp ); + + QCString str; + str.sprintf("%04d%02d%02d", (utc->tm_year + 1900), utc->tm_mon+1, utc->tm_mday ); + return str; +} + +QCString TimeConversion::toISO8601( const QDateTime &dt ) +{ + time_t tmp = toUTC( dt ); + struct tm *utc = gmtime( &tmp ); + + QCString str; + str.sprintf("%04d%02d%02dT%02d%02d%02dZ", + (utc->tm_year + 1900), utc->tm_mon+1, utc->tm_mday, + utc->tm_hour, utc->tm_min, utc->tm_sec ); + return str; +} + +QDateTime TimeConversion::fromISO8601( const QCString &s ) +{ + +#if defined(_OS_WIN32) || defined (Q_OS_WIN32) || defined (Q_OS_WIN64) + _tzset(); +#else + tzset(); +#endif + + struct tm *thetime = new tm; + + QCString str = s.copy(); + str.replace(QRegExp("-"), "" ); + str.replace(QRegExp(":"), "" ); + str.stripWhiteSpace(); + str = str.lower(); + + int i = str.find( "t" ); + QCString date; + QCString timestr; + if ( i != -1 ) { + date = str.left( i ); + timestr = str.mid( i+1 ); + } else { + date = str; + } + +// qDebug("--- parsing ISO time---"); + thetime->tm_year = 100; + thetime->tm_mon = 0; + thetime->tm_mday = 0; + thetime->tm_hour = 0; + thetime->tm_min = 0; + thetime->tm_sec = 0; + +// qDebug("date = %s", date.data() ); + + switch( date.length() ) { + case 8: + thetime->tm_mday = date.right( 2 ).toInt(); + case 6: + thetime->tm_mon = date.mid( 4, 2 ).toInt() - 1; + case 4: + thetime->tm_year = date.left( 4 ).toInt(); + thetime->tm_year -= 1900; + break; + default: + break; + } + + int tzoff = 0; + bool inLocalTime = FALSE; + if ( timestr.find( 'z' ) == (int)timestr.length() - 1 ) + // UTC + timestr = timestr.left( timestr.length() -1 ); + else { + int plus = timestr.find( "+" ); + int minus = timestr.find( "-" ); + if ( plus != -1 || minus != -1 ) { + // have a timezone offset + plus = (plus != -1) ? plus : minus; + QCString off = timestr.mid( plus ); + timestr = timestr.left( plus ); + + int tzoffhour = 0; + int tzoffmin = 0; + switch( off.length() ) { + case 5: + tzoffmin = off.mid(3).toInt(); + case 3: + tzoffhour = off.left(3).toInt(); + default: + break; + } + tzoff = 60*tzoffhour + tzoffmin; + } else + inLocalTime = TRUE; + } + + // get the time: + switch( timestr.length() ) { + case 6: + thetime->tm_sec = timestr.mid( 4 ).toInt(); + case 4: + thetime->tm_min = timestr.mid( 2, 2 ).toInt(); + case 2: + thetime->tm_hour = timestr.left( 2 ).toInt(); + default: + break; + } + + int tzloc = 0; + time_t tmp = time( 0 ); + if ( !inLocalTime ) { + // have to get the offset between gmt and local time + struct tm *lt = localtime( &tmp ); + tzloc = mktime( lt ); + struct tm *ut = gmtime( &tmp ); + tzloc -= mktime( ut ); + } +// qDebug("time: %d %d %d, tzloc=%d, tzoff=%d", thetime->tm_hour, thetime->tm_min, thetime->tm_sec, +// tzloc, tzoff ); + + tmp = mktime( thetime ); + tmp += 60*(-tzloc + tzoff); + + delete thetime; + + return fromUTC( tmp ); +} + 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 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef __timeconversion_h__ +#define __timeconversion_h__ + +#include <time.h> +#include <sys/types.h> +#include <qdatetime.h> + +#include <qpe/qpcglobal.h> + +class QPC_EXPORT TimeConversion +{ +public: + static QString toString( const QDate &d ); + static QDate fromString( const QString &datestr ); + + static time_t toUTC( const QDateTime& dt ); + static QDateTime fromUTC( time_t time ); + static int secsTo( const QDateTime &from, const QDateTime &to ); + + static QCString toISO8601( const QDate & ); + static QCString toISO8601( const QDateTime & ); + static QDateTime fromISO8601( const QCString & ); +}; + +#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 @@ +%{
+
+/***************************************************************************
+(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+
+For purposes of this license notice, the term Licensors shall mean,
+collectively, Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+The term Licensor shall mean any of the Licensors.
+
+Subject to acceptance of the following conditions, permission is hereby
+granted by Licensors without the need for written agreement and without
+license or royalty fees, to use, copy, modify and distribute this
+software for any purpose.
+
+The above copyright notice and the following four paragraphs must be
+reproduced in all copies of this software and any software including
+this software.
+
+THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
+ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
+MODIFICATIONS.
+
+IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+
+The software is provided with RESTRICTED RIGHTS. Use, duplication, or
+disclosure by the government are subject to restrictions set forth in
+DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
+
+***************************************************************************/
+
+/*
+ * src: vcc.c
+ * doc: Parser for vCard and vCalendar. Note that this code is
+ * generated by a yacc parser generator. Generally it should not
+ * be edited by hand. The real source is vcc.y. The #line directives
+ * can be commented out here to make it easier to trace through
+ * in a debugger. However, if a bug is found it should
+ * be fixed in vcc.y and this file regenerated.
+ */
+
+
+/* debugging utilities */
+#if __DEBUG
+#define DBG_(x) printf x
+#else
+#define DBG_(x)
+#endif
+
+/**** External Functions ****/
+
+/* assign local name to parser variables and functions so that
+ we can use more than one yacc based parser.
+*/
+
+#if 0
+#define yyparse mime_parse
+#define yylex mime_lex
+#define yyerror mime_error
+#define yychar mime_char
+/* #define p_yyval p_mime_val */
+#undef yyval
+#define yyval mime_yyval
+/* #define p_yylval p_mime_lval */
+#undef yylval
+#define yylval mime_yylval
+#define yydebug mime_debug
+#define yynerrs mime_nerrs
+#define yyerrflag mime_errflag
+#define yyss mime_ss
+#define yyssp mime_ssp
+#define yyvs mime_vs
+#define yyvsp mime_vsp
+#define yylhs mime_lhs
+#define yylen mime_len
+#define yydefred mime_defred
+#define yydgoto mime_dgoto
+#define yysindex mime_sindex
+#define yyrindex mime_rindex
+#define yygindex mime_gindex
+#define yytable mime_table
+#define yycheck mime_check
+#define yyname mime_name
+#define yyrule mime_rule
+#ifdef YYPREFIX
+#undef YYPREFIX
+#endif
+#define YYPREFIX "mime_"
+#endif
+
+
+#ifndef _NO_LINE_FOLDING
+#define _SUPPORT_LINE_FOLDING 1
+#endif
+
+/* undef below if compile with MFC */
+/* #define INCLUDEMFC 1 */
+
+#if defined(WIN32) || defined(_WIN32)
+#ifdef INCLUDEMFC
+#include <afx.h>
+#endif
+#endif
+
+#include <string.h>
+#ifndef __MWERKS__
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+//#ifdef PALMTOPCENTER
+//#include <qpe/vobject_p.h>
+//#else
+#include "vobject_p.h"
+//#endif
+
+/**** Types, Constants ****/
+
+#define YYDEBUG 0 /* 1 to compile in some debugging code */
+#define MAXTOKEN 256 /* maximum token (line) length */
+#define YYSTACKSIZE 100 // ~unref ?
+#define MAXLEVEL 10 /* max # of nested objects parseable */
+ /* (includes outermost) */
+
+
+/**** Global Variables ****/
+int mime_lineNum, mime_numErrors; /* yyerror() can use these */
+static VObject* vObjList;
+static VObject *curProp;
+static VObject *curObj;
+static VObject* ObjStack[MAXLEVEL];
+static int ObjStackTop;
+
+
+/* A helpful utility for the rest of the app. */
+#if __CPLUSPLUS__
+extern "C" {
+#endif
+
+ extern void yyerror(char *s);
+
+#if __CPLUSPLUS__
+ };
+#endif
+
+int yyparse();
+
+enum LexMode {
+ L_NORMAL,
+ L_VCARD,
+ L_VCAL,
+ L_VEVENT,
+ L_VTODO,
+ L_VALUES,
+ L_BASE64,
+ L_QUOTED_PRINTABLE
+ };
+
+/**** Private Forward Declarations ****/
+static int pushVObject(const char *prop);
+static VObject* popVObject();
+static void lexPopMode(int top);
+static int lexWithinMode(enum LexMode mode);
+static void lexPushMode(enum LexMode mode);
+static void enterProps(const char *s);
+static void enterAttr(const char *s1, const char *s2);
+static void enterValues(const char *value);
+#define mime_error yyerror
+void mime_error(char *s);
+void mime_error_(char *s);
+
+%}
+
+/***************************************************************************/
+/*** The grammar ****/
+/***************************************************************************/
+
+%union {
+ char *str;
+ VObject *vobj;
+ }
+
+%token
+ EQ COLON DOT SEMICOLON SPACE HTAB LINESEP NEWLINE
+ BEGIN_VCARD END_VCARD BEGIN_VCAL END_VCAL
+ BEGIN_VEVENT END_VEVENT BEGIN_VTODO END_VTODO
+ ID
+
+/*
+ * NEWLINE is the token that would occur outside a vCard,
+ * while LINESEP is the token that would occur inside a vCard.
+ */
+
+%token <str>
+ STRING ID
+
+%type <str> name value
+
+%type <vobj> vcard vcal vobject
+
+%start mime
+
+%%
+
+
+mime: vobjects
+ ;
+
+vobjects: vobjects vobject
+ { addList(&vObjList, $2); curObj = 0; }
+ | vobject
+ { addList(&vObjList, $1); curObj = 0; }
+ ;
+
+vobject: vcard
+ | vcal
+ ;
+
+vcard:
+ BEGIN_VCARD
+ {
+ lexPushMode(L_VCARD);
+ if (!pushVObject(VCCardProp)) YYERROR;
+ }
+ items END_VCARD
+ {
+ lexPopMode(0);
+ $$ = popVObject();
+ }
+ | BEGIN_VCARD
+ {
+ lexPushMode(L_VCARD);
+ if (!pushVObject(VCCardProp)) YYERROR;
+ }
+ END_VCARD
+ {
+ lexPopMode(0);
+ $$ = popVObject();
+ }
+ ;
+
+items: items item
+ | item
+ ;
+
+item: prop COLON
+ {
+ lexPushMode(L_VALUES);
+ }
+ values LINESEP
+ {
+ if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
+ lexPopMode(0);
+ lexPopMode(0);
+ }
+ | error
+ ;
+
+prop: name
+ {
+ enterProps($1);
+ }
+ attr_params
+ | name
+ {
+ enterProps($1);
+ }
+ ;
+
+attr_params: attr_params attr_param
+ | attr_param
+ ;
+
+attr_param: SEMICOLON attr
+ ;
+
+attr: name
+ {
+ enterAttr($1,0);
+ }
+ | name EQ name
+ {
+ enterAttr($1,$3);
+
+ }
+ ;
+
+name: ID
+ ;
+
+values: value SEMICOLON { enterValues($1); } values
+ | value
+ { enterValues($1); }
+ ;
+
+value: STRING
+ |
+ { $$ = 0; }
+ ;
+
+vcal:
+ BEGIN_VCAL
+ { if (!pushVObject(VCCalProp)) YYERROR; }
+ calitems
+ END_VCAL
+ { $$ = popVObject(); }
+ | BEGIN_VCAL
+ { if (!pushVObject(VCCalProp)) YYERROR; }
+ END_VCAL
+ { $$ = popVObject(); }
+ ;
+
+calitems: calitems calitem
+ | calitem
+ ;
+
+calitem:
+ eventitem
+ | todoitem
+ | items
+ ;
+
+eventitem:
+ BEGIN_VEVENT
+ {
+ lexPushMode(L_VEVENT);
+ if (!pushVObject(VCEventProp)) YYERROR;
+ }
+ items
+ END_VEVENT
+ {
+ lexPopMode(0);
+ popVObject();
+ }
+ | BEGIN_VEVENT
+ {
+ lexPushMode(L_VEVENT);
+ if (!pushVObject(VCEventProp)) YYERROR;
+ }
+ END_VEVENT
+ {
+ lexPopMode(0);
+ popVObject();
+ }
+ ;
+
+todoitem:
+ BEGIN_VTODO
+ {
+ lexPushMode(L_VTODO);
+ if (!pushVObject(VCTodoProp)) YYERROR;
+ }
+ items
+ END_VTODO
+ {
+ lexPopMode(0);
+ popVObject();
+ }
+ | BEGIN_VTODO
+ {
+ lexPushMode(L_VTODO);
+ if (!pushVObject(VCTodoProp)) YYERROR;
+ }
+ END_VTODO
+ {
+ lexPopMode(0);
+ popVObject();
+ }
+ ;
+
+%%
+/*------------------------------------*/
+static int pushVObject(const char *prop)
+ {
+ VObject *newObj;
+ if (ObjStackTop == MAXLEVEL)
+ return FALSE;
+
+ ObjStack[++ObjStackTop] = curObj;
+
+ if (curObj) {
+ newObj = addProp(curObj,prop);
+ curObj = newObj;
+ }
+ else
+ curObj = newVObject(prop);
+
+ return TRUE;
+ }
+
+
+/*---------------------------------------*/
+/* This pops the recently built vCard off the stack and returns it. */
+static VObject* popVObject()
+ {
+ VObject *oldObj;
+ if (ObjStackTop < 0) {
+ yyerror("pop on empty Object Stack\n");
+ return 0;
+ }
+ oldObj = curObj;
+ curObj = ObjStack[ObjStackTop--];
+
+ return oldObj;
+ }
+
+
+static void enterValues(const char *value)
+ {
+ if (fieldedProp && *fieldedProp) {
+ if (value) {
+ addPropValue(curProp,*fieldedProp,value);
+ }
+ /* else this field is empty, advance to next field */
+ fieldedProp++;
+ }
+ else {
+ if (value) {
+ setVObjectStringZValue_(curProp,strdup( value ));
+ }
+ }
+ deleteStr(value);
+ }
+
+static void enterProps(const char *s)
+ {
+ curProp = addGroup(curObj,s);
+ deleteStr(s);
+ }
+
+static void enterAttr(const char *s1, const char *s2)
+ {
+ const char *p1, *p2;
+ p1 = lookupProp_(s1);
+ if (s2) {
+ VObject *a;
+ p2 = lookupProp_(s2);
+ a = addProp(curProp,p1);
+ setVObjectStringZValue(a,p2);
+ }
+ else
+ addProp(curProp,p1);
+ if (qstricmp(p1,VCBase64Prop) == 0 || (s2 && qstricmp(p2,VCBase64Prop)==0))
+ lexPushMode(L_BASE64);
+ else if (qstricmp(p1,VCQuotedPrintableProp) == 0
+ || (s2 && qstricmp(p2,VCQuotedPrintableProp)==0))
+ lexPushMode(L_QUOTED_PRINTABLE);
+ deleteStr(s1); deleteStr(s2);
+ }
+
+
+#define MAX_LEX_LOOKAHEAD_0 32
+#define MAX_LEX_LOOKAHEAD 64
+#define MAX_LEX_MODE_STACK_SIZE 10
+#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
+
+struct LexBuf {
+ /* input */
+#ifdef INCLUDEMFC
+ CFile *inputFile;
+#else
+ FILE *inputFile;
+#endif
+ char *inputString;
+ unsigned long curPos;
+ unsigned long inputLen;
+ /* lookahead buffer */
+ /* -- lookahead buffer is short instead of char so that EOF
+ / can be represented correctly.
+ */
+ unsigned long len;
+ short buf[MAX_LEX_LOOKAHEAD];
+ unsigned long getPtr;
+ /* context stack */
+ unsigned long lexModeStackTop;
+ enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
+ /* token buffer */
+ unsigned long maxToken;
+ char *strs;
+ unsigned long strsLen;
+ } lexBuf;
+
+static void lexPushMode(enum LexMode mode)
+ {
+ if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
+ yyerror("lexical context stack overflow");
+ else {
+ lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
+ }
+ }
+
+static void lexPopMode(int top)
+ {
+ /* special case of pop for ease of error recovery -- this
+ version will never underflow */
+ if (top)
+ lexBuf.lexModeStackTop = 0;
+ else
+ if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
+ }
+
+static int lexWithinMode(enum LexMode mode) {
+ unsigned long i;
+ for (i=0;i<lexBuf.lexModeStackTop;i++)
+ if (mode == lexBuf.lexModeStack[i]) return 1;
+ return 0;
+ }
+
+static char lexGetc_()
+ {
+ /* get next char from input, no buffering. */
+ if (lexBuf.curPos == lexBuf.inputLen)
+ return EOF;
+ else if (lexBuf.inputString)
+ return *(lexBuf.inputString + lexBuf.curPos++);
+ else {
+#ifdef INCLUDEMFC
+ char result;
+ return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF;
+#else
+ return fgetc(lexBuf.inputFile);
+#endif
+ }
+ }
+
+static int lexGeta()
+ {
+ ++lexBuf.len;
+ return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
+ }
+
+static int lexGeta_(int i)
+ {
+ ++lexBuf.len;
+ return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
+ }
+
+static void lexSkipLookahead() {
+ if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
+ /* don't skip EOF. */
+ lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
+ lexBuf.len--;
+ }
+ }
+
+static int lexLookahead() {
+ int c = (lexBuf.len)?
+ lexBuf.buf[lexBuf.getPtr]:
+ lexGeta();
+ /* do the \r\n -> \n or \r -> \n translation here */
+ if (c == '\r') {
+ int a = (lexBuf.len>1)?
+ lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
+ lexGeta_(1);
+ if (a == '\n') {
+ lexSkipLookahead();
+ }
+ lexBuf.buf[lexBuf.getPtr] = c = '\n';
+ }
+ else if (c == '\n') {
+ int a = (lexBuf.len>1)?
+ lexBuf.buf[lexBuf.getPtr+1]:
+ lexGeta_(1);
+ if (a == '\r') {
+ lexSkipLookahead();
+ }
+ lexBuf.buf[lexBuf.getPtr] = '\n';
+ }
+ return c;
+ }
+
+static int lexGetc() {
+ int c = lexLookahead();
+ if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
+ /* EOF will remain in lookahead buffer */
+ lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
+ lexBuf.len--;
+ }
+ return c;
+ }
+
+static void lexSkipLookaheadWord() {
+ if (lexBuf.strsLen <= lexBuf.len) {
+ lexBuf.len -= lexBuf.strsLen;
+ lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
+ }
+ }
+
+static void lexClearToken()
+ {
+ lexBuf.strsLen = 0;
+ }
+
+static void lexAppendc(int c)
+ {
+ lexBuf.strs[lexBuf.strsLen] = c;
+ /* append up to zero termination */
+ if (c == 0) return;
+ lexBuf.strsLen++;
+ if (lexBuf.strsLen > lexBuf.maxToken) {
+ /* double the token string size */
+ lexBuf.maxToken <<= 1;
+ lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
+ }
+ }
+
+static char* lexStr() {
+ return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
+ }
+
+static void lexSkipWhite() {
+ int c = lexLookahead();
+ while (c == ' ' || c == '\t') {
+ lexSkipLookahead();
+ c = lexLookahead();
+ }
+ }
+
+static char* lexGetWord() {
+ int c;
+ lexSkipWhite();
+ lexClearToken();
+ c = lexLookahead();
+ while (c != EOF && !strchr("\t\n ;:=",c)) {
+ lexAppendc(c);
+ lexSkipLookahead();
+ c = lexLookahead();
+ }
+ lexAppendc(0);
+ return lexStr();
+ }
+
+static void lexPushLookaheadc(int c) {
+ int putptr;
+ /* can't putback EOF, because it never leaves lookahead buffer */
+ if (c == EOF) return;
+ putptr = (int)lexBuf.getPtr - 1;
+ if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
+ lexBuf.getPtr = putptr;
+ lexBuf.buf[putptr] = c;
+ lexBuf.len += 1;
+ }
+
+static char* lexLookaheadWord() {
+ /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
+ / and thing bigger than that will stop the lookahead and return 0;
+ / leading white spaces are not recoverable.
+ */
+ int c;
+ int len = 0;
+ int curgetptr = 0;
+ lexSkipWhite();
+ lexClearToken();
+ curgetptr = (int)lexBuf.getPtr; // remember!
+ while (len < (MAX_LEX_LOOKAHEAD_0)) {
+ c = lexGetc();
+ len++;
+ if (c == EOF || strchr("\t\n ;:=", c)) {
+ lexAppendc(0);
+ /* restore lookahead buf. */
+ lexBuf.len += len;
+ lexBuf.getPtr = curgetptr;
+ return lexStr();
+ }
+ else
+ lexAppendc(c);
+ }
+ lexBuf.len += len; /* char that has been moved to lookahead buffer */
+ lexBuf.getPtr = curgetptr;
+ return 0;
+ }
+
+#ifdef _SUPPORT_LINE_FOLDING
+static void handleMoreRFC822LineBreak(int c) {
+ /* suport RFC 822 line break in cases like
+ * ADR: foo;
+ * morefoo;
+ * more foo;
+ */
+ if (c == ';') {
+ int a;
+ lexSkipLookahead();
+ /* skip white spaces */
+ a = lexLookahead();
+ while (a == ' ' || a == '\t') {
+ lexSkipLookahead();
+ a = lexLookahead();
+ }
+ if (a == '\n') {
+ lexSkipLookahead();
+ a = lexLookahead();
+ if (a == ' ' || a == '\t') {
+ /* continuation, throw away all the \n and spaces read so
+ * far
+ */
+ lexSkipWhite();
+ lexPushLookaheadc(';');
+ }
+ else {
+ lexPushLookaheadc('\n');
+ lexPushLookaheadc(';');
+ }
+ }
+ else {
+ lexPushLookaheadc(';');
+ }
+ }
+ }
+
+static char* lexGet1Value() {
+ int c;
+ lexSkipWhite();
+ c = lexLookahead();
+ lexClearToken();
+ while (c != EOF && c != ';') {
+ if (c == '\\' ) {
+ int a;
+ lexSkipLookahead();
+ a = lexLookahead();
+ if ( a != ';' ) {
+ lexAppendc('\\');
+ } else {
+ lexAppendc( ';' );
+ lexSkipLookahead();
+ }
+ } else if (c == '\n') {
+ int a;
+ lexSkipLookahead();
+ a = lexLookahead();
+ if (a == ' ' || a == '\t') {
+ lexAppendc(' ');
+ lexSkipLookahead();
+ }
+ else {
+ lexPushLookaheadc('\n');
+ break;
+ }
+ }
+ else {
+ lexAppendc(c);
+ lexSkipLookahead();
+ }
+ c = lexLookahead();
+ }
+ lexAppendc(0);
+ handleMoreRFC822LineBreak(c);
+ return c==EOF?0:lexStr();
+ }
+#endif
+
+static int match_begin_name(int end) {
+ char *n = lexLookaheadWord();
+ int token = ID;
+ if (n) {
+ if (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
+ else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
+ else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
+ else if (!qstricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
+ deleteStr(n);
+ return token;
+ }
+ return 0;
+ }
+
+
+#ifdef INCLUDEMFC
+void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile)
+#else
+void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
+#endif
+ {
+ // initialize lex mode stack
+ lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
+
+ // iniatialize lex buffer.
+ lexBuf.inputString = (char*) inputstring;
+ lexBuf.inputLen = inputlen;
+ lexBuf.curPos = 0;
+ lexBuf.inputFile = inputfile;
+
+ lexBuf.len = 0;
+ lexBuf.getPtr = 0;
+
+ lexBuf.maxToken = MAXTOKEN;
+ lexBuf.strs = (char*)malloc(MAXTOKEN);
+ lexBuf.strsLen = 0;
+
+ }
+
+static void finiLex() {
+ free(lexBuf.strs);
+ }
+
+
+/*-----------------------------------*/
+/* This parses and converts the base64 format for binary encoding into
+ * a decoded buffer (allocated with new). See RFC 1521.
+ */
+static char * lexGetDataFromBase64()
+ {
+ unsigned long bytesLen = 0, bytesMax = 0;
+ int quadIx = 0, pad = 0;
+ unsigned long trip = 0;
+ unsigned char b;
+ int c;
+ unsigned char *bytes = NULL;
+ unsigned char *oldBytes = NULL;
+
+ DBG_(("db: lexGetDataFromBase64\n"));
+ while (1) {
+ c = lexGetc();
+ if (c == '\n') {
+ ++mime_lineNum;
+ if (lexLookahead() == '\n') {
+ /* a '\n' character by itself means end of data */
+ break;
+ }
+ else continue; /* ignore '\n' */
+ }
+ else {
+ if ((c >= 'A') && (c <= 'Z'))
+ b = (unsigned char)(c - 'A');
+ else if ((c >= 'a') && (c <= 'z'))
+ b = (unsigned char)(c - 'a') + 26;
+ else if ((c >= '0') && (c <= '9'))
+ b = (unsigned char)(c - '0') + 52;
+ else if (c == '+')
+ b = 62;
+ else if (c == '/')
+ b = 63;
+ else if (c == '=') {
+ b = 0;
+ pad++;
+ } else if ((c == ' ') || (c == '\t')) {
+ continue;
+ } else { /* error condition */
+ if (bytes) free(bytes);
+ else if (oldBytes) free(oldBytes);
+ // error recovery: skip until 2 adjacent newlines.
+ DBG_(("db: invalid character 0x%x '%c'\n", c,c));
+ if (c != EOF) {
+ c = lexGetc();
+ while (c != EOF) {
+ if (c == '\n' && lexLookahead() == '\n') {
+ ++mime_lineNum;
+ break;
+ }
+ c = lexGetc();
+ }
+ }
+ return NULL;
+ }
+ trip = (trip << 6) | b;
+ if (++quadIx == 4) {
+ unsigned char outBytes[3];
+ int numOut;
+ int i;
+ for (i = 0; i < 3; i++) {
+ outBytes[2-i] = (unsigned char)(trip & 0xFF);
+ trip >>= 8;
+ }
+ numOut = 3 - pad;
+ if (bytesLen + numOut > bytesMax) {
+ if (!bytes) {
+ bytesMax = 1024;
+ bytes = (unsigned char*)malloc((size_t)bytesMax);
+ }
+ else {
+ bytesMax <<= 2;
+ oldBytes = bytes;
+ bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
+ }
+ if (bytes == 0) {
+ mime_error("out of memory while processing BASE64 data\n");
+ }
+ }
+ if (bytes) {
+ memcpy(bytes + bytesLen, outBytes, numOut);
+ bytesLen += numOut;
+ }
+ trip = 0;
+ quadIx = 0;
+ }
+ }
+ } /* while */
+ DBG_(("db: bytesLen = %d\n", bytesLen));
+ /* kludge: all this won't be necessary if we have tree form
+ representation */
+ if (bytes) {
+ setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
+ free(bytes);
+ }
+ else if (oldBytes) {
+ setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
+ free(oldBytes);
+ }
+ return 0;
+ }
+
+static int match_begin_end_name(int end) {
+ int token;
+ lexSkipWhite();
+ if (lexLookahead() != ':') return ID;
+ lexSkipLookahead();
+ lexSkipWhite();
+ token = match_begin_name(end);
+ if (token == ID) {
+ lexPushLookaheadc(':');
+ DBG_(("db: ID '%s'\n", yylval.str));
+ return ID;
+ }
+ else if (token != 0) {
+ lexSkipLookaheadWord();
+ deleteStr(yylval.str);
+ DBG_(("db: begin/end %d\n", token));
+ return token;
+ }
+ return 0;
+ }
+
+static char* lexGetQuotedPrintable()
+ {
+ char cur;
+
+ lexClearToken();
+ do {
+ cur = lexGetc();
+ switch (cur) {
+ case '=': {
+ int c = 0;
+ int next[2];
+ int i;
+ for (i = 0; i < 2; i++) {
+ next[i] = lexGetc();
+ if (next[i] >= '0' && next[i] <= '9')
+ c = c * 16 + next[i] - '0';
+ else if (next[i] >= 'A' && next[i] <= 'F')
+ c = c * 16 + next[i] - 'A' + 10;
+ else
+ break;
+ }
+ if (i == 0) {
+ /* single '=' follow by LINESEP is continuation sign? */
+ if (next[0] == '\n') {
+ ++mime_lineNum;
+ }
+ else {
+ lexPushLookaheadc('=');
+ goto EndString;
+ }
+ }
+ else if (i == 1) {
+ lexPushLookaheadc(next[1]);
+ lexPushLookaheadc(next[0]);
+ lexAppendc('=');
+ } else {
+ lexAppendc(c);
+ }
+ break;
+ } /* '=' */
+ case '\n': {
+ lexPushLookaheadc('\n');
+ goto EndString;
+ }
+ case (char)EOF:
+ break;
+ default:
+ lexAppendc(cur);
+ break;
+ } /* switch */
+ } while (cur != (char)EOF);
+
+EndString:
+ lexAppendc(0);
+ return lexStr();
+ } /* LexQuotedPrintable */
+
+static int yylex() {
+
+ int lexmode = LEXMODE();
+ if (lexmode == L_VALUES) {
+ int c = lexGetc();
+ if (c == ';') {
+ DBG_(("db: SEMICOLON\n"));
+ lexPushLookaheadc(c);
+ handleMoreRFC822LineBreak(c);
+ lexSkipLookahead();
+ return SEMICOLON;
+ }
+ else if (strchr("\n",c)) {
+ ++mime_lineNum;
+ /* consume all line separator(s) adjacent to each other */
+ c = lexLookahead();
+ while (strchr("\n",c)) {
+ lexSkipLookahead();
+ c = lexLookahead();
+ ++mime_lineNum;
+ }
+ DBG_(("db: LINESEP\n"));
+ return LINESEP;
+ }
+ else {
+ char *p = 0;
+ lexPushLookaheadc(c);
+ if (lexWithinMode(L_BASE64)) {
+ /* get each char and convert to bin on the fly... */
+ p = lexGetDataFromBase64();
+ yylval.str = p;
+ return STRING;
+ }
+ else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
+ p = lexGetQuotedPrintable();
+ }
+ else {
+#ifdef _SUPPORT_LINE_FOLDING
+ p = lexGet1Value();
+#else
+ p = lexGetStrUntil(";\n");
+#endif
+ }
+ if (p) {
+ DBG_(("db: STRING: '%s'\n", p));
+ yylval.str = p;
+ return STRING;
+ }
+ else return 0;
+ }
+ }
+ else {
+ /* normal mode */
+ while (1) {
+ int c = lexGetc();
+ switch(c) {
+ case ':': {
+ /* consume all line separator(s) adjacent to each other */
+ /* ignoring linesep immediately after colon. */
+ c = lexLookahead();
+ while (strchr("\n",c)) {
+ lexSkipLookahead();
+ c = lexLookahead();
+ ++mime_lineNum;
+ }
+ DBG_(("db: COLON\n"));
+ return COLON;
+ }
+ case ';':
+ DBG_(("db: SEMICOLON\n"));
+ return SEMICOLON;
+ case '=':
+ DBG_(("db: EQ\n"));
+ return EQ;
+ /* ignore whitespace in this mode */
+ case '\t':
+ case ' ': continue;
+ case '\n': {
+ ++mime_lineNum;
+ continue;
+ }
+ case EOF: return 0;
+ break;
+ default: {
+ lexPushLookaheadc(c);
+ if (isalnum(c)) {
+ char *t = lexGetWord();
+ yylval.str = t;
+ if (!qstricmp(t, "begin")) {
+ return match_begin_end_name(0);
+ }
+ else if (!qstricmp(t,"end")) {
+ return match_begin_end_name(1);
+ }
+ else {
+ DBG_(("db: ID '%s'\n", t));
+ return ID;
+ }
+ }
+ else {
+ /* unknow token */
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+
+/***************************************************************************/
+/*** Public Functions ****/
+/***************************************************************************/
+
+static VObject* Parse_MIMEHelper()
+ {
+ ObjStackTop = -1;
+ mime_numErrors = 0;
+ mime_lineNum = 1;
+ vObjList = 0;
+ curObj = 0;
+
+ if (yyparse() != 0)
+ return 0;
+
+ finiLex();
+ return vObjList;
+ }
+
+/*--------------------------------------------*/
+DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len)
+ {
+ initLex(input, len, 0);
+ return Parse_MIMEHelper();
+ }
+
+
+#if INCLUDEMFC
+
+DLLEXPORT(VObject*) Parse_MIME_FromFile(CFile *file)
+ {
+ unsigned long startPos;
+ VObject *result;
+
+ initLex(0,-1,file);
+ startPos = file->GetPosition();
+ if (!(result = Parse_MIMEHelper()))
+ file->Seek(startPos, CFile::begin);
+ return result;
+ }
+
+#else
+
+VObject* Parse_MIME_FromFile(FILE *file)
+ {
+ VObject *result;
+ long startPos;
+
+ initLex(0,(unsigned long)-1,file);
+ startPos = ftell(file);
+ if (!(result = Parse_MIMEHelper())) {
+ fseek(file,startPos,SEEK_SET);
+ }
+ return result;
+ }
+
+DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname)
+ {
+ FILE *fp = fopen(fname,"r");
+ if (fp) {
+ VObject* o = Parse_MIME_FromFile(fp);
+ fclose(fp);
+ return o;
+ }
+ else {
+ char msg[80];
+ sprintf(msg, "can't open file '%s' for reading\n", fname);
+ mime_error_(msg);
+ return 0;
+ }
+ }
+
+#endif
+
+/*-------------------------------------*/
+
+static MimeErrorHandler mimeErrorHandler;
+
+DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me)
+ {
+ mimeErrorHandler = me;
+ }
+
+void mime_error(char *s)
+ {
+ char msg[256];
+ if (mimeErrorHandler) {
+ sprintf(msg,"%s at line %d", s, mime_lineNum);
+ mimeErrorHandler(msg);
+ }
+ }
+
+void mime_error_(char *s)
+ {
+ if (mimeErrorHandler) {
+ mimeErrorHandler(s);
+ }
+ }
+
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 @@ +/***************************************************************************
+(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+
+For purposes of this license notice, the term Licensors shall mean,
+collectively, Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+The term Licensor shall mean any of the Licensors.
+
+Subject to acceptance of the following conditions, permission is hereby
+granted by Licensors without the need for written agreement and without
+license or royalty fees, to use, copy, modify and distribute this
+software for any purpose.
+
+The above copyright notice and the following four paragraphs must be
+reproduced in all copies of this software and any software including
+this software.
+
+THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
+ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
+MODIFICATIONS.
+
+IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+
+The software is provided with RESTRICTED RIGHTS. Use, duplication, or
+disclosure by the government are subject to restrictions set forth in
+DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
+
+***************************************************************************/
+
+/*
+ * src: vobject.c
+ * doc: vobject and APIs to construct vobject, APIs pretty print
+ * vobject, and convert a vobject into its textual representation.
+ */
+
+#ifndef MWERKS
+#include <malloc.h>
+#endif
+
+#include "vobject_p.h"
+#include "qfiledirect_p.h"
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+//#include <io.h>
+
+
+#define NAME_OF(o) o->id
+#define VALUE_TYPE(o) o->valType
+#define STRINGZ_VALUE_OF(o) o->val.strs
+#define INTEGER_VALUE_OF(o) o->val.i
+#define LONG_VALUE_OF(o) o->val.l
+#define ANY_VALUE_OF(o) o->val.any
+#define VOBJECT_VALUE_OF(o) o->val.vobj
+
+typedef union ValueItem {
+ const char *strs;
+ unsigned int i;
+ unsigned long l;
+ void *any;
+ VObject *vobj;
+ } ValueItem;
+
+struct VObject {
+ VObject *next;
+ const char *id;
+ VObject *prop;
+ unsigned short valType;
+ ValueItem val;
+ };
+
+typedef struct StrItem StrItem;
+
+struct StrItem {
+ StrItem *next;
+ const char *s;
+ unsigned int refCnt;
+ };
+
+const char** fieldedProp;
+
+
+
+/*----------------------------------------------------------------------
+ The following functions involve with memory allocation:
+ newVObject
+ deleteVObject
+ dupStr
+ deleteStr
+ newStrItem
+ deleteStrItem
+ ----------------------------------------------------------------------*/
+
+DLLEXPORT(VObject*) newVObject_(const char *id)
+{
+ VObject *p = (VObject*)malloc(sizeof(VObject));
+ p->next = 0;
+ p->id = id;
+ p->prop = 0;
+ VALUE_TYPE(p) = 0;
+ ANY_VALUE_OF(p) = 0;
+ return p;
+}
+
+DLLEXPORT(VObject*) newVObject(const char *id)
+{
+ return newVObject_(lookupStr(id));
+}
+
+DLLEXPORT(void) deleteVObject(VObject *p)
+{
+ unUseStr(p->id);
+ free(p);
+}
+
+DLLEXPORT(char*) dupStr(const char *s, unsigned int size)
+{
+ char *t;
+ if (size == 0) {
+ size = strlen(s);
+ }
+ t = (char*)malloc(size+1);
+ if (t) {
+ memcpy(t,s,size);
+ t[size] = 0;
+ return t;
+ }
+ else {
+ return (char*)0;
+ }
+}
+
+DLLEXPORT(void) deleteStr(const char *p)
+{
+ if (p) free((void*)p);
+}
+
+
+static StrItem* newStrItem(const char *s, StrItem *next)
+{
+ StrItem *p = (StrItem*)malloc(sizeof(StrItem));
+ p->next = next;
+ p->s = s;
+ p->refCnt = 1;
+ return p;
+}
+
+static void deleteStrItem(StrItem *p)
+{
+ free((void*)p);
+}
+
+
+/*----------------------------------------------------------------------
+ The following function provide accesses to VObject's value.
+ ----------------------------------------------------------------------*/
+
+DLLEXPORT(const char*) vObjectName(VObject *o)
+{
+ return NAME_OF(o);
+}
+
+DLLEXPORT(void) setVObjectName(VObject *o, const char* id)
+{
+ NAME_OF(o) = id;
+}
+
+DLLEXPORT(const char*) vObjectStringZValue(VObject *o)
+{
+ return STRINGZ_VALUE_OF(o);
+}
+
+DLLEXPORT(void) setVObjectStringZValue(VObject *o, const char *s)
+{
+ STRINGZ_VALUE_OF(o) = dupStr(s,0);
+ VALUE_TYPE(o) = VCVT_STRINGZ;
+}
+
+DLLEXPORT(void) setVObjectStringZValue_(VObject *o, const char *s)
+{
+ STRINGZ_VALUE_OF(o) = s;
+ VALUE_TYPE(o) = VCVT_STRINGZ;
+}
+
+DLLEXPORT(unsigned int) vObjectIntegerValue(VObject *o)
+{
+ return INTEGER_VALUE_OF(o);
+}
+
+DLLEXPORT(void) setVObjectIntegerValue(VObject *o, unsigned int i)
+{
+ INTEGER_VALUE_OF(o) = i;
+ VALUE_TYPE(o) = VCVT_UINT;
+}
+
+DLLEXPORT(unsigned long) vObjectLongValue(VObject *o)
+{
+ return LONG_VALUE_OF(o);
+}
+
+DLLEXPORT(void) setVObjectLongValue(VObject *o, unsigned long l)
+{
+ LONG_VALUE_OF(o) = l;
+ VALUE_TYPE(o) = VCVT_ULONG;
+}
+
+DLLEXPORT(void*) vObjectAnyValue(VObject *o)
+{
+ return ANY_VALUE_OF(o);
+}
+
+DLLEXPORT(void) setVObjectAnyValue(VObject *o, void *t)
+{
+ ANY_VALUE_OF(o) = t;
+ VALUE_TYPE(o) = VCVT_RAW;
+}
+
+DLLEXPORT(VObject*) vObjectVObjectValue(VObject *o)
+{
+ return VOBJECT_VALUE_OF(o);
+}
+
+DLLEXPORT(void) setVObjectVObjectValue(VObject *o, VObject *p)
+{
+ VOBJECT_VALUE_OF(o) = p;
+ VALUE_TYPE(o) = VCVT_VOBJECT;
+}
+
+DLLEXPORT(int) vObjectValueType(VObject *o)
+{
+ return VALUE_TYPE(o);
+}
+
+
+/*----------------------------------------------------------------------
+ The following functions can be used to build VObject.
+ ----------------------------------------------------------------------*/
+
+DLLEXPORT(VObject*) addVObjectProp(VObject *o, VObject *p)
+{
+ /* circular link list pointed to tail */
+ /*
+ o {next,id,prop,val}
+ V
+ pn {next,id,prop,val}
+ V
+ ...
+ p1 {next,id,prop,val}
+ V
+ pn
+ -->
+ o {next,id,prop,val}
+ V
+ pn {next,id,prop,val}
+ V
+ p {next,id,prop,val}
+ ...
+ p1 {next,id,prop,val}
+ V
+ pn
+ */
+
+ VObject *tail = o->prop;
+ if (tail) {
+ p->next = tail->next;
+ o->prop = tail->next = p;
+ }
+ else {
+ o->prop = p->next = p;
+ }
+ return p;
+}
+
+DLLEXPORT(VObject*) addProp(VObject *o, const char *id)
+{
+ return addVObjectProp(o,newVObject(id));
+}
+
+DLLEXPORT(VObject*) addProp_(VObject *o, const char *id)
+{
+ return addVObjectProp(o,newVObject_(id));
+}
+
+DLLEXPORT(void) addList(VObject **o, VObject *p)
+{
+ p->next = 0;
+ if (*o == 0) {
+ *o = p;
+ }
+ else {
+ VObject *t = *o;
+ while (t->next) {
+ t = t->next;
+ }
+ t->next = p;
+ }
+}
+
+DLLEXPORT(VObject*) nextVObjectInList(VObject *o)
+{
+ return o->next;
+}
+
+DLLEXPORT(VObject*) setValueWithSize_(VObject *prop, void *val, unsigned int size)
+{
+ VObject *sizeProp;
+ setVObjectAnyValue(prop, val);
+ sizeProp = addProp(prop,VCDataSizeProp);
+ setVObjectLongValue(sizeProp, size);
+ return prop;
+}
+
+DLLEXPORT(VObject*) setValueWithSize(VObject *prop, void *val, unsigned int size)
+{
+ void *p = dupStr((const char *)val,size);
+ return setValueWithSize_(prop,p,p?size:0);
+}
+
+DLLEXPORT(void) initPropIterator(VObjectIterator *i, VObject *o)
+{
+ i->start = o->prop;
+ i->next = 0;
+}
+
+DLLEXPORT(void) initVObjectIterator(VObjectIterator *i, VObject *o)
+{
+ i->start = o->next;
+ i->next = 0;
+}
+
+DLLEXPORT(int) moreIteration(VObjectIterator *i)
+{
+ return (i->start && (i->next==0 || i->next!=i->start));
+}
+
+DLLEXPORT(VObject*) nextVObject(VObjectIterator *i)
+{
+ if (i->start && i->next != i->start) {
+ if (i->next == 0) {
+ i->next = i->start->next;
+ return i->next;
+ }
+ else {
+ i->next = i->next->next;
+ return i->next;
+ }
+ }
+ else return (VObject*)0;
+}
+
+DLLEXPORT(VObject*) isAPropertyOf(VObject *o, const char *id)
+{
+ VObjectIterator i;
+ initPropIterator(&i,o);
+ while (moreIteration(&i)) {
+ VObject *each = nextVObject(&i);
+ if (!qstricmp(id,each->id))
+ return each;
+ }
+ return (VObject*)0;
+}
+
+DLLEXPORT(VObject*) addGroup(VObject *o, const char *g)
+{
+ /*
+ a.b.c
+ -->
+ prop(c)
+ prop(VCGrouping=b)
+ prop(VCGrouping=a)
+ */
+ char *dot = strrchr(g,'.');
+ if (dot) {
+ VObject *p, *t;
+ char *gs, *n = dot+1;
+ gs = dupStr(g,0); /* so we can write to it. */
+ /* used to be
+ * t = p = addProp_(o,lookupProp_(n));
+ */
+ t = p = addProp_(o,lookupProp(n));
+ dot = strrchr(gs,'.');
+ *dot = 0;
+ do {
+ dot = strrchr(gs,'.');
+ if (dot) {
+ n = dot+1;
+ *dot=0;
+ }
+ else
+ n = gs;
+ /* property(VCGroupingProp=n);
+ * and the value may have VCGrouping property
+ */
+ t = addProp(t,VCGroupingProp);
+ setVObjectStringZValue(t,lookupProp_(n));
+ } while (n != gs);
+ deleteStr(gs);
+ return p;
+ }
+ else
+ return addProp_(o,lookupProp(g));
+}
+
+DLLEXPORT(VObject*) addPropValue(VObject *o, const char *p, const char *v)
+{
+ VObject *prop;
+ prop = addProp(o,p);
+ setVObjectStringZValue_(prop, strdup( v ) );
+ return prop;
+}
+
+DLLEXPORT(VObject*) addPropSizedValue_(VObject *o, const char *p, const char *v,
+ unsigned int size)
+{
+ VObject *prop;
+ prop = addProp(o,p);
+ setValueWithSize_(prop, (void*)v, size);
+ return prop;
+}
+
+DLLEXPORT(VObject*) addPropSizedValue(VObject *o, const char *p, const char *v,
+ unsigned int size)
+{
+ return addPropSizedValue_(o,p,dupStr(v,size),size);
+}
+
+
+DLLEXPORT(void) cleanVObject(VObject *o)
+{
+ if (o == 0) return;
+ if (o->prop) {
+ /* destroy time: cannot use the iterator here.
+ Have to break the cycle in the circular link
+ list and turns it into regular NULL-terminated
+ list -- since at some point of destruction,
+ the reference entry for the iterator to work
+ will not longer be valid.
+ */
+ VObject *p;
+ p = o->prop->next;
+ o->prop->next = 0;
+ do {
+ VObject *t = p->next;
+ cleanVObject(p);
+ p = t;
+ } while (p);
+ }
+ switch (VALUE_TYPE(o)) {
+ case VCVT_STRINGZ:
+ case VCVT_RAW:
+ // assume they are all allocated by malloc.
+ free((char*)STRINGZ_VALUE_OF(o));
+ break;
+ case VCVT_VOBJECT:
+ cleanVObject(VOBJECT_VALUE_OF(o));
+ break;
+ }
+ deleteVObject(o);
+}
+
+DLLEXPORT(void) cleanVObjects(VObject *list)
+{
+ while (list) {
+ VObject *t = list;
+ list = nextVObjectInList(list);
+ cleanVObject(t);
+ }
+}
+
+/*----------------------------------------------------------------------
+ The following is a String Table Facilities.
+ ----------------------------------------------------------------------*/
+
+#define STRTBLSIZE 255
+
+static StrItem *strTbl[STRTBLSIZE];
+
+static unsigned int hashStr(const char *s)
+{
+ unsigned int h = 0;
+ int i;
+ for (i=0;s[i];i++) {
+ h += s[i]*i;
+ }
+ return h % STRTBLSIZE;
+}
+
+DLLEXPORT(const char*) lookupStr(const char *s)
+{
+ StrItem *t;
+ unsigned int h = hashStr(s);
+ if ((t = strTbl[h]) != 0) {
+ do {
+ if (qstricmp(t->s,s) == 0) {
+ t->refCnt++;
+ return t->s;
+ }
+ t = t->next;
+ } while (t);
+ }
+ s = dupStr(s,0);
+ strTbl[h] = newStrItem(s,strTbl[h]);
+ return s;
+}
+
+DLLEXPORT(void) unUseStr(const char *s)
+{
+ StrItem *t, *p;
+ unsigned int h = hashStr(s);
+ if ((t = strTbl[h]) != 0) {
+ p = t;
+ do {
+ if (qstricmp(t->s,s) == 0) {
+ t->refCnt--;
+ if (t->refCnt == 0) {
+ if (p == strTbl[h]) {
+ strTbl[h] = t->next;
+ }
+ else {
+ p->next = t->next;
+ }
+ deleteStr(t->s);
+ deleteStrItem(t);
+ return;
+ }
+ }
+ p = t;
+ t = t->next;
+ } while (t);
+ }
+}
+
+DLLEXPORT(void) cleanStrTbl()
+{
+ int i;
+ for (i=0; i<STRTBLSIZE;i++) {
+ StrItem *t = strTbl[i];
+ while (t) {
+ StrItem *p;
+ deleteStr(t->s);
+ p = t;
+ t = t->next;
+ deleteStrItem(p);
+ } while (t);
+ strTbl[i] = 0;
+ }
+}
+
+
+struct PreDefProp {
+ const char *name;
+ const char *alias;
+ const char** fields;
+ unsigned int flags;
+ };
+
+/* flags in PreDefProp */
+#define PD_BEGIN 0x1
+#define PD_INTERNAL 0x2
+
+static const char *adrFields[] = {
+ VCPostalBoxProp,
+ VCExtAddressProp,
+ VCStreetAddressProp,
+ VCCityProp,
+ VCRegionProp,
+ VCPostalCodeProp,
+ VCCountryNameProp,
+ 0
+};
+
+static const char *nameFields[] = {
+ VCFamilyNameProp,
+ VCGivenNameProp,
+ VCAdditionalNamesProp,
+ VCNamePrefixesProp,
+ VCNameSuffixesProp,
+ NULL
+ };
+
+static const char *orgFields[] = {
+ VCOrgNameProp,
+ VCOrgUnitProp,
+ VCOrgUnit2Prop,
+ VCOrgUnit3Prop,
+ VCOrgUnit4Prop,
+ NULL
+ };
+
+static const char *AAlarmFields[] = {
+ VCRunTimeProp,
+ VCSnoozeTimeProp,
+ VCRepeatCountProp,
+ VCAudioContentProp,
+ 0
+ };
+
+/* ExDate -- has unamed fields */
+/* RDate -- has unamed fields */
+
+static const char *DAlarmFields[] = {
+ VCRunTimeProp,
+ VCSnoozeTimeProp,
+ VCRepeatCountProp,
+ VCDisplayStringProp,
+ 0
+ };
+
+static const char *MAlarmFields[] = {
+ VCRunTimeProp,
+ VCSnoozeTimeProp,
+ VCRepeatCountProp,
+ VCEmailAddressProp,
+ VCNoteProp,
+ 0
+ };
+
+static const char *PAlarmFields[] = {
+ VCRunTimeProp,
+ VCSnoozeTimeProp,
+ VCRepeatCountProp,
+ VCProcedureNameProp,
+ 0
+ };
+
+static struct PreDefProp propNames[] = {
+ { VC7bitProp, 0, 0, 0 },
+ { VC8bitProp, 0, 0, 0 },
+ { VCAAlarmProp, 0, AAlarmFields, 0 },
+ { VCAdditionalNamesProp, 0, 0, 0 },
+ { VCAdrProp, 0, adrFields, 0 },
+ { VCAgentProp, 0, 0, 0 },
+ { VCAIFFProp, 0, 0, 0 },
+ { VCAOLProp, 0, 0, 0 },
+ { VCAppleLinkProp, 0, 0, 0 },
+ { VCAttachProp, 0, 0, 0 },
+ { VCAttendeeProp, 0, 0, 0 },
+ { VCATTMailProp, 0, 0, 0 },
+ { VCAudioContentProp, 0, 0, 0 },
+ { VCAVIProp, 0, 0, 0 },
+ { VCBase64Prop, 0, 0, 0 },
+ { VCBBSProp, 0, 0, 0 },
+ { VCBirthDateProp, 0, 0, 0 },
+ { VCBMPProp, 0, 0, 0 },
+ { VCBodyProp, 0, 0, 0 },
+ { VCBusinessRoleProp, 0, 0, 0 },
+ { VCCalProp, 0, 0, PD_BEGIN },
+ { VCCaptionProp, 0, 0, 0 },
+ { VCCardProp, 0, 0, PD_BEGIN },
+ { VCCarProp, 0, 0, 0 },
+ { VCCategoriesProp, 0, 0, 0 },
+ { VCCellularProp, 0, 0, 0 },
+ { VCCGMProp, 0, 0, 0 },
+ { VCCharSetProp, 0, 0, 0 },
+ { VCCIDProp, VCContentIDProp, 0, 0 },
+ { VCCISProp, 0, 0, 0 },
+ { VCCityProp, 0, 0, 0 },
+ { VCClassProp, 0, 0, 0 },
+ { VCCommentProp, 0, 0, 0 },
+ { VCCompletedProp, 0, 0, 0 },
+ { VCContentIDProp, 0, 0, 0 },
+ { VCCountryNameProp, 0, 0, 0 },
+ { VCDAlarmProp, 0, DAlarmFields, 0 },
+ { VCDataSizeProp, 0, 0, PD_INTERNAL },
+ { VCDayLightProp, 0, 0, 0 },
+ { VCDCreatedProp, 0, 0, 0 },
+ { VCDeliveryLabelProp, 0, 0, 0 },
+ { VCDescriptionProp, 0, 0, 0 },
+ { VCDIBProp, 0, 0, 0 },
+ { VCDisplayStringProp, 0, 0, 0 },
+ { VCDomesticProp, 0, 0, 0 },
+ { VCDTendProp, 0, 0, 0 },
+ { VCDTstartProp, 0, 0, 0 },
+ { VCDueProp, 0, 0, 0 },
+ { VCEmailAddressProp, 0, 0, 0 },
+ { VCEncodingProp, 0, 0, 0 },
+ { VCEndProp, 0, 0, 0 },
+ { VCEventProp, 0, 0, PD_BEGIN },
+ { VCEWorldProp, 0, 0, 0 },
+ { VCExNumProp, 0, 0, 0 },
+ { VCExpDateProp, 0, 0, 0 },
+ { VCExpectProp, 0, 0, 0 },
+ { VCExtAddressProp, 0, 0, 0 },
+ { VCFamilyNameProp, 0, 0, 0 },
+ { VCFaxProp, 0, 0, 0 },
+ { VCFullNameProp, 0, 0, 0 },
+ { VCGeoLocationProp, 0, 0, 0 },
+ { VCGeoProp, 0, 0, 0 },
+ { VCGIFProp, 0, 0, 0 },
+ { VCGivenNameProp, 0, 0, 0 },
+ { VCGroupingProp, 0, 0, 0 },
+ { VCHomeProp, 0, 0, 0 },
+ { VCIBMMailProp, 0, 0, 0 },
+ { VCInlineProp, 0, 0, 0 },
+ { VCInternationalProp, 0, 0, 0 },
+ { VCInternetProp, 0, 0, 0 },
+ { VCISDNProp, 0, 0, 0 },
+ { VCJPEGProp, 0, 0, 0 },
+ { VCLanguageProp, 0, 0, 0 },
+ { VCLastModifiedProp, 0, 0, 0 },
+ { VCLastRevisedProp, 0, 0, 0 },
+ { VCLocationProp, 0, 0, 0 },
+ { VCLogoProp, 0, 0, 0 },
+ { VCMailerProp, 0, 0, 0 },
+ { VCMAlarmProp, 0, MAlarmFields, 0 },
+ { VCMCIMailProp, 0, 0, 0 },
+ { VCMessageProp, 0, 0, 0 },
+ { VCMETProp, 0, 0, 0 },
+ { VCModemProp, 0, 0, 0 },
+ { VCMPEG2Prop, 0, 0, 0 },
+ { VCMPEGProp, 0, 0, 0 },
+ { VCMSNProp, 0, 0, 0 },
+ { VCNamePrefixesProp, 0, 0, 0 },
+ { VCNameProp, 0, nameFields, 0 },
+ { VCNameSuffixesProp, 0, 0, 0 },
+ { VCNoteProp, 0, 0, 0 },
+ { VCOrgNameProp, 0, 0, 0 },
+ { VCOrgProp, 0, orgFields, 0 },
+ { VCOrgUnit2Prop, 0, 0, 0 },
+ { VCOrgUnit3Prop, 0, 0, 0 },
+ { VCOrgUnit4Prop, 0, 0, 0 },
+ { VCOrgUnitProp, 0, 0, 0 },
+ { VCPagerProp, 0, 0, 0 },
+ { VCPAlarmProp, 0, PAlarmFields, 0 },
+ { VCParcelProp, 0, 0, 0 },
+ { VCPartProp, 0, 0, 0 },
+ { VCPCMProp, 0, 0, 0 },
+ { VCPDFProp, 0, 0, 0 },
+ { VCPGPProp, 0, 0, 0 },
+ { VCPhotoProp, 0, 0, 0 },
+ { VCPICTProp, 0, 0, 0 },
+ { VCPMBProp, 0, 0, 0 },
+ { VCPostalBoxProp, 0, 0, 0 },
+ { VCPostalCodeProp, 0, 0, 0 },
+ { VCPostalProp, 0, 0, 0 },
+ { VCPowerShareProp, 0, 0, 0 },
+ { VCPreferredProp, 0, 0, 0 },
+ { VCPriorityProp, 0, 0, 0 },
+ { VCProcedureNameProp, 0, 0, 0 },
+ { VCProdIdProp, 0, 0, 0 },
+ { VCProdigyProp, 0, 0, 0 },
+ { VCPronunciationProp, 0, 0, 0 },
+ { VCPSProp, 0, 0, 0 },
+ { VCPublicKeyProp, 0, 0, 0 },
+ { VCQPProp, VCQuotedPrintableProp, 0, 0 },
+ { VCQuickTimeProp, 0, 0, 0 },
+ { VCQuotedPrintableProp, 0, 0, 0 },
+ { VCRDateProp, 0, 0, 0 },
+ { VCRegionProp, 0, 0, 0 },
+ { VCRelatedToProp, 0, 0, 0 },
+ { VCRepeatCountProp, 0, 0, 0 },
+ { VCResourcesProp, 0, 0, 0 },
+ { VCRNumProp, 0, 0, 0 },
+ { VCRoleProp, 0, 0, 0 },
+ { VCRRuleProp, 0, 0, 0 },
+ { VCRSVPProp, 0, 0, 0 },
+ { VCRunTimeProp, 0, 0, 0 },
+ { VCSequenceProp, 0, 0, 0 },
+ { VCSnoozeTimeProp, 0, 0, 0 },
+ { VCStartProp, 0, 0, 0 },
+ { VCStatusProp, 0, 0, 0 },
+ { VCStreetAddressProp, 0, 0, 0 },
+ { VCSubTypeProp, 0, 0, 0 },
+ { VCSummaryProp, 0, 0, 0 },
+ { VCTelephoneProp, 0, 0, 0 },
+ { VCTIFFProp, 0, 0, 0 },
+ { VCTimeZoneProp, 0, 0, 0 },
+ { VCTitleProp, 0, 0, 0 },
+ { VCTLXProp, 0, 0, 0 },
+ { VCTodoProp, 0, 0, PD_BEGIN },
+ { VCTranspProp, 0, 0, 0 },
+ { VCUniqueStringProp, 0, 0, 0 },
+ { VCURLProp, 0, 0, 0 },
+ { VCURLValueProp, 0, 0, 0 },
+ { VCValueProp, 0, 0, 0 },
+ { VCVersionProp, 0, 0, 0 },
+ { VCVideoProp, 0, 0, 0 },
+ { VCVoiceProp, 0, 0, 0 },
+ { VCWAVEProp, 0, 0, 0 },
+ { VCWMFProp, 0, 0, 0 },
+ { VCWorkProp, 0, 0, 0 },
+ { VCX400Prop, 0, 0, 0 },
+ { VCX509Prop, 0, 0, 0 },
+ { VCXRuleProp, 0, 0, 0 },
+ { 0,0,0,0 }
+ };
+
+
+static struct PreDefProp* lookupPropInfo(const char* str)
+{
+ /* brute force for now, could use a hash table here. */
+ int i;
+
+ for (i = 0; propNames[i].name; i++)
+ if (qstricmp(str, propNames[i].name) == 0) {
+ return &propNames[i];
+ }
+
+ return 0;
+}
+
+
+DLLEXPORT(const char*) lookupProp_(const char* str)
+{
+ int i;
+
+ for (i = 0; propNames[i].name; i++)
+ if (qstricmp(str, propNames[i].name) == 0) {
+ const char* s;
+ s = propNames[i].alias?propNames[i].alias:propNames[i].name;
+ return lookupStr(s);
+ }
+ return lookupStr(str);
+}
+
+
+DLLEXPORT(const char*) lookupProp(const char* str)
+{
+ int i;
+
+ for (i = 0; propNames[i].name; i++)
+ if (qstricmp(str, propNames[i].name) == 0) {
+ const char *s;
+ fieldedProp = propNames[i].fields;
+ s = propNames[i].alias?propNames[i].alias:propNames[i].name;
+ return lookupStr(s);
+ }
+ fieldedProp = 0;
+ return lookupStr(str);
+}
+
+
+/*----------------------------------------------------------------------
+ APIs to Output text form.
+ ----------------------------------------------------------------------*/
+#define OFILE_REALLOC_SIZE 256
+typedef struct OFile {
+ FILE *fp;
+ char *s;
+ int len;
+ int limit;
+ int alloc:1;
+ int fail:1;
+ } OFile;
+
+#if 0
+static void appendsOFile(OFile *fp, const char *s)
+{
+ int slen;
+ if (fp->fail) return;
+ slen = strlen(s);
+ if (fp->fp) {
+ fwrite(s,1,slen,fp->fp);
+ }
+ else {
+stuff:
+ if (fp->len + slen < fp->limit) {
+ memcpy(fp->s+fp->len,s,slen);
+ fp->len += slen;
+ return;
+ }
+ else if (fp->alloc) {
+ fp->limit = fp->limit + OFILE_REALLOC_SIZE;
+ if (OFILE_REALLOC_SIZE <= slen) fp->limit += slen;
+ fp->s = (char *) realloc(fp->s,fp->limit);
+ if (fp->s) goto stuff;
+ }
+ if (fp->alloc)
+ free(fp->s);
+ fp->s = 0;
+ fp->fail = 1;
+ }
+}
+
+static void appendcOFile(OFile *fp, char c)
+{
+ if (fp->fail) return;
+ if (fp->fp) {
+ fputc(c,fp->fp);
+ }
+ else {
+stuff:
+ if (fp->len+1 < fp->limit) {
+ fp->s[fp->len] = c;
+ fp->len++;
+ return;
+ }
+ else if (fp->alloc) {
+ fp->limit = fp->limit + OFILE_REALLOC_SIZE;
+ fp->s = (char *) realloc(fp->s,fp->limit);
+ if (fp->s) goto stuff;
+ }
+ if (fp->alloc)
+ free(fp->s);
+ fp->s = 0;
+ fp->fail = 1;
+ }
+}
+#else
+static void appendcOFile_(OFile *fp, char c)
+{
+ if (fp->fail) return;
+ if (fp->fp) {
+ fputc(c,fp->fp);
+ }
+ else {
+stuff:
+ if (fp->len+1 < fp->limit) {
+ fp->s[fp->len] = c;
+ fp->len++;
+ return;
+ }
+ else if (fp->alloc) {
+ fp->limit = fp->limit + OFILE_REALLOC_SIZE;
+ fp->s = (char *)realloc(fp->s,fp->limit);
+ if (fp->s) goto stuff;
+ }
+ if (fp->alloc)
+ free(fp->s);
+ fp->s = 0;
+ fp->fail = 1;
+ }
+}
+
+static void appendcOFile(OFile *fp, char c)
+{
+ if (c == '\n') {
+ /* write out as <CR><LF> */
+ appendcOFile_(fp,0xd);
+ appendcOFile_(fp,0xa);
+ }
+ else
+ appendcOFile_(fp,c);
+}
+
+static void appendsOFile(OFile *fp, const char *s)
+{
+ int i, slen;
+ slen = strlen(s);
+ for (i=0; i<slen; i++) {
+ appendcOFile(fp,s[i]);
+ }
+}
+
+#endif
+
+static void initOFile(OFile *fp, FILE *ofp)
+{
+ fp->fp = ofp;
+ fp->s = 0;
+ fp->len = 0;
+ fp->limit = 0;
+ fp->alloc = 0;
+ fp->fail = 0;
+}
+
+static int writeBase64(OFile *fp, unsigned char *s, long len)
+{
+ long cur = 0;
+ int i, numQuads = 0;
+ unsigned long trip;
+ unsigned char b;
+ char quad[5];
+#define MAXQUADS 16
+
+ quad[4] = 0;
+
+ while (cur < len) {
+ // collect the triplet of bytes into 'trip'
+ trip = 0;
+ for (i = 0; i < 3; i++) {
+ b = (cur < len) ? *(s + cur) : 0;
+ cur++;
+ trip = trip << 8 | b;
+ }
+ // fill in 'quad' with the appropriate four characters
+ for (i = 3; i >= 0; i--) {
+ b = (unsigned char)(trip & 0x3F);
+ trip = trip >> 6;
+ if ((3 - i) < (cur - len))
+ quad[i] = '='; // pad char
+ else if (b < 26) quad[i] = (char)b + 'A';
+ else if (b < 52) quad[i] = (char)(b - 26) + 'a';
+ else if (b < 62) quad[i] = (char)(b - 52) + '0';
+ else if (b == 62) quad[i] = '+';
+ else quad[i] = '/';
+ }
+ // now output 'quad' with appropriate whitespace and line ending
+ appendsOFile(fp, (numQuads == 0 ? " " : ""));
+ appendsOFile(fp, quad);
+ appendsOFile(fp, ((cur >= len)?"\n" :(numQuads==MAXQUADS-1?"\n" : "")));
+ numQuads = (numQuads + 1) % MAXQUADS;
+ }
+ appendcOFile(fp,'\n');
+
+ return 1;
+}
+
+static void writeQPString(OFile *fp, const char *s)
+{
+ const char *p = s;
+ while (*p) {
+ if (*p == '\n') {
+ if (p[1]) appendsOFile(fp,"=0A=");
+ }
+ appendcOFile(fp,*p);
+ p++;
+ }
+}
+
+
+
+static void writeVObject_(OFile *fp, VObject *o);
+
+static void writeValue(OFile *fp, VObject *o, unsigned long size)
+{
+ if (o == 0) return;
+ switch (VALUE_TYPE(o)) {
+ case VCVT_STRINGZ: {
+ writeQPString(fp, STRINGZ_VALUE_OF(o));
+ break;
+ }
+ case VCVT_UINT: {
+ char buf[16];
+ sprintf(buf,"%u", INTEGER_VALUE_OF(o));
+ appendsOFile(fp,buf);
+ break;
+ }
+ case VCVT_ULONG: {
+ char buf[16];
+ sprintf(buf,"%lu", LONG_VALUE_OF(o));
+ appendsOFile(fp,buf);
+ break;
+ }
+ case VCVT_RAW: {
+ appendcOFile(fp,'\n');
+ writeBase64(fp,(unsigned char*)(ANY_VALUE_OF(o)),size);
+ break;
+ }
+ case VCVT_VOBJECT:
+ appendcOFile(fp,'\n');
+ writeVObject_(fp,VOBJECT_VALUE_OF(o));
+ break;
+ }
+}
+
+static void writeAttrValue(OFile *fp, VObject *o)
+{
+ if (NAME_OF(o)) {
+ struct PreDefProp *pi;
+ pi = lookupPropInfo(NAME_OF(o));
+ if (pi && ((pi->flags & PD_INTERNAL) != 0)) return;
+ appendcOFile(fp,';');
+ appendsOFile(fp,NAME_OF(o));
+ }
+ else
+ appendcOFile(fp,';');
+ if (VALUE_TYPE(o)) {
+ appendcOFile(fp,'=');
+ writeValue(fp,o,0);
+ }
+}
+
+static void writeGroup(OFile *fp, VObject *o)
+{
+ char buf1[256];
+ char buf2[256];
+ strcpy(buf1,NAME_OF(o));
+ while ((o=isAPropertyOf(o,VCGroupingProp)) != 0) {
+ strcpy(buf2,STRINGZ_VALUE_OF(o));
+ strcat(buf2,".");
+ strcat(buf2,buf1);
+ strcpy(buf1,buf2);
+ }
+ appendsOFile(fp,buf1);
+}
+
+static int inList(const char **list, const char *s)
+{
+ if (list == 0) return 0;
+ while (*list) {
+ if (qstricmp(*list,s) == 0) return 1;
+ list++;
+ }
+ return 0;
+}
+
+static void writeProp(OFile *fp, VObject *o)
+{
+ if (NAME_OF(o)) {
+ struct PreDefProp *pi;
+ VObjectIterator t;
+ const char **fields_ = 0;
+ pi = lookupPropInfo(NAME_OF(o));
+ if (pi && ((pi->flags & PD_BEGIN) != 0)) {
+ writeVObject_(fp,o);
+ return;
+ }
+ if (isAPropertyOf(o,VCGroupingProp))
+ writeGroup(fp,o);
+ else
+ appendsOFile(fp,NAME_OF(o));
+ if (pi) fields_ = pi->fields;
+ initPropIterator(&t,o);
+ while (moreIteration(&t)) {
+ const char *s;
+ VObject *eachProp = nextVObject(&t);
+ s = NAME_OF(eachProp);
+ if (qstricmp(VCGroupingProp,s) && !inList(fields_,s))
+ writeAttrValue(fp,eachProp);
+ }
+ if (fields_) {
+ int i = 0, n = 0;
+ const char** fields = fields_;
+ /* output prop as fields */
+ appendcOFile(fp,':');
+ while (*fields) {
+ VObject *t = isAPropertyOf(o,*fields);
+ i++;
+ if (t) n = i;
+ fields++;
+ }
+ fields = fields_;
+ for (i=0;i<n;i++) {
+ writeValue(fp,isAPropertyOf(o,*fields),0);
+ fields++;
+ if (i<(n-1)) appendcOFile(fp,';');
+ }
+ }
+ }
+
+ if (VALUE_TYPE(o)) {
+ unsigned long size = 0;
+ VObject *p = isAPropertyOf(o,VCDataSizeProp);
+ if (p) size = LONG_VALUE_OF(p);
+ appendcOFile(fp,':');
+ writeValue(fp,o,size);
+ }
+
+ appendcOFile(fp,'\n');
+}
+
+static void writeVObject_(OFile *fp, VObject *o)
+{
+ if (NAME_OF(o)) {
+ struct PreDefProp *pi;
+ pi = lookupPropInfo(NAME_OF(o));
+
+ if (pi && ((pi->flags & PD_BEGIN) != 0)) {
+ VObjectIterator t;
+ const char *begin = NAME_OF(o);
+ appendsOFile(fp,"BEGIN:");
+ appendsOFile(fp,begin);
+ appendcOFile(fp,'\n');
+ initPropIterator(&t,o);
+ while (moreIteration(&t)) {
+ VObject *eachProp = nextVObject(&t);
+ writeProp(fp, eachProp);
+ }
+ appendsOFile(fp,"END:");
+ appendsOFile(fp,begin);
+ appendsOFile(fp,"\n\n");
+ }
+ }
+}
+
+void writeVObject(FILE *fp, VObject *o)
+{
+ OFile ofp;
+ // #####
+ //_setmode(_fileno(fp), _O_BINARY);
+ initOFile(&ofp,fp);
+ writeVObject_(&ofp,o);
+}
+
+DLLEXPORT(void) writeVObjectToFile(char *fname, VObject *o)
+{
+ QFileDirect f( fname);
+ if ( !f.open( IO_WriteOnly ) ) {
+ qWarning("Unable to open vobject write %s", fname);
+ return;
+ }
+
+ writeVObject( f.directHandle(),o );
+}
+
+DLLEXPORT(void) writeVObjectsToFile(char *fname, VObject *list)
+{
+ QFileDirect f( fname);
+ if ( !f.open( IO_WriteOnly ) ) {
+ qWarning("Unable to open vobject write %s", fname);
+ return;
+ }
+
+ while (list) {
+ writeVObject(f.directHandle(),list);
+ list = nextVObjectInList(list);
+ }
+}
+
+// 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 @@ +/***************************************************************************
+(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+
+For purposes of this license notice, the term Licensors shall mean,
+collectively, Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+The term Licensor shall mean any of the Licensors.
+
+Subject to acceptance of the following conditions, permission is hereby
+granted by Licensors without the need for written agreement and without
+license or royalty fees, to use, copy, modify and distribute this
+software for any purpose.
+
+The above copyright notice and the following four paragraphs must be
+reproduced in all copies of this software and any software including
+this software.
+
+THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
+ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
+MODIFICATIONS.
+
+IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+
+The software is provided with RESTRICTED RIGHTS. Use, duplication, or
+disclosure by the government are subject to restrictions set forth in
+DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
+
+***************************************************************************/
+
+/*
+
+The vCard/vCalendar C interface is implemented in the set
+of files as follows:
+
+vcc.y, yacc source, and vcc.c, the yacc output you will use
+implements the core parser
+
+vobject.c implements an API that insulates the caller from
+the parser and changes in the vCard/vCalendar BNF
+
+port.h defines compilation environment dependent stuff
+
+vcc.h and vobject.h are header files for their .c counterparts
+
+vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions
+which you may find useful.
+
+test.c is a standalone test driver that exercises some of
+the features of the APIs provided. Invoke test.exe on a
+VCARD/VCALENDAR input text file and you will see the pretty
+print output of the internal representation (this pretty print
+output should give you a good idea of how the internal
+representation looks like -- there is one such output in the
+following too). Also, a file with the .out suffix is generated
+to show that the internal representation can be written back
+in the original text format.
+
+For more information on this API see the readme.txt file
+which accompanied this distribution.
+
+ Also visit:
+
+ http://www.versit.com
+ http://www.ralden.com
+
+*/
+
+
+#ifndef __VOBJECT_H__
+#define __VOBJECT_H__ 1
+
+#include <qstring.h>
+
+#define vCardClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCard"
+#define vCalendarClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCalendar"
+
+/* The above strings vCardClipboardFormat and vCalendarClipboardFormat
+are globally unique IDs which can be used to generate clipboard format
+ID's as per the requirements of a specific platform. For example, in
+Windows they are used as the parameter in a call to RegisterClipboardFormat.
+For example:
+
+ CLIPFORMAT foo = RegisterClipboardFormat(vCardClipboardFormat);
+
+*/
+
+#define vCardMimeType "text/x-vCard"
+#define vCalendarMimeType "text/x-vCalendar"
+
+#undef DLLEXPORT
+#include <qglobal.h>
+#if defined(Q_WS_WIN)
+#define DLLEXPORT(t) __declspec(dllexport) t
+#else
+#define DLLEXPORT(t) t
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+#define VC7bitProp "7BIT"
+#define VC8bitProp "8BIT"
+#define VCAAlarmProp "AALARM"
+#define VCAdditionalNamesProp "ADDN"
+#define VCAdrProp "ADR"
+#define VCAgentProp "AGENT"
+#define VCAIFFProp "AIFF"
+#define VCAOLProp "AOL"
+#define VCAppleLinkProp "APPLELINK"
+#define VCAttachProp "ATTACH"
+#define VCAttendeeProp "ATTENDEE"
+#define VCATTMailProp "ATTMAIL"
+#define VCAudioContentProp "AUDIOCONTENT"
+#define VCAVIProp "AVI"
+#define VCBase64Prop "BASE64"
+#define VCBBSProp "BBS"
+#define VCBirthDateProp "BDAY"
+#define VCBMPProp "BMP"
+#define VCBodyProp "BODY"
+#define VCBusinessRoleProp "ROLE"
+#define VCCalProp "VCALENDAR"
+#define VCCaptionProp "CAP"
+#define VCCardProp "VCARD"
+#define VCCarProp "CAR"
+#define VCCategoriesProp "CATEGORIES"
+#define VCCellularProp "CELL"
+#define VCCGMProp "CGM"
+#define VCCharSetProp "CS"
+#define VCCIDProp "CID"
+#define VCCISProp "CIS"
+#define VCCityProp "L"
+#define VCClassProp "CLASS"
+#define VCCommentProp "NOTE"
+#define VCCompletedProp "COMPLETED"
+#define VCContentIDProp "CONTENT-ID"
+#define VCCountryNameProp "C"
+#define VCDAlarmProp "DALARM"
+#define VCDataSizeProp "DATASIZE"
+#define VCDayLightProp "DAYLIGHT"
+#define VCDCreatedProp "DCREATED"
+#define VCDeliveryLabelProp "LABEL"
+#define VCDescriptionProp "DESCRIPTION"
+#define VCDIBProp "DIB"
+#define VCDisplayStringProp "DISPLAYSTRING"
+#define VCDomesticProp "DOM"
+#define VCDTendProp "DTEND"
+#define VCDTstartProp "DTSTART"
+#define VCDueProp "DUE"
+#define VCEmailAddressProp "EMAIL"
+#define VCEncodingProp "ENCODING"
+#define VCEndProp "END"
+#define VCEventProp "VEVENT"
+#define VCEWorldProp "EWORLD"
+#define VCExNumProp "EXNUM"
+#define VCExpDateProp "EXDATE"
+#define VCExpectProp "EXPECT"
+#define VCExtAddressProp "EXT ADD"
+#define VCFamilyNameProp "F"
+#define VCFaxProp "FAX"
+#define VCFullNameProp "FN"
+#define VCGeoProp "GEO"
+#define VCGeoLocationProp "GEO"
+#define VCGIFProp "GIF"
+#define VCGivenNameProp "G"
+#define VCGroupingProp "Grouping"
+#define VCHomeProp "HOME"
+#define VCIBMMailProp "IBMMail"
+#define VCInlineProp "INLINE"
+#define VCInternationalProp "INTL"
+#define VCInternetProp "INTERNET"
+#define VCISDNProp "ISDN"
+#define VCJPEGProp "JPEG"
+#define VCLanguageProp "LANG"
+#define VCLastModifiedProp "LAST-MODIFIED"
+#define VCLastRevisedProp "REV"
+#define VCLocationProp "LOCATION"
+#define VCLogoProp "LOGO"
+#define VCMailerProp "MAILER"
+#define VCMAlarmProp "MALARM"
+#define VCMCIMailProp "MCIMAIL"
+#define VCMessageProp "MSG"
+#define VCMETProp "MET"
+#define VCModemProp "MODEM"
+#define VCMPEG2Prop "MPEG2"
+#define VCMPEGProp "MPEG"
+#define VCMSNProp "MSN"
+#define VCNamePrefixesProp "NPRE"
+#define VCNameProp "N"
+#define VCNameSuffixesProp "NSUF"
+#define VCNoteProp "NOTE"
+#define VCOrgNameProp "ORGNAME"
+#define VCOrgProp "ORG"
+#define VCOrgUnit2Prop "OUN2"
+#define VCOrgUnit3Prop "OUN3"
+#define VCOrgUnit4Prop "OUN4"
+#define VCOrgUnitProp "OUN"
+#define VCPagerProp "PAGER"
+#define VCPAlarmProp "PALARM"
+#define VCParcelProp "PARCEL"
+#define VCPartProp "PART"
+#define VCPCMProp "PCM"
+#define VCPDFProp "PDF"
+#define VCPGPProp "PGP"
+#define VCPhotoProp "PHOTO"
+#define VCPICTProp "PICT"
+#define VCPMBProp "PMB"
+#define VCPostalBoxProp "BOX"
+#define VCPostalCodeProp "PC"
+#define VCPostalProp "POSTAL"
+#define VCPowerShareProp "POWERSHARE"
+#define VCPreferredProp "PREF"
+#define VCPriorityProp "PRIORITY"
+#define VCProcedureNameProp "PROCEDURENAME"
+#define VCProdIdProp "PRODID"
+#define VCProdigyProp "PRODIGY"
+#define VCPronunciationProp "SOUND"
+#define VCPSProp "PS"
+#define VCPublicKeyProp "KEY"
+#define VCQPProp "QP"
+#define VCQuickTimeProp "QTIME"
+#define VCQuotedPrintableProp "QUOTED-PRINTABLE"
+#define VCRDateProp "RDATE"
+#define VCRegionProp "R"
+#define VCRelatedToProp "RELATED-TO"
+#define VCRepeatCountProp "REPEATCOUNT"
+#define VCResourcesProp "RESOURCES"
+#define VCRNumProp "RNUM"
+#define VCRoleProp "ROLE"
+#define VCRRuleProp "RRULE"
+#define VCRSVPProp "RSVP"
+#define VCRunTimeProp "RUNTIME"
+#define VCSequenceProp "SEQUENCE"
+#define VCSnoozeTimeProp "SNOOZETIME"
+#define VCStartProp "START"
+#define VCStatusProp "STATUS"
+#define VCStreetAddressProp "STREET"
+#define VCSubTypeProp "SUBTYPE"
+#define VCSummaryProp "SUMMARY"
+#define VCTelephoneProp "TEL"
+#define VCTIFFProp "TIFF"
+#define VCTimeZoneProp "TZ"
+#define VCTitleProp "TITLE"
+#define VCTLXProp "TLX"
+#define VCTodoProp "VTODO"
+#define VCTranspProp "TRANSP"
+#define VCUniqueStringProp "UID"
+#define VCURLProp "URL"
+#define VCURLValueProp "URLVAL"
+#define VCValueProp "VALUE"
+#define VCVersionProp "VERSION"
+#define VCVideoProp "VIDEO"
+#define VCVoiceProp "VOICE"
+#define VCWAVEProp "WAVE"
+#define VCWMFProp "WMF"
+#define VCWorkProp "WORK"
+#define VCX400Prop "X400"
+#define VCX509Prop "X509"
+#define VCXRuleProp "XRULE"
+
+
+typedef struct VObject VObject;
+
+typedef struct VObjectIterator {
+ VObject* start;
+ VObject* next;
+ } VObjectIterator;
+
+extern DLLEXPORT(VObject*) newVObject(const char *id);
+extern DLLEXPORT(void) deleteVObject(VObject *p);
+extern DLLEXPORT(char*) dupStr(const char *s, unsigned int size);
+extern DLLEXPORT(void) deleteStr(const char *p);
+extern DLLEXPORT(void) unUseStr(const char *s);
+
+extern DLLEXPORT(void) setVObjectName(VObject *o, const char* id);
+extern DLLEXPORT(void) setVObjectStringZValue(VObject *o, const char *s);
+extern DLLEXPORT(void) setVObjectStringZValue_(VObject *o, const char *s);
+extern DLLEXPORT(void) setVObjectIntegerValue(VObject *o, unsigned int i);
+extern DLLEXPORT(void) setVObjectLongValue(VObject *o, unsigned long l);
+extern DLLEXPORT(void) setVObjectAnyValue(VObject *o, void *t);
+extern DLLEXPORT(VObject*) setValueWithSize(VObject *prop, void *val, unsigned int size);
+extern DLLEXPORT(VObject*) setValueWithSize_(VObject *prop, void *val, unsigned int size);
+
+extern DLLEXPORT(const char*) vObjectName(VObject *o);
+extern DLLEXPORT(const char*) vObjectStringZValue(VObject *o);
+extern DLLEXPORT(unsigned int) vObjectIntegerValue(VObject *o);
+extern DLLEXPORT(unsigned long) vObjectLongValue(VObject *o);
+extern DLLEXPORT(void*) vObjectAnyValue(VObject *o);
+extern DLLEXPORT(VObject*) vObjectVObjectValue(VObject *o);
+extern DLLEXPORT(void) setVObjectVObjectValue(VObject *o, VObject *p);
+
+extern DLLEXPORT(VObject*) addVObjectProp(VObject *o, VObject *p);
+extern DLLEXPORT(VObject*) addProp(VObject *o, const char *id);
+extern DLLEXPORT(VObject*) addProp_(VObject *o, const char *id);
+extern DLLEXPORT(VObject*) addPropValue(VObject *o, const char *p, const char *v);
+extern DLLEXPORT(VObject*) addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size);
+extern DLLEXPORT(VObject*) addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size);
+extern DLLEXPORT(VObject*) addGroup(VObject *o, const char *g);
+extern DLLEXPORT(void) addList(VObject **o, VObject *p);
+
+extern DLLEXPORT(VObject*) isAPropertyOf(VObject *o, const char *id);
+
+extern DLLEXPORT(VObject*) nextVObjectInList(VObject *o);
+extern DLLEXPORT(void) initPropIterator(VObjectIterator *i, VObject *o);
+extern DLLEXPORT(int) moreIteration(VObjectIterator *i);
+extern DLLEXPORT(VObject*) nextVObject(VObjectIterator *i);
+
+extern DLLEXPORT(const char*) lookupStr(const char *s);
+extern DLLEXPORT(void) cleanStrTbl();
+
+extern DLLEXPORT(void) cleanVObject(VObject *o);
+extern DLLEXPORT(void) cleanVObjects(VObject *list);
+
+extern DLLEXPORT(const char*) lookupProp(const char* str);
+extern DLLEXPORT(const char*) lookupProp_(const char* str);
+
+extern DLLEXPORT(void) writeVObjectToFile(char *fname, VObject *o);
+extern DLLEXPORT(void) writeVObjectsToFile(char *fname, VObject *list);
+
+extern DLLEXPORT(int) vObjectValueType(VObject *o);
+
+/* return type of vObjectValueType: */
+#define VCVT_NOVALUE 0
+ /* if the VObject has no value associated with it. */
+#define VCVT_STRINGZ 1
+ /* if the VObject has value set by setVObjectStringZValue. */
+#define VCVT_UINT 2
+ /* if the VObject has value set by setVObjectIntegerValue. */
+#define VCVT_ULONG 3
+ /* if the VObject has value set by setVObjectLongValue. */
+#define VCVT_RAW 4
+ /* if the VObject has value set by setVObjectAnyValue. */
+#define VCVT_VOBJECT 5
+ /* if the VObject has value set by setVObjectVObjectValue. */
+
+extern const char** fieldedProp;
+
+/***************************************************
+ * The methods below are implemented in vcc.c (generated from vcc.y )
+ ***************************************************/
+
+/* NOTE regarding printVObject and writeVObject
+
+The functions below are not exported from the DLL because they
+take a FILE* as a parameter, which cannot be passed across a DLL
+interface (at least that is my experience). Instead you can use
+their companion functions which take file names or pointers
+to memory. However, if you are linking this code into
+your build directly then you may find them a more convenient API
+and you can go ahead and use them. If you try to use them with
+the DLL LIB you will get a link error.
+*/
+extern void writeVObject(FILE *fp, VObject *o);
+
+
+
+typedef void (*MimeErrorHandler)(char *);
+
+extern DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler);
+
+extern DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len);
+extern DLLEXPORT(VObject*) Parse_MIME_FromFileName(char* fname);
+
+
+/* NOTE regarding Parse_MIME_FromFile
+The function above, Parse_MIME_FromFile, comes in two flavors,
+neither of which is exported from the DLL. Each version takes
+a CFile or FILE* as a parameter, neither of which can be
+passed across a DLL interface (at least that is my experience).
+If you are linking this code into your build directly then
+you may find them a more convenient API that the other flavors
+that take a file name. If you use them with the DLL LIB you
+will get a link error.
+*/
+
+
+#if INCLUDEMFC
+extern VObject* Parse_MIME_FromFile(CFile *file);
+#else
+extern VObject* Parse_MIME_FromFile(FILE *file);
+#endif
+
+#endif /* __VOBJECT_H__ */
+
+
|