libkcal Library API Documentation

incidenceformatter.cpp

00001 /*
00002     This file is part of libkcal.
00003     Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
00004     Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019     Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include "incidenceformatter.h"
00023 
00024 #include <libkcal/attachment.h>
00025 #include <libkcal/incidence.h>
00026 #include <libkcal/event.h>
00027 #include <libkcal/todo.h>
00028 #include <libkcal/journal.h>
00029 #include <libkcal/calendar.h>
00030 #include <libkcal/calendarlocal.h>
00031 #include <libkcal/icalformat.h>
00032 #include <libkcal/freebusy.h>
00033 #include <libkcal/recurrence.h>
00034 
00035 #include <libkdepim/email.h>
00036 
00037 #include <ktnef/ktnefparser.h>
00038 #include <ktnef/ktnefmessage.h>
00039 #include <ktnef/ktnefdefs.h>
00040 #include <kabc/phonenumber.h>
00041 #include <kabc/vcardconverter.h>
00042 #include <kabc/stdaddressbook.h>
00043 
00044 #include <kapplication.h>
00045 // #include <kdebug.h>
00046 
00047 #include <klocale.h>
00048 #include <kiconloader.h>
00049 
00050 #include <qbuffer.h>
00051 
00052 #include <time.h>
00053 
00054 
00055 using namespace KCal;
00056 
00057 static const struct {
00058    const char* day;
00059    const char* dayPlain;
00060 } daysOfWeek[] = {
00061         { I18N_NOOP("Mondays"), I18N_NOOP("Monday") },
00062         { I18N_NOOP("Tuesdays"), I18N_NOOP("Tuesday") },
00063         { I18N_NOOP("Wednesdays"), I18N_NOOP("Wednesday") },
00064         { I18N_NOOP("Thursdays"), I18N_NOOP("Thursday") },
00065         { I18N_NOOP("Fridays"), I18N_NOOP("Friday") },
00066         { I18N_NOOP("Saturdays"), I18N_NOOP("Saturday") },
00067         { I18N_NOOP("Sundays"), I18N_NOOP("Sunday") },
00068 };
00069 
00070 const int sizeOfDaysOfWeek = sizeof(daysOfWeek) / sizeof(*daysOfWeek);
00071 
00072 static const struct {
00073    const int dayNo;
00074    const char *date;
00075 } daysOfMonth[] = {
00076        { 1, I18N_NOOP("1st") },
00077        { 2, I18N_NOOP("2nd") },
00078        { 3, I18N_NOOP("3rd") },
00079        { 4, I18N_NOOP("4th") },
00080        { 5, I18N_NOOP("5th") },
00081        { 6, I18N_NOOP("6th") },
00082        { 7, I18N_NOOP("7th") },
00083        { 8, I18N_NOOP("8th") },
00084        { 9, I18N_NOOP("9th") },
00085        { 10, I18N_NOOP("10th") },
00086        { 11, I18N_NOOP("11th") },
00087        { 12, I18N_NOOP("12th") },
00088        { 13, I18N_NOOP("13th") },
00089        { 14, I18N_NOOP("14th") },
00090        { 15, I18N_NOOP("15th") },
00091        { 16, I18N_NOOP("16th") },
00092        { 17, I18N_NOOP("17th") },
00093        { 18, I18N_NOOP("18th") },
00094        { 19, I18N_NOOP("19th") },
00095        { 20, I18N_NOOP("20th") },
00096        { 21, I18N_NOOP("21st") },
00097        { 22, I18N_NOOP("22nd") },
00098        { 23, I18N_NOOP("23rd") },
00099        { 24, I18N_NOOP("24th") },
00100        { 25, I18N_NOOP("25th") },
00101        { 26, I18N_NOOP("26th") },
00102        { 27, I18N_NOOP("27th") },
00103        { 28, I18N_NOOP("28th") },
00104        { 29, I18N_NOOP("29th") },
00105        { 30, I18N_NOOP("30th") },
00106        { 31, I18N_NOOP("31st") },
00107        { -1, I18N_NOOP("last day") },
00108        { -2, I18N_NOOP("2nd last day") },
00109        { -3, I18N_NOOP("3rd last day") },
00110        { -4, I18N_NOOP("4th last day") },
00111        { -5, I18N_NOOP("5th last day") },
00112 };
00113 
00114 const int sizeOfDaysOfMonth = sizeof (daysOfMonth) / sizeof (*daysOfMonth);
00115 
00116 static const struct {
00117    const char* month;
00118 } monthsOfYear[] = {
00119         { I18N_NOOP("January") },
00120         { I18N_NOOP("February") },
00121         { I18N_NOOP("March") },
00122         { I18N_NOOP("April") },
00123         { I18N_NOOP("May") },
00124         { I18N_NOOP("June") },
00125         { I18N_NOOP("July") },
00126         { I18N_NOOP("August") },
00127         { I18N_NOOP("September") },
00128         { I18N_NOOP("October") },
00129         { I18N_NOOP("November") },
00130         { I18N_NOOP("December") }
00131 };
00132 
00133 const int sizeOfMonthsofYear = sizeof(monthsOfYear) / sizeof(*monthsOfYear);
00134 
00135 
00136 static QString stringProp( KTNEFMessage* tnefMsg, const Q_UINT32& key,
00137                            const QString& fallback = QString::null)
00138 {
00139   return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
00140                             fallback );
00141 }
00142 
00143 static QString sNamedProp( KTNEFMessage* tnefMsg, const QString& name,
00144                            const QString& fallback = QString::null )
00145 {
00146   return tnefMsg->findNamedProp( name, fallback );
00147 }
00148 
00149 struct save_tz { char* old_tz; char* tz_env_str; };
00150 
00151 /* temporarily go to a different timezone */
00152 static struct save_tz set_tz( const char* _tc )
00153 {
00154   const char *tc = _tc?_tc:"UTC";
00155 
00156   struct save_tz rv;
00157 
00158   rv.old_tz = 0;
00159   rv.tz_env_str = 0;
00160 
00161   //kdDebug(5006) << "set_tz(), timezone before = " << timezone << endl;
00162 
00163   char* tz_env = 0;
00164   if( getenv( "TZ" ) ) {
00165     tz_env = strdup( getenv( "TZ" ) );
00166     rv.old_tz = tz_env;
00167   }
00168   char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
00169   strcpy( tmp_env, "TZ=" );
00170   strcpy( tmp_env+3, tc );
00171   putenv( tmp_env );
00172 
00173   rv.tz_env_str = tmp_env;
00174 
00175   /* tmp_env is not free'ed -- it is part of the environment */
00176 
00177   tzset();
00178   //kdDebug(5006) << "set_tz(), timezone after = " << timezone << endl;
00179 
00180   return rv;
00181 }
00182 
00183 /* restore previous timezone */
00184 static void unset_tz( struct save_tz old_tz )
00185 {
00186   if( old_tz.old_tz ) {
00187     char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
00188     strcpy( tmp_env, "TZ=" );
00189     strcpy( tmp_env+3, old_tz.old_tz );
00190     putenv( tmp_env );
00191     /* tmp_env is not free'ed -- it is part of the environment */
00192     free( old_tz.old_tz );
00193   } else {
00194     /* clear TZ from env */
00195     putenv( strdup("TZ") );
00196   }
00197   tzset();
00198 
00199   /* is this OK? */
00200   if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
00201 }
00202 
00203 static QDateTime utc2Local( const QDateTime& utcdt )
00204 {
00205   struct tm tmL;
00206 
00207   save_tz tmp_tz = set_tz("UTC");
00208   time_t utc = utcdt.toTime_t();
00209   unset_tz( tmp_tz );
00210 
00211   localtime_r( &utc, &tmL );
00212   return QDateTime( QDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
00213                     QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
00214 }
00215 
00216 
00217 static QDateTime pureISOToLocalQDateTime( const QString& dtStr,
00218                                           bool bDateOnly = false )
00219 {
00220   QDate tmpDate;
00221   QTime tmpTime;
00222   int year, month, day, hour, minute, second;
00223 
00224   if( bDateOnly ) {
00225     year = dtStr.left( 4 ).toInt();
00226     month = dtStr.mid( 4, 2 ).toInt();
00227     day = dtStr.mid( 6, 2 ).toInt();
00228     hour = 0;
00229     minute = 0;
00230     second = 0;
00231   } else {
00232     year = dtStr.left( 4 ).toInt();
00233     month = dtStr.mid( 4, 2 ).toInt();
00234     day = dtStr.mid( 6, 2 ).toInt();
00235     hour = dtStr.mid( 9, 2 ).toInt();
00236     minute = dtStr.mid( 11, 2 ).toInt();
00237     second = dtStr.mid( 13, 2 ).toInt();
00238   }
00239   tmpDate.setYMD( year, month, day );
00240   tmpTime.setHMS( hour, minute, second );
00241 
00242   if( tmpDate.isValid() && tmpTime.isValid() ) {
00243     QDateTime dT = QDateTime( tmpDate, tmpTime );
00244 
00245     if( !bDateOnly ) {
00246       // correct for GMT ( == Zulu time == UTC )
00247       if (dtStr.at(dtStr.length()-1) == 'Z') {
00248         //dT = dT.addSecs( 60 * KRFCDate::localUTCOffset() );
00249         //localUTCOffset( dT ) );
00250         dT = utc2Local( dT );
00251       }
00252     }
00253     return dT;
00254   } else
00255     return QDateTime();
00256 }
00257 
00258 
00259 
00260 QString IncidenceFormatter::msTNEFToVPart( const QByteArray& tnef )
00261 {
00262   bool bOk = false;
00263 
00264   KTNEFParser parser;
00265   QBuffer buf( tnef );
00266   CalendarLocal cal;
00267   KABC::Addressee addressee;
00268   KABC::VCardConverter cardConv;
00269   ICalFormat calFormat;
00270   Event* event = new Event();
00271 
00272   if( parser.openDevice( &buf ) ) {
00273     KTNEFMessage* tnefMsg = parser.message();
00274     //QMap<int,KTNEFProperty*> props = parser.message()->properties();
00275 
00276     // Everything depends from property PR_MESSAGE_CLASS
00277     // (this is added by KTNEFParser):
00278     QString msgClass = tnefMsg->findProp( 0x001A, QString::null, true )
00279       .upper();
00280     if( !msgClass.isEmpty() ) {
00281       // Match the old class names that might be used by Outlook for
00282       // compatibility with Microsoft Mail for Windows for Workgroups 3.1.
00283       bool bCompatClassAppointment = false;
00284       bool bCompatMethodRequest = false;
00285       bool bCompatMethodCancled = false;
00286       bool bCompatMethodAccepted = false;
00287       bool bCompatMethodAcceptedCond = false;
00288       bool bCompatMethodDeclined = false;
00289       if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
00290         bCompatClassAppointment = true;
00291         if( msgClass.endsWith( ".MTGREQ" ) )
00292           bCompatMethodRequest = true;
00293         if( msgClass.endsWith( ".MTGCNCL" ) )
00294           bCompatMethodCancled = true;
00295         if( msgClass.endsWith( ".MTGRESPP" ) )
00296           bCompatMethodAccepted = true;
00297         if( msgClass.endsWith( ".MTGRESPA" ) )
00298           bCompatMethodAcceptedCond = true;
00299         if( msgClass.endsWith( ".MTGRESPN" ) )
00300           bCompatMethodDeclined = true;
00301       }
00302       bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
00303 
00304       if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
00305         // Compose a vCal
00306         bool bIsReply = false;
00307         QString prodID = "-//Microsoft Corporation//Outlook ";
00308         prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
00309         prodID += "MIMEDIR/EN\n";
00310         prodID += "VERSION:2.0\n";
00311         calFormat.setApplication( "Outlook", prodID );
00312 
00313         Scheduler::Method method;
00314         if( bCompatMethodRequest )
00315           method = Scheduler::Request;
00316         else if( bCompatMethodCancled )
00317           method = Scheduler::Cancel;
00318         else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
00319                  bCompatMethodDeclined ) {
00320           method = Scheduler::Reply;
00321           bIsReply = true;
00322         } else {
00323           // pending(khz): verify whether "0x0c17" is the right tag ???
00324           //
00325           // at the moment we think there are REQUESTS and UPDATES
00326           //
00327           // but WHAT ABOUT REPLIES ???
00328           //
00329           //
00330 
00331           if( tnefMsg->findProp(0x0c17) == "1" )
00332             bIsReply = true;
00333           method = Scheduler::Request;
00334         }
00335 
00337         ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
00338 
00339         QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
00340 
00341         if( !sSenderSearchKeyEmail.isEmpty() ) {
00342           int colon = sSenderSearchKeyEmail.find( ':' );
00343           // May be e.g. "SMTP:KHZ@KDE.ORG"
00344           if( sSenderSearchKeyEmail.find( ':' ) == -1 )
00345             sSenderSearchKeyEmail.remove( 0, colon+1 );
00346         }
00347 
00348         QString s( tnefMsg->findProp( 0x0e04 ) );
00349         QStringList attendees = QStringList::split( ';', s );
00350         if( attendees.count() ) {
00351           for( QStringList::Iterator it = attendees.begin();
00352                it != attendees.end(); ++it ) {
00353             // Skip all entries that have no '@' since these are
00354             // no mail addresses
00355             if( (*it).find('@') == -1 ) {
00356               s = (*it).stripWhiteSpace();
00357 
00358               Attendee *attendee = new Attendee( s, s, true );
00359               if( bIsReply ) {
00360                 if( bCompatMethodAccepted )
00361                   attendee->setStatus( Attendee::Accepted );
00362                 if( bCompatMethodDeclined )
00363                   attendee->setStatus( Attendee::Declined );
00364                 if( bCompatMethodAcceptedCond )
00365                   attendee->setStatus(Attendee::Tentative);
00366               } else {
00367                 attendee->setStatus( Attendee::NeedsAction );
00368                 attendee->setRole( Attendee::ReqParticipant );
00369               }
00370               event->addAttendee(attendee);
00371             }
00372           }
00373         } else {
00374           // Oops, no attendees?
00375           // This must be old style, let us use the PR_SENDER_SEARCH_KEY.
00376           s = sSenderSearchKeyEmail;
00377           if( !s.isEmpty() ) {
00378             Attendee *attendee = new Attendee( QString::null, QString::null,
00379                                                true );
00380             if( bIsReply ) {
00381               if( bCompatMethodAccepted )
00382                 attendee->setStatus( Attendee::Accepted );
00383               if( bCompatMethodAcceptedCond )
00384                 attendee->setStatus( Attendee::Declined );
00385               if( bCompatMethodDeclined )
00386                 attendee->setStatus( Attendee::Tentative );
00387             } else {
00388               attendee->setStatus(Attendee::NeedsAction);
00389               attendee->setRole(Attendee::ReqParticipant);
00390             }
00391             event->addAttendee(attendee);
00392           }
00393         }
00394         s = tnefMsg->findProp( 0x0c1f ); // look for organizer property
00395         if( s.isEmpty() && !bIsReply )
00396           s = sSenderSearchKeyEmail;
00397         // TODO: Use the common name?
00398         if( !s.isEmpty() )
00399           event->setOrganizer( s );
00400 
00401         s = tnefMsg->findProp( 0x8516 ).replace( QChar( '-' ), QString::null )
00402           .replace( QChar( ':' ), QString::null );
00403         event->setDtStart( QDateTime::fromString( s ) ); // ## Format??
00404 
00405         s = tnefMsg->findProp( 0x8517 ).replace( QChar( '-' ), QString::null )
00406           .replace( QChar( ':' ), QString::null );
00407         event->setDtEnd( QDateTime::fromString( s ) );
00408 
00409         s = tnefMsg->findProp( 0x8208 );
00410         event->setLocation( s );
00411 
00412         // is it OK to set this to OPAQUE always ??
00413         //vPart += "TRANSP:OPAQUE\n"; ###FIXME, portme!
00414         //vPart += "SEQUENCE:0\n";
00415 
00416         // is "0x0023" OK  -  or should we look for "0x0003" ??
00417         s = tnefMsg->findProp( 0x0023 );
00418         event->setUid( s );
00419 
00420         // PENDING(khz): is this value in local timezone? Must it be
00421         // adjusted? Most likely this is a bug in the server or in
00422         // Outlook - we ignore it for now.
00423         s = tnefMsg->findProp( 0x8202 ).replace( QChar( '-' ), QString::null )
00424           .replace( QChar( ':' ), QString::null );
00425         // ### libkcal always uses currentDateTime()
00426         // event->setDtStamp(QDateTime::fromString(s));
00427 
00428         s = tnefMsg->findNamedProp( "Keywords" );
00429         event->setCategories( s );
00430 
00431         s = tnefMsg->findProp( 0x1000 );
00432         event->setDescription( s );
00433 
00434         s = tnefMsg->findProp( 0x0070 );
00435         event->setSummary( s );
00436 
00437         s = tnefMsg->findProp( 0x0026 );
00438         event->setPriority( s.toInt() );
00439 
00440         // is reminder flag set ?
00441         if(!tnefMsg->findProp(0x8503).isEmpty()) {
00442           Alarm *alarm = new Alarm(event);
00443           QDateTime highNoonTime =
00444             pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 )
00445                                      .replace( QChar( '-' ), "" )
00446                                      .replace( QChar( ':' ), "" ) );
00447           QDateTime wakeMeUpTime =
00448             pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" )
00449                                      .replace( QChar( '-' ), "" )
00450                                      .replace( QChar( ':' ), "" ) );
00451           alarm->setTime(wakeMeUpTime);
00452 
00453           if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
00454             alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
00455           else
00456             // default: wake them up 15 minutes before the appointment
00457             alarm->setStartOffset( Duration( 15*60 ) );
00458           alarm->setDisplayAlarm( i18n( "Reminder" ) );
00459 
00460           // Sorry: the different action types are not known (yet)
00461           //        so we always set 'DISPLAY' (no sounds, no images...)
00462           event->addAlarm( alarm );
00463         }
00464         cal.addEvent( event );
00465         bOk = true;
00466         // we finished composing a vCal
00467       } else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
00468         addressee.setUid( stringProp( tnefMsg, attMSGID ) );
00469         addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
00470         addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
00471         addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
00472         addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
00473         addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
00474         addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
00475         addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
00476         addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
00477         addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
00478         addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
00479         addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
00480 
00481         QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
00482           .replace( QChar( '-' ), QString::null )
00483           .replace( QChar( ':' ), QString::null );
00484         if( !s.isEmpty() )
00485           addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
00486 
00487         addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE )  ) );
00488 
00489         // collect parts of Name entry
00490         addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
00491         addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
00492         addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
00493         addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
00494         addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
00495 
00496         addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
00497         addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
00498         addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
00499         /*
00500         the MAPI property ID of this (multiline) )field is unknown:
00501         vPart += stringProp(tnefMsg, "\n","NOTE", ... , "" );
00502         */
00503 
00504         KABC::Address adr;
00505         adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
00506         adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
00507         adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
00508         adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
00509         adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
00510         adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
00511         adr.setType(KABC::Address::Home);
00512         addressee.insertAddress(adr);
00513 
00514         adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
00515         adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
00516         adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
00517         adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
00518         adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
00519         adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
00520         adr.setType( KABC::Address::Work );
00521         addressee.insertAddress( adr );
00522 
00523         adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
00524         adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
00525         adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
00526         adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
00527         adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
00528         adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
00529         adr.setType( KABC::Address::Dom );
00530         addressee.insertAddress(adr);
00531 
00532         // problem: the 'other' address was stored by KOrganizer in
00533         //          a line looking like the following one:
00534         // vPart += "\nADR;TYPE=dom;TYPE=intl;TYPE=parcel;TYPE=postal;TYPE=work;TYPE=home:other_pobox;;other_str1\nother_str2;other_loc;other_region;other_pocode;other_country
00535 
00536         QString nr;
00537         nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
00538         addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
00539         nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
00540         addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
00541         nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
00542         addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
00543         nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
00544         addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
00545         nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
00546         addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
00547 
00548         s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
00549           .replace( QChar( '-' ), QString::null )
00550           .replace( QChar( ':' ), QString::null );
00551         if( !s.isEmpty() )
00552           addressee.setBirthday( QDateTime::fromString( s ) );
00553 
00554         bOk = ( !addressee.isEmpty() );
00555       } else if( "IPM.NOTE" == msgClass ) {
00556 
00557       } // else if ... and so on ...
00558     }
00559   }
00560 
00561   // Compose return string
00562   QString iCal = calFormat.toString( &cal );
00563   if( !iCal.isEmpty() )
00564     // This was an iCal
00565     return iCal;
00566 
00567   // Not an iCal - try a vCard
00568   KABC::VCardConverter converter;
00569   return converter.createVCard( addressee );
00570 }
00571 
00572 static QString weeklyRecurrenceAsString( Recurrence * recur )
00573 {
00574   Q_ASSERT( recur->doesRecur() == Recurrence::rWeekly );
00575 
00576   //For Weekly, setting up the weekdays of recurrence with 
00577   //comma as a separator and "and" separating last two
00578   //days 
00579   QStringList dayList;
00580   for ( int i = 0; i < sizeOfDaysOfWeek; i++ ) {
00581     if( recur->days().testBit(i) ) {
00582       dayList+= i18n( daysOfWeek[i].day );
00583     } 
00584   }
00585 
00586   QString strDays;
00587   if( dayList.count() > 1 ) {
00588     strDays = dayList.join(", ");
00589     strDays.replace( strDays.findRev(','), 1, i18n(" and") );
00590   } else if( dayList.count() == 1 ) {
00591     strDays = dayList.first();
00592   }
00593   return strDays;
00594 }
00595 
00596 static QString monthlyPosRecurrenceAsString( Recurrence * recur )
00597 {
00598    Q_ASSERT( recur->doesRecur() == Recurrence::rMonthlyPos );
00599 
00600   QString strDays;
00601 
00602   Recurrence::rMonthPos *tmpDay;
00603       /*struct rMonthlyPos {
00604          QBitArray rDays;
00605          short rPos;
00606          bool negative;
00607        } 
00608      */
00609 
00610   //Recurrence::rMonthPos tmpDay;
00611   QPtrList<Recurrence::rMonthPos> tmpDays = recur->monthPositions();
00612   for ( tmpDay = tmpDays.first();
00613         tmpDay;
00614         tmpDay = tmpDays.next() ) {
00615 
00616       QString day;
00617       for ( int i = 0; i < sizeOfDaysOfWeek; i++ ) {
00618       if( tmpDay->rDays.testBit(i) ) {
00619          day = i18n( daysOfWeek[i].dayPlain );
00620          break;
00621       }
00622     }
00623     strDays += i18n( "%1 %2").arg( i18n( daysOfMonth[ tmpDay->rPos - 1 ].date ) ).arg( day );
00624   }
00625 
00626   return strDays;
00627 }
00628 
00629 static QString monthlyDayRecurrenceAsString( Recurrence * recur )
00630 {
00631   Q_ASSERT( recur->doesRecur() == Recurrence::rMonthlyDay );
00632 
00633   QString strDays;
00634 
00635   int *tmpDay;
00636   QPtrList<int> tmpDays = recur->monthDays();
00637   for ( tmpDay = tmpDays.first();
00638         tmpDay;
00639         tmpDay = tmpDays.next() ) {
00640      strDays += i18n( daysOfMonth[ *tmpDay - 1 ].date ) + " ";
00641   }
00642 
00643   return strDays;
00644 }
00645 
00646 //QPtrList<int> &yearNums()
00647 //QPtrList<rMonthPos> &yearMonthPositions()
00648 
00649 //rYearlyMonth = 0x0007, 
00650 static QString yearlyMonthRecurrenceAsString( Recurrence * recur )
00651 {
00652    Q_ASSERT( recur->doesRecur() == Recurrence::rYearlyMonth );
00653 
00654    QString strDays;
00655    QPtrList<int> days = recur->monthDays();
00656    int *day = days.first();
00657    int *tmpMonth;
00658    QPtrList<int> tmpMonths = recur->yearNums();
00659    for ( tmpMonth = tmpMonths.first();
00660          tmpMonth;
00661          tmpMonth = tmpMonths.next()) {
00662         strDays = i18n( "%1 day of %2" ).arg( i18n( daysOfMonth[ *day  - 1 ].date ) )
00663                    .arg( i18n( monthsOfYear[ *tmpMonth - 1 ].month ) );
00664    }
00665    return strDays;
00666 }
00667 
00668 //rYearlyDay = 0x0008, 
00669 //TODO Ordinal Numbers : 1st to 365th day of the year
00670 static QString yearlyDayRecurrenceAsString( Recurrence * recur )
00671 {
00672    Q_ASSERT( recur->doesRecur() == Recurrence::rYearlyDay );
00673 
00674    int *tmpDay;
00675    QString strDays;
00676    QPtrList<int> tmpDays = recur->yearNums();
00677    tmpDay = tmpDays.first();
00678    strDays += i18n( "%1 ").arg( *tmpDay );
00679 
00680    return strDays;
00681 }
00682 
00683 //rYearlyPos
00684 static QString yearlyPosRecurrenceAsString( Recurrence * recur )
00685 {
00686    Q_ASSERT( recur->doesRecur() == Recurrence::rYearlyPos );
00687 
00688    int *tmpMonth;
00689    QString strDays;
00690    QString day;
00691 
00692    QPtrList<Recurrence::rMonthPos> tmpDays = recur->yearMonthPositions();
00693    Recurrence::rMonthPos *tmpDay = tmpDays.first();
00694    for ( int i = 0; i < sizeOfDaysOfWeek; i++ ) {
00695        if( tmpDay->rDays.testBit(i) ) {
00696           day = i18n( daysOfWeek[i].dayPlain );
00697           break;
00698        }
00699    }
00700 
00701    QPtrList<int> tmpMonths = recur->yearNums();
00702    tmpMonth = tmpMonths.first();
00703    strDays += i18n("%1 %2 of %3 ").arg( i18n( daysOfMonth[ tmpDay->rPos  - 1 ].date ) )
00704                                   .arg( day )
00705                                   .arg( i18n( monthsOfYear[ *tmpMonth - 1 ].month ) );
00706    return strDays;
00707 }
00708 
00709 QString IncidenceFormatter::recurrenceAsHTML( Incidence * incidence )
00710 {
00711   QString result;
00712 
00713   if ( incidence->doesRecur() ) {
00714     Recurrence *recur = incidence->recurrence();
00715     switch (recur->doesRecur())
00716     {
00717         case Recurrence::rDaily:
00718           result += i18n("Recurs every day. ", "Recurs every %n days.",recur->frequency());
00719           break;
00720         case Recurrence::rWeekly:
00721           result += i18n("Recurs every week on %1. ", "Recurs every %n weeks on %1.",recur->frequency())
00722                               .arg( weeklyRecurrenceAsString( recur ) );
00723           break;
00724         case Recurrence::rMonthlyPos:
00725           result += i18n("Recurs on the %1 of every month.", "Recurs on the %1 every %n months.", recur->frequency())
00726                               .arg( monthlyPosRecurrenceAsString( recur ) );
00727           break;
00728         case Recurrence::rMonthlyDay:
00729           result += i18n("Recurs on the %1 of every month.", "Recurs on the %1 every %n months.", recur->frequency())
00730                               .arg( monthlyDayRecurrenceAsString( recur ) );
00731           break;
00732         case Recurrence::rYearlyMonth:
00733           result += i18n("Recurs on the %1 of every year.", "Recurs on %1 every %n years.", recur->frequency())
00734                               .arg( yearlyMonthRecurrenceAsString( recur ) );
00735           break;
00736         case Recurrence::rYearlyDay:
00737           result += i18n("Recurs on day %1 of every year.", "Recurs on %1 day every %n years.", recur->frequency())
00738                               .arg( yearlyDayRecurrenceAsString( recur ) );
00739           break;
00740         case Recurrence::rYearlyPos:
00741           result += i18n("Recurs on the %1 of every year.", "Recurs on %1 every %n years.", recur->frequency())
00742                               .arg( yearlyPosRecurrenceAsString( recur ) );
00743           break;
00744     }
00745 
00746     if ( recur->duration() > 0 ) {
00747       result += i18n (" Repeats once.", " Repeats %n times.", recur->duration());
00748       result += '\n';
00749     } else {
00750       if ( recur->duration() != -1 ) {
00751 // TODO_Recurrence: What to do with floating
00752         QString endstr;
00753         if ( incidence->doesFloat() ) {
00754           endstr = KGlobal::locale()->formatDate( recur->endDate() );
00755         } else {
00756           endstr = KGlobal::locale()->formatDateTime( recur->endDateTime() );
00757         }
00758         result += i18n(" Repeats until: %1.<br>").arg( endstr );
00759       } else {
00760         result += i18n(" Repeats forever.<br>");
00761       }
00762     }
00763     const DateList exdates = incidence->exDates();
00764     if ( !exdates.isEmpty() )
00765       result += i18n("Except: ");
00766     DateList::ConstIterator it( exdates.begin() );
00767     while ( it != exdates.end() ) {
00768         if ( it != exdates.begin() )
00769           result += " ,";
00770         QDate d(*it++);
00771         result += KGlobal::locale()->formatDateTime( d );
00772     }
00773      if ( !exdates.isEmpty() )
00774       result += "<br>";
00775 
00776   }
00777   return result;
00778 }
00779 
00780 
KDE Logo
This file is part of the documentation for libkcal Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Aug 23 18:18:40 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003