summaryrefslogtreecommitdiffabout
path: root/libkcal
authorzautrix <zautrix>2004-06-26 19:01:18 (UTC)
committer zautrix <zautrix>2004-06-26 19:01:18 (UTC)
commitb9aad1f15dc600e4dbe4c62d3fcced6363188ba3 (patch) (unidiff)
tree2c3d4004fb21c72cba65793859f9bcd8ffd3a49c /libkcal
downloadkdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.zip
kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.gz
kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.bz2
Initial revision
Diffstat (limited to 'libkcal') (more/less context) (ignore whitespace changes)
-rw-r--r--libkcal/alarm.cpp407
-rw-r--r--libkcal/alarm.h245
-rw-r--r--libkcal/attachment.cpp86
-rw-r--r--libkcal/attachment.h69
-rw-r--r--libkcal/attendee.cpp167
-rw-r--r--libkcal/attendee.h96
-rw-r--r--libkcal/calendar.cpp426
-rw-r--r--libkcal/calendar.h349
-rw-r--r--libkcal/calendar.moc0
-rw-r--r--libkcal/calendarlocal.cpp655
-rw-r--r--libkcal/calendarlocal.h216
-rw-r--r--libkcal/calendarresources.h17
-rw-r--r--libkcal/calfilter.cpp201
-rw-r--r--libkcal/calfilter.h128
-rw-r--r--libkcal/calformat.cpp98
-rw-r--r--libkcal/calformat.h111
-rw-r--r--libkcal/calstorage.h52
-rw-r--r--libkcal/compat.cpp37
-rw-r--r--libkcal/compat.h53
-rw-r--r--libkcal/customproperties.cpp114
-rw-r--r--libkcal/customproperties.h97
-rw-r--r--libkcal/dndfactory.h62
-rw-r--r--libkcal/dummyscheduler.cpp119
-rw-r--r--libkcal/dummyscheduler.h51
-rw-r--r--libkcal/duration.cpp59
-rw-r--r--libkcal/duration.h48
-rw-r--r--libkcal/event.cpp178
-rw-r--r--libkcal/event.h88
-rw-r--r--libkcal/exceptions.cpp90
-rw-r--r--libkcal/exceptions.h75
-rw-r--r--libkcal/filestorage.cpp140
-rw-r--r--libkcal/filestorage.h58
-rw-r--r--libkcal/freebusy.cpp184
-rw-r--r--libkcal/freebusy.h72
-rw-r--r--libkcal/icaldrag.cpp58
-rw-r--r--libkcal/icaldrag.h46
-rw-r--r--libkcal/icalformat.cpp478
-rw-r--r--libkcal/icalformat.h116
-rw-r--r--libkcal/icalformatimpl.cpp2173
-rw-r--r--libkcal/icalformatimpl.h109
-rw-r--r--libkcal/icalformatimpl.h.bup109
-rw-r--r--libkcal/imipscheduler.cpp58
-rw-r--r--libkcal/imipscheduler.h49
-rw-r--r--libkcal/incidence.cpp594
-rw-r--r--libkcal/incidence.h298
-rw-r--r--libkcal/incidencebase.cpp393
-rw-r--r--libkcal/incidencebase.h170
-rw-r--r--libkcal/journal.cpp49
-rw-r--r--libkcal/journal.h50
-rw-r--r--libkcal/kcal.pro.back84
-rw-r--r--libkcal/libkcal.pro100
-rw-r--r--libkcal/libkcalE.pro88
-rw-r--r--libkcal/listbase.h97
-rw-r--r--libkcal/period.cpp65
-rw-r--r--libkcal/period.h51
-rw-r--r--libkcal/person.cpp77
-rw-r--r--libkcal/person.h50
-rw-r--r--libkcal/qtopiaformat.cpp333
-rw-r--r--libkcal/qtopiaformat.h53
-rw-r--r--libkcal/recurrence.cpp3360
-rw-r--r--libkcal/recurrence.h401
-rw-r--r--libkcal/resourcecalendar.h16
-rw-r--r--libkcal/scheduler.cpp355
-rw-r--r--libkcal/scheduler.h133
-rw-r--r--libkcal/sharpformat.cpp1007
-rw-r--r--libkcal/sharpformat.h61
-rw-r--r--libkcal/todo.cpp316
-rw-r--r--libkcal/todo.h121
-rw-r--r--libkcal/vcaldrag.cpp54
-rw-r--r--libkcal/vcaldrag.h47
-rw-r--r--libkcal/vcalformat.cpp1678
-rw-r--r--libkcal/vcalformat.h108
-rw-r--r--libkcal/versit/port.h75
-rw-r--r--libkcal/versit/vcc.c2162
-rw-r--r--libkcal/versit/vcc.h76
-rw-r--r--libkcal/versit/versit.pro15
-rw-r--r--libkcal/versit/versit.pro.back15
-rw-r--r--libkcal/versit/vobject.c1433
-rw-r--r--libkcal/versit/vobject.h384
79 files changed, 22413 insertions, 0 deletions
diff --git a/libkcal/alarm.cpp b/libkcal/alarm.cpp
new file mode 100644
index 0000000..07812c2
--- a/dev/null
+++ b/libkcal/alarm.cpp
@@ -0,0 +1,407 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#include <kdebug.h>
23
24#include "incidence.h"
25#include "todo.h"
26
27#include "alarm.h"
28
29using namespace KCal;
30#include <qwidget.h>
31Alarm::Alarm(Incidence *parent)
32 : mParent(parent),
33 mType(Audio),
34 mDescription(""), // to make operator==() not fail
35 mFile(""), // to make operator==() not fail
36 mMailSubject(""), // to make operator==() not fail
37 mAlarmSnoozeTime(5),
38 mAlarmRepeatCount(0),
39 mEndOffset(false),
40 mHasTime(false),
41 mAlarmEnabled(false)
42{
43
44}
45
46Alarm::~Alarm()
47{
48}
49
50bool Alarm::operator==( const Alarm& rhs ) const
51{
52 if ( mType != rhs.mType ||
53 mAlarmSnoozeTime != rhs.mAlarmSnoozeTime ||
54 mAlarmRepeatCount != rhs.mAlarmRepeatCount ||
55 mAlarmEnabled != rhs.mAlarmEnabled ||
56 mHasTime != rhs.mHasTime)
57 return false;
58
59 if (mHasTime) {
60 if (mAlarmTime != rhs.mAlarmTime)
61 return false;
62 } else {
63 if (mOffset != rhs.mOffset ||
64 mEndOffset != rhs.mEndOffset)
65 return false;
66 }
67
68 switch (mType) {
69 case Display:
70 return mDescription == rhs.mDescription;
71
72 case Email:
73 return mDescription == rhs.mDescription &&
74 mMailAttachFiles == rhs.mMailAttachFiles &&
75 mMailAddresses == rhs.mMailAddresses &&
76 mMailSubject == rhs.mMailSubject;
77
78 case Procedure:
79 return mFile == rhs.mFile &&
80 mDescription == rhs.mDescription;
81
82 case Audio:
83 return mFile == rhs.mFile;
84
85 case Invalid:
86 break;
87 }
88 return false;
89}
90
91void Alarm::setType(Alarm::Type type)
92{
93 if (type == mType)
94 return;
95
96 switch (type) {
97 case Display:
98 mDescription = "";
99 break;
100 case Procedure:
101 mFile = mDescription = "";
102 break;
103 case Audio:
104 mFile = "";
105 break;
106 case Email:
107 mMailSubject = mDescription = "";
108 mMailAddresses.clear();
109 mMailAttachFiles.clear();
110 break;
111 case Invalid:
112 break;
113 default:
114 return;
115 }
116 mType = type;
117 mParent->updated();
118}
119
120Alarm::Type Alarm::type() const
121{
122 return mType;
123}
124
125void Alarm::setAudioAlarm(const QString &audioFile)
126{
127 mType = Audio;
128 mFile = audioFile;
129 mParent->updated();
130}
131
132void Alarm::setAudioFile(const QString &audioFile)
133{
134 if (mType == Audio) {
135 mFile = audioFile;
136 mParent->updated();
137 }
138}
139
140QString Alarm::audioFile() const
141{
142 return (mType == Audio) ? mFile : QString::null;
143}
144
145void Alarm::setProcedureAlarm(const QString &programFile, const QString &arguments)
146{
147 mType = Procedure;
148 mFile = programFile;
149 mDescription = arguments;
150 mParent->updated();
151}
152
153void Alarm::setProgramFile(const QString &programFile)
154{
155 if (mType == Procedure) {
156 mFile = programFile;
157 mParent->updated();
158 }
159}
160
161QString Alarm::programFile() const
162{
163 return (mType == Procedure) ? mFile : QString::null;
164}
165
166void Alarm::setProgramArguments(const QString &arguments)
167{
168 if (mType == Procedure) {
169 mDescription = arguments;
170 mParent->updated();
171 }
172}
173
174QString Alarm::programArguments() const
175{
176 return (mType == Procedure) ? mDescription : QString::null;
177}
178
179void Alarm::setEmailAlarm(const QString &subject, const QString &text,
180 const QValueList<Person> &addressees, const QStringList &attachments)
181{
182 mType = Email;
183 mMailSubject = subject;
184 mDescription = text;
185 mMailAddresses = addressees;
186 mMailAttachFiles = attachments;
187 mParent->updated();
188}
189
190void Alarm::setMailAddress(const Person &mailAddress)
191{
192 if (mType == Email) {
193 mMailAddresses.clear();
194 mMailAddresses += mailAddress;
195 mParent->updated();
196 }
197}
198
199void Alarm::setMailAddresses(const QValueList<Person> &mailAddresses)
200{
201 if (mType == Email) {
202 mMailAddresses = mailAddresses;
203 mParent->updated();
204 }
205}
206
207void Alarm::addMailAddress(const Person &mailAddress)
208{
209 if (mType == Email) {
210 mMailAddresses += mailAddress;
211 mParent->updated();
212 }
213}
214
215QValueList<Person> Alarm::mailAddresses() const
216{
217 return (mType == Email) ? mMailAddresses : QValueList<Person>();
218}
219
220void Alarm::setMailSubject(const QString &mailAlarmSubject)
221{
222 if (mType == Email) {
223 mMailSubject = mailAlarmSubject;
224 mParent->updated();
225 }
226}
227
228QString Alarm::mailSubject() const
229{
230 return (mType == Email) ? mMailSubject : QString::null;
231}
232
233void Alarm::setMailAttachment(const QString &mailAttachFile)
234{
235 if (mType == Email) {
236 mMailAttachFiles.clear();
237 mMailAttachFiles += mailAttachFile;
238 mParent->updated();
239 }
240}
241
242void Alarm::setMailAttachments(const QStringList &mailAttachFiles)
243{
244 if (mType == Email) {
245 mMailAttachFiles = mailAttachFiles;
246 mParent->updated();
247 }
248}
249
250void Alarm::addMailAttachment(const QString &mailAttachFile)
251{
252 if (mType == Email) {
253 mMailAttachFiles += mailAttachFile;
254 mParent->updated();
255 }
256}
257
258QStringList Alarm::mailAttachments() const
259{
260 return (mType == Email) ? mMailAttachFiles : QStringList();
261}
262
263void Alarm::setMailText(const QString &text)
264{
265 if (mType == Email) {
266 mDescription = text;
267 mParent->updated();
268 }
269}
270
271QString Alarm::mailText() const
272{
273 return (mType == Email) ? mDescription : QString::null;
274}
275
276void Alarm::setDisplayAlarm(const QString &text)
277{
278 mType = Display;
279 mDescription = text;
280 mParent->updated();
281}
282
283void Alarm::setText(const QString &text)
284{
285 if (mType == Display) {
286 mDescription = text;
287 mParent->updated();
288 }
289}
290
291QString Alarm::text() const
292{
293 return (mType == Display) ? mDescription : QString::null;
294}
295
296void Alarm::setTime(const QDateTime &alarmTime)
297{
298 mAlarmTime = alarmTime;
299 mHasTime = true;
300
301 mParent->updated();
302}
303
304QDateTime Alarm::time() const
305{
306 if ( hasTime() )
307 return mAlarmTime;
308 else
309 {
310 if (mParent->type()=="Todo") {
311 Todo *t = static_cast<Todo*>(mParent);
312 return mOffset.end( t->dtDue() );
313 } else if (mEndOffset) {
314 return mOffset.end( mParent->dtEnd() );
315 } else {
316 return mOffset.end( mParent->dtStart() );
317 }
318 }
319}
320
321bool Alarm::hasTime() const
322{
323 return mHasTime;
324}
325
326void Alarm::setSnoozeTime(int alarmSnoozeTime)
327{
328 mAlarmSnoozeTime = alarmSnoozeTime;
329 mParent->updated();
330}
331
332int Alarm::snoozeTime() const
333{
334 return mAlarmSnoozeTime;
335}
336
337void Alarm::setRepeatCount(int alarmRepeatCount)
338{
339 kdDebug(5800) << "Alarm::setRepeatCount(): " << alarmRepeatCount << endl;
340
341 mAlarmRepeatCount = alarmRepeatCount;
342 mParent->updated();
343}
344
345int Alarm::repeatCount() const
346{
347 kdDebug(5800) << "Alarm::repeatCount(): " << mAlarmRepeatCount << endl;
348 return mAlarmRepeatCount;
349}
350
351void Alarm::toggleAlarm()
352{
353 mAlarmEnabled = !mAlarmEnabled;
354 mParent->updated();
355}
356
357void Alarm::setEnabled(bool enable)
358{
359 mAlarmEnabled = enable;
360 mParent->updated();
361}
362
363bool Alarm::enabled() const
364{
365 return mAlarmEnabled;
366}
367
368void Alarm::setStartOffset( const Duration &offset )
369{
370 mOffset = offset;
371 mEndOffset = false;
372 mHasTime = false;
373 mParent->updated();
374}
375
376Duration Alarm::startOffset() const
377{
378 return (mHasTime || mEndOffset) ? 0 : mOffset;
379}
380
381bool Alarm::hasStartOffset() const
382{
383 return !mHasTime && !mEndOffset;
384}
385
386bool Alarm::hasEndOffset() const
387{
388 return !mHasTime && mEndOffset;
389}
390
391void Alarm::setEndOffset( const Duration &offset )
392{
393 mOffset = offset;
394 mEndOffset = true;
395 mHasTime = false;
396 mParent->updated();
397}
398
399Duration Alarm::endOffset() const
400{
401 return (mHasTime || !mEndOffset) ? 0 : mOffset;
402}
403
404void Alarm::setParent( Incidence *parent )
405{
406 mParent = parent;
407}
diff --git a/libkcal/alarm.h b/libkcal/alarm.h
new file mode 100644
index 0000000..ae2eca3
--- a/dev/null
+++ b/libkcal/alarm.h
@@ -0,0 +1,245 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#ifndef KCAL_ALARM_H
22#define KCAL_ALARM_H
23
24#include <qstring.h>
25#include <qvaluelist.h>
26
27#include "customproperties.h"
28#include "duration.h"
29#include "person.h"
30
31namespace KCal {
32
33class Incidence;
34
35/**
36 This class represents an alarm notification.
37*/
38class Alarm : public CustomProperties
39{
40 public:
41 enum Type { Invalid, Display, Procedure, Email, Audio };
42 typedef QValueList<Alarm *> List;
43
44 /** Construct a new alarm with variables initialized to "sane" values. */
45 explicit Alarm(Incidence *parent);
46 /** Destruct Alarm object. */
47 ~Alarm();
48
49 /** Compare this alarm with another one. */
50 bool operator==(const Alarm &) const;
51 bool operator!=(const Alarm &a) const { return !operator==(a); }
52
53 /** Set the type of the alarm.
54 If the specified type is different from the current type of the alarm,
55 the alarm's type-specific properties are initialised to null.
56 @param type type of alarm.
57 */
58 void setType(Type type);
59 /** Return the type of the alarm */
60 Type type() const;
61
62 /** Set the alarm to be a display alarm.
63 @param text text to display when the alarm is triggered.
64 */
65 void setDisplayAlarm(const QString &text);
66 /** Set the text to be displayed when the alarm is triggered.
67 Ignored if the alarm is not a display alarm.
68 */
69 void setText(const QString &text);
70 /** Return the text string that displays when the alarm is triggered. */
71 QString text() const;
72
73 /** Set the alarm to be an audio alarm.
74 @param audioFile optional file to play when the alarm is triggered.
75 */
76 void setAudioAlarm(const QString &audioFile = QString::null);
77 /** Set the file to play when the audio alarm is triggered.
78 Ignored if the alarm is not an audio alarm.
79 */
80 void setAudioFile(const QString &audioFile);
81 /** Return the name of the audio file for the alarm.
82 @return The audio file for the alarm, or QString::null if not an audio alarm.
83 */
84 QString audioFile() const;
85
86 /** Set the alarm to be a procedure alarm.
87 @param programFile program to execute when the alarm is triggered.
88 @param arguments arguments to supply to programFile.
89 */
90 void setProcedureAlarm(const QString &programFile, const QString &arguments = QString::null);
91 /** Set the program file to execute when the alarm is triggered.
92 Ignored if the alarm is not a procedure alarm.
93 */
94 void setProgramFile(const QString &programFile);
95 /** Return the name of the program file to execute when the alarm is triggered.
96 @return the program file name, or QString::null if not a procedure alarm.
97 */
98 QString programFile() const;
99 /** Set the arguments to the program to execute when the alarm is triggered.
100 Ignored if the alarm is not a procedure alarm.
101 */
102 void setProgramArguments(const QString &arguments);
103 /** Return the arguments to the program to run when the alarm is triggered.
104 @return the program arguments, or QString::null if not a procedure alarm.
105 */
106 QString programArguments() const;
107
108 /** Set the alarm to be an email alarm.
109 @param subject subject line of email.
110 @param text body of email.
111 @param addressees email addresses of recipient(s).
112 @param attachments optional names of files to attach to the email.
113 */
114 void setEmailAlarm(const QString &subject, const QString &text, const QValueList<Person> &addressees,
115 const QStringList &attachments = QStringList());
116
117 /** Send mail to this address when the alarm is triggered.
118 Ignored if the alarm is not an email alarm.
119 */
120 void setMailAddress(const Person &mailAlarmAddress);
121 /** Send mail to these addresses when the alarm is triggered.
122 Ignored if the alarm is not an email alarm.
123 */
124 void setMailAddresses(const QValueList<Person> &mailAlarmAddresses);
125 /** Add this address to the list of addresses to send mail to when the alarm is triggered.
126 Ignored if the alarm is not an email alarm.
127 */
128 void addMailAddress(const Person &mailAlarmAddress);
129 /** return the addresses to send mail to when an alarm goes off */
130 QValueList<Person> mailAddresses() const;
131
132 /** Set the subject line of the mail.
133 Ignored if the alarm is not an email alarm.
134 */
135 void setMailSubject(const QString &mailAlarmSubject);
136 /** return the subject line of the mail */
137 QString mailSubject() const;
138
139 /** Attach this filename to the email.
140 Ignored if the alarm is not an email alarm.
141 */
142 void setMailAttachment(const QString &mailAttachFile);
143 /** Attach these filenames to the email.
144 Ignored if the alarm is not an email alarm.
145 */
146 void setMailAttachments(const QStringList &mailAttachFiles);
147 /** Add this filename to the list of files to attach to the email.
148 Ignored if the alarm is not an email alarm.
149 */
150 void addMailAttachment(const QString &mailAttachFile);
151 /** return the filenames to attach to the email */
152 QStringList mailAttachments() const;
153
154 /** Set the email body text.
155 Ignored if the alarm is not an email alarm.
156 */
157 void setMailText(const QString &text);
158 /** Return the email body text.
159 @return the body text, or QString::null if not an email alarm.
160 */
161 QString mailText() const;
162
163 /** set the time to trigger an alarm */
164 void setTime(const QDateTime &alarmTime);
165 /** return the date/time when an alarm goes off */
166 QDateTime time() const;
167 /** Return true, if the alarm has an explicit date/time. */
168 bool hasTime() const;
169
170 /** Set offset of alarm in time relative to the start of the event. */
171 void setStartOffset(const Duration &);
172 /** Return offset of alarm in time relative to the start of the event.
173 * If the alarm's time is not defined in terms of an offset relative
174 * to the start of the event, returns zero.
175 */
176 Duration startOffset() const;
177 /** Return whether the alarm is defined in terms of an offset relative
178 * to the start of the event.
179 */
180 bool hasStartOffset() const;
181
182 /** Set offset of alarm in time relative to the end of the event. */
183 void setEndOffset(const Duration &);
184 /** Return offset of alarm in time relative to the end of the event.
185 * If the alarm's time is not defined in terms of an offset relative
186 * to the end of the event, returns zero.
187 */
188 Duration endOffset() const;
189 /** Return whether the alarm is defined in terms of an offset relative
190 * to the end of the event.
191 */
192 bool hasEndOffset() const;
193
194 /** Set the interval between snoozes for the alarm.
195 @param snoozeTime the time in minutes between snoozes.
196 */
197 void setSnoozeTime(int alarmSnoozeTime);
198 /** Get how long the alarm snooze interval is.
199 @return the number of minutes between snoozes.
200 */
201 int snoozeTime() const;
202
203 /** set how many times an alarm is to repeat itself (w/snoozes) */
204 void setRepeatCount(int alarmRepeatCount);
205 /** get how many times an alarm repeats */
206 int repeatCount() const;
207
208 /** toggles the value of alarm to be either on or off.
209 set's the alarm time to be x minutes before dtStart time. */
210 void toggleAlarm();
211
212 /** set the alarm enabled status */
213 void setEnabled(bool enable);
214 /** get the alarm enabled status */
215 bool enabled() const;
216
217 /** Set the alarm's parent incidence */
218 void setParent( Incidence * );
219 /** get the alarm's parent incidence */
220 Incidence *parent() const { return mParent; }
221
222 private:
223 Incidence *mParent; // the incidence which this alarm belongs to
224 Type mType; // type of alarm
225 QString mDescription; // text to display/email body/procedure arguments
226 QString mFile; // procedure program to run/optional audio file to play
227 QStringList mMailAttachFiles; // filenames to attach to email
228 QValueList<Person> mMailAddresses; // who to mail for reminder
229 QString mMailSubject; // subject of email
230
231 int mAlarmSnoozeTime; // number of minutes after alarm to
232 // snooze before ringing again
233 int mAlarmRepeatCount; // number of times for alarm to repeat
234 // after the initial time
235
236 QDateTime mAlarmTime; // time at which to trigger the alarm
237 Duration mOffset; // time relative to incidence DTSTART to trigger the alarm
238 bool mEndOffset; // if true, mOffset relates to DTEND, not DTSTART
239 bool mHasTime; // use mAlarmTime, not mOffset
240 bool mAlarmEnabled;
241};
242
243}
244
245#endif
diff --git a/libkcal/attachment.cpp b/libkcal/attachment.cpp
new file mode 100644
index 0000000..1ead923
--- a/dev/null
+++ b/libkcal/attachment.cpp
@@ -0,0 +1,86 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2002 Michael Brade <brade@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include "attachment.h"
22
23using namespace KCal;
24
25Attachment::Attachment(const QString& uri, const QString& mime)
26{
27 mMimeType = mime;
28 mData = uri;
29 mBinary = false;
30}
31
32Attachment::Attachment(const char *base64, const QString& mime)
33{
34 mMimeType = mime;
35 mData = QString::fromUtf8(base64);
36 mBinary = true;
37}
38
39bool Attachment::isURI() const
40{
41 return !mBinary;
42}
43
44QString Attachment::uri() const
45{
46 if (!mBinary)
47 return mData;
48 else
49 return QString::null;
50}
51
52void Attachment::setURI(const QString& uri)
53{
54 mData = uri;
55 mBinary = false;
56}
57
58bool Attachment::isBinary() const
59{
60 return mBinary;
61}
62
63char *Attachment::data() const
64{
65 if (mBinary)
66 return mData.utf8().data();
67 else
68 return 0;
69}
70
71void Attachment::setData(const char *base64)
72{
73 mData = QString::fromUtf8(base64);
74 mBinary = true;
75}
76
77QString Attachment::mimeType() const
78{
79 return mMimeType;
80}
81
82void Attachment::setMimeType(const QString& mime)
83{
84 mMimeType = mime;
85}
86
diff --git a/libkcal/attachment.h b/libkcal/attachment.h
new file mode 100644
index 0000000..cdf2458
--- a/dev/null
+++ b/libkcal/attachment.h
@@ -0,0 +1,69 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2002 Michael Brade <brade@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#ifndef _ATTACHMENT_H
22#define _ATTACHMENT_H
23
24#include <qstring.h>
25
26
27namespace KCal {
28
29/**
30 * This class represents information related to an attachment.
31 */
32class Attachment
33{
34public:
35 /**
36 * Create a Reference to some URI.
37 * @param uri the uri this attachment refers to
38 * @param mime the mime type of the resource being linked to
39 */
40 Attachment(const QString& uri, const QString& mime = QString::null);
41
42 /**
43 * Create a binary attachment.
44 * @param base64 the attachment in base64 format
45 * @param mime the mime type of the attachment
46 */
47 Attachment(const char *base64, const QString& mime = QString::null);
48
49 /* The VALUE parameter in Cal */
50 bool isURI() const;
51 QString uri() const;
52 void setURI(const QString& uri);
53
54 bool isBinary() const;
55 char *data() const;
56 void setData(const char *base64);
57
58 /* The optional FMTTYPE parameter in iCal */
59 QString mimeType() const;
60 void setMimeType(const QString& mime);
61private:
62 QString mMimeType;
63 QString mData;
64 bool mBinary;
65};
66
67}
68
69#endif
diff --git a/libkcal/attendee.cpp b/libkcal/attendee.cpp
new file mode 100644
index 0000000..41c6fcd
--- a/dev/null
+++ b/libkcal/attendee.cpp
@@ -0,0 +1,167 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <qstringlist.h>
22
23#include <kdebug.h>
24#include <klocale.h>
25
26#include "attendee.h"
27
28using namespace KCal;
29
30Attendee::Attendee(const QString &name, const QString &email, bool _rsvp, Attendee::PartStat s,
31 Attendee::Role r,const QString &u) :
32 Person(name,email)
33{
34 mFlag = TRUE;
35 mRSVP = _rsvp;
36 mStatus = s;
37 mRole = r;
38 mUid = u;
39}
40
41Attendee::~Attendee()
42{
43}
44
45
46bool KCal::operator==( const Attendee& a1, const Attendee& a2 )
47{
48 return ( operator==( (const Person&)a1, (const Person&) a2 ) &&
49 a1.RSVP() == a2.RSVP() &&
50 a1.role() == a2.role() &&
51 a1.status() == a2.status() &&
52 a1.uid() == a2.uid() );
53}
54
55
56void Attendee::setStatus(Attendee::PartStat s)
57{
58 mStatus = s;
59}
60
61Attendee::PartStat Attendee::status() const
62{
63 return mStatus;
64}
65
66QString Attendee::statusStr() const
67{
68 return statusName(mStatus);
69}
70
71QString Attendee::statusName( Attendee::PartStat s )
72{
73 switch (s) {
74 default:
75 case NeedsAction:
76 return i18n("Needs Action");
77 break;
78 case Accepted:
79 return i18n("Accepted");
80 break;
81 case Declined:
82 return i18n("Declined");
83 break;
84 case Tentative:
85 return i18n("Tentative");
86 break;
87 case Delegated:
88 return i18n("Delegated");
89 break;
90 case Completed:
91 return i18n("Completed");
92 break;
93 case InProcess:
94 return i18n("In Process");
95 break;
96 }
97}
98
99QStringList Attendee::statusList()
100{
101 QStringList list;
102 list << statusName(NeedsAction);
103 list << statusName(Accepted);
104 list << statusName(Declined);
105 list << statusName(Tentative);
106 list << statusName(Delegated);
107 list << statusName(Completed);
108 list << statusName(InProcess);
109
110 return list;
111}
112
113
114void Attendee::setRole(Attendee::Role r)
115{
116 mRole = r;
117}
118
119Attendee::Role Attendee::role() const
120{
121 return mRole;
122}
123
124QString Attendee::roleStr() const
125{
126 return roleName(mRole);
127}
128
129void Attendee::setUid(QString uid)
130{
131 mUid = uid;
132}
133
134QString Attendee::uid() const
135{
136 return mUid;
137}
138
139QString Attendee::roleName( Attendee::Role r )
140{
141 switch (r) {
142 case Chair:
143 return i18n("Chair");
144 break;
145 default:
146 case ReqParticipant:
147 return i18n("Participant");
148 break;
149 case OptParticipant:
150 return i18n("Optional Participant");
151 break;
152 case NonParticipant:
153 return i18n("Observer");
154 break;
155 }
156}
157
158QStringList Attendee::roleList()
159{
160 QStringList list;
161 list << roleName(ReqParticipant);
162 list << roleName(OptParticipant);
163 list << roleName(NonParticipant);
164 list << roleName(Chair);
165
166 return list;
167}
diff --git a/libkcal/attendee.h b/libkcal/attendee.h
new file mode 100644
index 0000000..1bd2ff3
--- a/dev/null
+++ b/libkcal/attendee.h
@@ -0,0 +1,96 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#ifndef _ATTENDEE_H
22#define _ATTENDEE_H
23
24#include <qstring.h>
25
26#include "person.h"
27
28namespace KCal {
29
30/**
31 This class represents information related to an attendee of an event.
32*/
33class Attendee : public Person
34{
35 public:
36 enum PartStat { NeedsAction, Accepted, Declined, Tentative,
37 Delegated, Completed, InProcess };
38 enum Role { ReqParticipant, OptParticipant, NonParticipant, Chair };
39
40 /**
41 Create Attendee.
42
43 @param name Name
44 @param email Email address
45 @param rsvp Request for reply
46 @param status Status (see enum for list)
47 @param role Role
48 */
49 Attendee(const QString& name, const QString &email,
50 bool rsvp=false, PartStat status=NeedsAction,
51 Role role=ReqParticipant,const QString& u=QString::null);
52 /** Destruct Attendee */
53 virtual ~Attendee();
54
55 /** Set role of Attendee. List of roles still has to be documented. */
56 void setRole( Role );
57 /** Return role of Attendee. */
58 Role role() const;
59 /** Return role as clear text string */
60 QString roleStr() const;
61 static QString roleName( Role );
62 static QStringList roleList();
63
64 /** Holds the uid of the attendee, if applicable **/
65 QString uid() const;
66 void setUid (QString);
67
68 /** Set status. See enum for definitions of possible values */
69 void setStatus(PartStat s);
70 /** Return status. */
71 PartStat status() const;
72 /** Return status as human-readable string. */
73 QString statusStr() const;
74 static QString statusName( PartStat );
75 static QStringList statusList();
76
77 /** Set if Attendee is asked to reply. */
78 void setRSVP(bool r) { mRSVP = r; }
79 /** Return, if Attendee is asked to reply. */
80 bool RSVP() const { return mRSVP; }
81
82 private:
83 bool mRSVP;
84 Role mRole;
85 PartStat mStatus;
86 QString mUid;
87
88 // used to tell whether we have need to mail this person or not.
89 bool mFlag;
90};
91
92 bool operator==( const Attendee& a1, const Attendee& a2 );
93
94}
95
96#endif
diff --git a/libkcal/calendar.cpp b/libkcal/calendar.cpp
new file mode 100644
index 0000000..dc198bd
--- a/dev/null
+++ b/libkcal/calendar.cpp
@@ -0,0 +1,426 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#include <stdlib.h>
23#include <time.h>
24
25#include <kdebug.h>
26#include <kglobal.h>
27#include <klocale.h>
28
29#include "exceptions.h"
30#include "calfilter.h"
31
32#include "calendar.h"
33
34using namespace KCal;
35
36Calendar::Calendar()
37{
38
39 init();
40 setTimeZoneId( i18n (" 00:00 Europe/London(UTC)") );
41}
42
43Calendar::Calendar( const QString &timeZoneId )
44{
45
46 init();
47 setTimeZoneId(timeZoneId);
48}
49
50void Calendar::init()
51{
52 mObserver = 0;
53 mNewObserver = false;
54
55 mModified = false;
56
57 // Setup default filter, which does nothing
58 mDefaultFilter = new CalFilter;
59 mFilter = mDefaultFilter;
60 mFilter->setEnabled(false);
61
62 // initialize random numbers. This is a hack, and not
63 // even that good of one at that.
64// srandom(time(0));
65
66 // user information...
67 setOwner(i18n("Unknown Name"));
68 setEmail(i18n("unknown@nowhere"));
69
70#if 0
71 tmpStr = KOPrefs::instance()->mTimeZone;
72// kdDebug(5800) << "Calendar::Calendar(): TimeZone: " << tmpStr << endl;
73 int dstSetting = KOPrefs::instance()->mDaylightSavings;
74 extern long int timezone;
75 struct tm *now;
76 time_t curtime;
77 curtime = time(0);
78 now = localtime(&curtime);
79 int hourOff = - ((timezone / 60) / 60);
80 if (now->tm_isdst)
81 hourOff += 1;
82 QString tzStr;
83 tzStr.sprintf("%.2d%.2d",
84 hourOff,
85 abs((timezone / 60) % 60));
86
87 // if no time zone was in the config file, write what we just discovered.
88 if (tmpStr.isEmpty()) {
89// KOPrefs::instance()->mTimeZone = tzStr;
90 } else {
91 tzStr = tmpStr;
92 }
93
94 // if daylight savings has changed since last load time, we need
95 // to rewrite these settings to the config file.
96 if ((now->tm_isdst && !dstSetting) ||
97 (!now->tm_isdst && dstSetting)) {
98 KOPrefs::instance()->mTimeZone = tzStr;
99 KOPrefs::instance()->mDaylightSavings = now->tm_isdst;
100 }
101
102 setTimeZone(tzStr);
103#endif
104
105// KOPrefs::instance()->writeConfig();
106}
107
108Calendar::~Calendar()
109{
110 delete mDefaultFilter;
111}
112
113const QString &Calendar::getOwner() const
114{
115 return mOwner;
116}
117
118void Calendar::setOwner(const QString &os)
119{
120 int i;
121 mOwner = os;
122 i = mOwner.find(',');
123 if (i != -1)
124 mOwner = mOwner.left(i);
125
126 setModified( true );
127}
128
129void Calendar::setTimeZone(const QString & tz)
130{
131 bool neg = FALSE;
132 int hours, minutes;
133 QString tmpStr(tz);
134
135 if (tmpStr.left(1) == "-")
136 neg = TRUE;
137 if (tmpStr.left(1) == "-" || tmpStr.left(1) == "+")
138 tmpStr.remove(0, 1);
139 hours = tmpStr.left(2).toInt();
140 if (tmpStr.length() > 2)
141 minutes = tmpStr.right(2).toInt();
142 else
143 minutes = 0;
144 mTimeZone = (60*hours+minutes);
145 if (neg)
146 mTimeZone = -mTimeZone;
147 mLocalTime = false;
148
149 setModified( true );
150}
151
152QString Calendar::getTimeZoneStr() const
153{
154 if (mLocalTime)
155 return "";
156 QString tmpStr;
157 int hours = abs(mTimeZone / 60);
158 int minutes = abs(mTimeZone % 60);
159 bool neg = mTimeZone < 0;
160
161 tmpStr.sprintf("%c%.2d%.2d",
162 (neg ? '-' : '+'),
163 hours, minutes);
164 return tmpStr;
165}
166
167void Calendar::setTimeZone(int tz)
168{
169 mTimeZone = tz;
170 mLocalTime = false;
171
172 setModified( true );
173}
174
175int Calendar::getTimeZone() const
176{
177 return mTimeZone;
178}
179
180void Calendar::setTimeZoneId(const QString &id)
181{
182 mTimeZoneId = id;
183 mLocalTime = false;
184 mTimeZone = KGlobal::locale()->timezoneOffset(mTimeZoneId);
185 if ( mTimeZone > 1000)
186 setLocalTime();
187 //qDebug("Calendar::setTimeZoneOffset %s %d ",mTimeZoneId.latin1(), mTimeZone);
188 setModified( true );
189}
190
191QString Calendar::timeZoneId() const
192{
193 return mTimeZoneId;
194}
195
196void Calendar::setLocalTime()
197{
198 //qDebug("Calendar::setLocalTime() ");
199 mLocalTime = true;
200 mTimeZone = 0;
201 mTimeZoneId = "";
202
203 setModified( true );
204}
205
206bool Calendar::isLocalTime() const
207{
208 return mLocalTime;
209}
210
211const QString &Calendar::getEmail()
212{
213 return mOwnerEmail;
214}
215
216void Calendar::setEmail(const QString &e)
217{
218 mOwnerEmail = e;
219
220 setModified( true );
221}
222
223void Calendar::setFilter(CalFilter *filter)
224{
225 mFilter = filter;
226}
227
228CalFilter *Calendar::filter()
229{
230 return mFilter;
231}
232
233QPtrList<Incidence> Calendar::incidences()
234{
235 QPtrList<Incidence> incidences;
236
237 Incidence *i;
238
239 QPtrList<Event> e = events();
240 for( i = e.first(); i; i = e.next() ) incidences.append( i );
241
242 QPtrList<Todo> t = todos();
243 for( i = t.first(); i; i = t.next() ) incidences.append( i );
244
245 QPtrList<Journal> j = journals();
246 for( i = j.first(); i; i = j.next() ) incidences.append( i );
247
248 return incidences;
249}
250
251QPtrList<Incidence> Calendar::rawIncidences()
252{
253 QPtrList<Incidence> incidences;
254
255 Incidence *i;
256
257 QPtrList<Event> e = rawEvents();
258 for( i = e.first(); i; i = e.next() ) incidences.append( i );
259
260 QPtrList<Todo> t = rawTodos();
261 for( i = t.first(); i; i = t.next() ) incidences.append( i );
262
263 QPtrList<Journal> j = journals();
264 for( i = j.first(); i; i = j.next() ) incidences.append( i );
265
266 return incidences;
267}
268
269QPtrList<Event> Calendar::events( const QDate &date, bool sorted )
270{
271 QPtrList<Event> el = rawEventsForDate(date,sorted);
272 mFilter->apply(&el);
273 return el;
274}
275
276QPtrList<Event> Calendar::events( const QDateTime &qdt )
277{
278 QPtrList<Event> el = rawEventsForDate(qdt);
279 mFilter->apply(&el);
280 return el;
281}
282
283QPtrList<Event> Calendar::events( const QDate &start, const QDate &end,
284 bool inclusive)
285{
286 QPtrList<Event> el = rawEvents(start,end,inclusive);
287 mFilter->apply(&el);
288 return el;
289}
290
291QPtrList<Event> Calendar::events()
292{
293 QPtrList<Event> el = rawEvents();
294 mFilter->apply(&el);
295 return el;
296}
297
298
299bool Calendar::addIncidence(Incidence *i)
300{
301 Incidence::AddVisitor<Calendar> v(this);
302
303 return i->accept(v);
304}
305void Calendar::deleteIncidence(Incidence *in)
306{
307 if ( in->type() == "Event" )
308 deleteEvent( (Event*) in );
309 else if ( in->type() =="Todo" )
310 deleteTodo( (Todo*) in);
311 else if ( in->type() =="Journal" )
312 deleteJournal( (Journal*) in );
313}
314
315Incidence* Calendar::incidence( const QString& uid )
316{
317 Incidence* i;
318
319 if( (i = todo( uid )) != 0 )
320 return i;
321 if( (i = event( uid )) != 0 )
322 return i;
323 if( (i = journal( uid )) != 0 )
324 return i;
325
326 return 0;
327}
328
329QPtrList<Todo> Calendar::todos()
330{
331 QPtrList<Todo> tl = rawTodos();
332 mFilter->apply( &tl );
333 return tl;
334}
335
336// When this is called, the todo have already been added to the calendar.
337// This method is only about linking related todos
338void Calendar::setupRelations( Incidence *incidence )
339{
340 QString uid = incidence->uid();
341 //qDebug("Calendar::setupRelations ");
342 // First, go over the list of orphans and see if this is their parent
343 while( Incidence* i = mOrphans[ uid ] ) {
344 mOrphans.remove( uid );
345 i->setRelatedTo( incidence );
346 incidence->addRelation( i );
347 mOrphanUids.remove( i->uid() );
348 }
349
350 // Now see about this incidences parent
351 if( !incidence->relatedTo() && !incidence->relatedToUid().isEmpty() ) {
352 // This incidence has a uid it is related to, but is not registered to it yet
353 // Try to find it
354 Incidence* parent = this->incidence( incidence->relatedToUid() );
355 if( parent ) {
356 // Found it
357 incidence->setRelatedTo( parent );
358 parent->addRelation( incidence );
359 } else {
360 // Not found, put this in the mOrphans list
361 mOrphans.insert( incidence->relatedToUid(), incidence );
362 mOrphanUids.insert( incidence->uid(), incidence );
363 }
364 }
365}
366
367// If a task with subtasks is deleted, move it's subtasks to the orphans list
368void Calendar::removeRelations( Incidence *incidence )
369{
370 // qDebug("Calendar::removeRelations ");
371 QString uid = incidence->uid();
372
373 QPtrList<Incidence> relations = incidence->relations();
374 for( Incidence* i = relations.first(); i; i = relations.next() )
375 if( !mOrphanUids.find( i->uid() ) ) {
376 mOrphans.insert( uid, i );
377 mOrphanUids.insert( i->uid(), i );
378 i->setRelatedTo( 0 );
379 i->setRelatedToUid( uid );
380 }
381
382 // If this incidence is related to something else, tell that about it
383 if( incidence->relatedTo() )
384 incidence->relatedTo()->removeRelation( incidence );
385
386 // Remove this one from the orphans list
387 if( mOrphanUids.remove( uid ) )
388 // This incidence is located in the orphans list - it should be removed
389 if( !( incidence->relatedTo() != 0 && mOrphans.remove( incidence->relatedTo()->uid() ) ) ) {
390 // Removing wasn't that easy
391 for( QDictIterator<Incidence> it( mOrphans ); it.current(); ++it ) {
392 if( it.current()->uid() == uid ) {
393 mOrphans.remove( it.currentKey() );
394 break;
395 }
396 }
397 }
398}
399
400void Calendar::registerObserver( Observer *observer )
401{
402 mObserver = observer;
403 mNewObserver = true;
404}
405
406void Calendar::setModified( bool modified )
407{
408 if ( mObserver ) mObserver->calendarModified( modified, this );
409 if ( modified != mModified || mNewObserver ) {
410 mNewObserver = false;
411 // if ( mObserver ) mObserver->calendarModified( modified, this );
412 mModified = modified;
413 }
414}
415
416void Calendar::setLoadedProductId( const QString &id )
417{
418 mLoadedProductId = id;
419}
420
421QString Calendar::loadedProductId()
422{
423 return mLoadedProductId;
424}
425
426#include "calendar.moc"
diff --git a/libkcal/calendar.h b/libkcal/calendar.h
new file mode 100644
index 0000000..7a85e74
--- a/dev/null
+++ b/libkcal/calendar.h
@@ -0,0 +1,349 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#ifndef CALENDAR_H
23#define CALENDAR_H
24
25#include <qobject.h>
26#include <qstring.h>
27#include <qdatetime.h>
28#include <qptrlist.h>
29#include <qdict.h>
30
31#include "customproperties.h"
32#include "event.h"
33#include "todo.h"
34#include "journal.h"
35
36#define _TIME_ZONE "-0500" /* hardcoded, overridden in config file. */
37
38class KConfig;
39
40namespace KCal {
41
42class CalFilter;
43
44/**
45 This is the main "calendar" object class for KOrganizer. It holds
46 information like all appointments/events, user information, etc. etc.
47 one calendar is associated with each CalendarView (@see calendarview.h).
48 This is an abstract base class defining the interface to a calendar. It is
49 implemented by subclasses like @see CalendarLocal, which use different
50 methods to store and access the data.
51
52 Ownership of events etc. is handled by the following policy: As soon as an
53 event (or any other subclass of IncidenceBase) object is added to the
54 Calendar by addEvent() it is owned by the Calendar object. The Calendar takes
55 care of deleting it. All Events returned by the query functions are returned
56 as pointers, that means all changes to the returned events are immediately
57 visible in the Calendar. You shouldn't delete any Event object you get from
58 Calendar.
59*/
60class Calendar : public QObject, public CustomProperties,
61 public IncidenceBase::Observer
62{
63 Q_OBJECT
64public:
65 Calendar();
66 Calendar(const QString &timeZoneId);
67 virtual ~Calendar();
68 void deleteIncidence(Incidence *in);
69 /**
70 Clears out the current calendar, freeing all used memory etc.
71 */
72 virtual void close() = 0;
73
74 /**
75 Sync changes in memory to persistant storage.
76 */
77 virtual void save() = 0;
78
79 virtual bool isSaving() { return false; }
80
81 /**
82 Return the owner of the calendar's full name.
83 */
84 const QString &getOwner() const;
85 /**
86 Set the owner of the calendar. Should be owner's full name.
87 */
88 void setOwner( const QString &os );
89 /**
90 Return the email address of the calendar owner.
91 */
92 const QString &getEmail();
93 /**
94 Set the email address of the calendar owner.
95 */
96 void setEmail( const QString & );
97
98 /**
99 Set time zone from a timezone string (e.g. -2:00)
100 */
101 void setTimeZone( const QString &tz );
102 /**
103 Set time zone from a minutes value (e.g. -60)
104 */
105 void setTimeZone( int tz );
106 /**
107 Return time zone as offest in minutes.
108 */
109 int getTimeZone() const;
110 /**
111 Compute an ISO 8601 format string from the time zone.
112 */
113 QString getTimeZoneStr() const;
114 /**
115 Set time zone id (see /usr/share/zoneinfo/zone.tab for list of legal
116 values).
117 */
118 void setTimeZoneId( const QString & );
119 /**
120 Return time zone id.
121 */
122 QString timeZoneId() const;
123 /**
124 Use local time, not UTC or a time zone.
125 */
126 void setLocalTime();
127 /**
128 Return whether local time is being used.
129 */
130 bool isLocalTime() const;
131
132 /**
133 Add an incidence to calendar.
134
135 @return true on success, false on error.
136 */
137 virtual bool addIncidence( Incidence * );
138 /**
139 Return filtered list of all incidences of this calendar.
140 */
141 virtual QPtrList<Incidence> incidences();
142
143 /**
144 Return unfiltered list of all incidences of this calendar.
145 */
146 virtual QPtrList<Incidence> rawIncidences();
147
148 /**
149 Adds a Event to this calendar object.
150 @param anEvent a pointer to the event to add
151
152 @return true on success, false on error.
153 */
154 virtual bool addEventNoDup( Event *event ) = 0;
155 virtual bool addEvent( Event *anEvent ) = 0;
156 /**
157 Delete event from calendar.
158 */
159 virtual void deleteEvent( Event * ) = 0;
160 /**
161 Retrieves an event on the basis of the unique string ID.
162 */
163 virtual Event *event( const QString &UniqueStr ) = 0;
164 virtual Event *event( int ) = 0;
165 /**
166 Builds and then returns a list of all events that match for the
167 date specified. useful for dayView, etc. etc.
168 The calendar filter is applied.
169 */
170 QPtrList<Event> events( const QDate &date, bool sorted = false);
171 /**
172 Get events, which occur on the given date.
173 The calendar filter is applied.
174 */
175 QPtrList<Event> events( const QDateTime &qdt );
176 /**
177 Get events in a range of dates. If inclusive is set to true, only events
178 are returned, which are completely included in the range.
179 The calendar filter is applied.
180 */
181 QPtrList<Event> events( const QDate &start, const QDate &end,
182 bool inclusive = false);
183 /**
184 Return filtered list of all events in calendar.
185 */
186 virtual QPtrList<Event> events();
187 /**
188 Return unfiltered list of all events in calendar.
189 */
190 virtual QPtrList<Event> rawEvents() = 0;
191
192 /**
193 Add a todo to the todolist.
194
195 @return true on success, false on error.
196 */
197 virtual bool addTodo( Todo *todo ) = 0;
198 virtual bool addTodoNoDup( Todo *todo ) = 0;
199 /**
200 Remove a todo from the todolist.
201 */
202 virtual void deleteTodo( Todo * ) = 0;
203 virtual void deleteJournal( Journal * ) = 0;
204 /**
205 Return filterd list of todos.
206 */
207 virtual QPtrList<Todo> todos();
208 /**
209 Searches todolist for an event with this unique string identifier,
210 returns a pointer or null.
211 */
212 virtual Todo *todo( const QString &uid ) = 0;
213 virtual Todo *todo( int ) = 0;
214 /**
215 Returns list of todos due on the specified date.
216 */
217 virtual QPtrList<Todo> todos( const QDate &date ) = 0;
218 /**
219 Return unfiltered list of todos.
220 */
221 virtual QPtrList<Todo> rawTodos() = 0;
222
223 /**
224 Add a Journal entry to calendar.
225
226 @return true on success, false on error.
227 */
228 virtual bool addJournal( Journal * ) = 0;
229 /**
230 Return Journal for given date.
231 */
232 virtual Journal *journal( const QDate & ) = 0;
233 /**
234 Return Journal with given UID.
235 */
236 virtual Journal *journal( const QString &UID ) = 0;
237 /**
238 Return list of all Journal entries.
239 */
240 virtual QPtrList<Journal> journals() = 0;
241
242 /**
243 Searches all incidence types for an incidence with this unique
244 string identifier, returns a pointer or null.
245 */
246 Incidence* incidence( const QString&UID );
247
248 /**
249 Setup relations for an incidence.
250 */
251 virtual void setupRelations( Incidence * );
252 /**
253 Remove all relations to an incidence
254 */
255 virtual void removeRelations( Incidence * );
256
257 /**
258 Set calendar filter, which filters events for the events() functions.
259 The Filter object is owned by the caller.
260 */
261 void setFilter( CalFilter * );
262 /**
263 Return calendar filter.
264 */
265 CalFilter *filter();
266 virtual QDateTime nextAlarm( int daysTo ) = 0;
267 virtual QString nextSummary( ) const = 0;
268 virtual void reInitAlarmSettings() = 0;
269 virtual QDateTime nextAlarmEventDateTime() const = 0;
270 virtual void checkAlarmForIncidence( Incidence *, bool ) = 0;
271 /**
272 Return all alarms, which ocur in the given time interval.
273 */
274 virtual Alarm::List alarms( const QDateTime &from,
275 const QDateTime &to ) = 0;
276
277 class Observer {
278 public:
279 virtual void calendarModified( bool, Calendar * ) = 0;
280 };
281
282 void registerObserver( Observer * );
283
284 void setModified( bool );
285
286 /**
287 Set product id returned by loadedProductId(). This function is only
288 useful for the calendar loading code.
289 */
290 void setLoadedProductId( const QString & );
291 /**
292 Return product id taken from file that has been loaded. Returns
293 QString::null, if no calendar has been loaded.
294 */
295 QString loadedProductId();
296
297 signals:
298 void calendarChanged();
299 void calendarSaved();
300 void calendarLoaded();
301 void addAlarm(const QDateTime &qdt, const QString &noti );
302 void removeAlarm(const QDateTime &qdt, const QString &noti );
303
304 protected:
305 /**
306 Get unfiltered events, which occur on the given date.
307 */
308 virtual QPtrList<Event> rawEventsForDate( const QDateTime &qdt ) = 0;
309 /**
310 Get unfiltered events, which occur on the given date.
311 */
312 virtual QPtrList<Event> rawEventsForDate( const QDate &date,
313 bool sorted = false ) = 0;
314 /**
315 Get events in a range of dates. If inclusive is set to true, only events
316 are returned, which are completely included in the range.
317 */
318 virtual QPtrList<Event> rawEvents( const QDate &start, const QDate &end,
319 bool inclusive = false ) = 0;
320 Incidence *mNextAlarmIncidence;
321
322private:
323 void init();
324
325 QString mOwner; // who the calendar belongs to
326 QString mOwnerEmail; // email address of the owner
327 int mTimeZone; // timezone OFFSET from GMT (MINUTES)
328 bool mLocalTime; // use local time, not UTC or a time zone
329
330 CalFilter *mFilter;
331 CalFilter *mDefaultFilter;
332
333 QString mTimeZoneId;
334
335 Observer *mObserver;
336 bool mNewObserver;
337
338 bool mModified;
339
340 QString mLoadedProductId;
341
342 // This list is used to put together related todos
343 QDict<Incidence> mOrphans;
344 QDict<Incidence> mOrphanUids;
345};
346
347}
348
349#endif
diff --git a/libkcal/calendar.moc b/libkcal/calendar.moc
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/libkcal/calendar.moc
diff --git a/libkcal/calendarlocal.cpp b/libkcal/calendarlocal.cpp
new file mode 100644
index 0000000..8ff8b14
--- a/dev/null
+++ b/libkcal/calendarlocal.cpp
@@ -0,0 +1,655 @@
1/*
2 This file is part of libkcal.
3
4 Copyright (c) 1998 Preston Brown
5 Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21*/
22
23#include <qdatetime.h>
24#include <qstring.h>
25#include <qptrlist.h>
26
27#include <kdebug.h>
28#include <kconfig.h>
29#include <kglobal.h>
30#include <klocale.h>
31
32#include "vcaldrag.h"
33#include "vcalformat.h"
34#include "icalformat.h"
35#include "exceptions.h"
36#include "incidence.h"
37#include "journal.h"
38#include "filestorage.h"
39#include "calfilter.h"
40
41#include "calendarlocal.h"
42
43// #ifndef DESKTOP_VERSION
44// #include <qtopia/alarmserver.h>
45// #endif
46using namespace KCal;
47
48CalendarLocal::CalendarLocal()
49 : Calendar()
50{
51 init();
52}
53
54CalendarLocal::CalendarLocal(const QString &timeZoneId)
55 : Calendar(timeZoneId)
56{
57 init();
58}
59
60void CalendarLocal::init()
61{
62 mNextAlarmIncidence = 0;
63}
64
65
66CalendarLocal::~CalendarLocal()
67{
68 close();
69}
70
71bool CalendarLocal::load( const QString &fileName )
72{
73 FileStorage storage( this, fileName );
74 return storage.load();
75}
76
77bool CalendarLocal::save( const QString &fileName, CalFormat *format )
78{
79 FileStorage storage( this, fileName, format );
80 return storage.save();
81}
82
83void CalendarLocal::close()
84{
85 mEventList.setAutoDelete( true );
86 mTodoList.setAutoDelete( true );
87 mJournalList.setAutoDelete( false );
88
89 mEventList.clear();
90 mTodoList.clear();
91 mJournalList.clear();
92
93 mEventList.setAutoDelete( false );
94 mTodoList.setAutoDelete( false );
95 mJournalList.setAutoDelete( false );
96
97 setModified( false );
98}
99bool CalendarLocal::addEventNoDup( Event *event )
100{
101 Event * eve;
102 for ( eve = mEventList.first(); eve ; eve = mEventList.next() ) {
103 if ( *eve == *event ) {
104 //qDebug("CalendarLocal::Duplicate event found! Not inserted! ");
105 return false;
106 }
107 }
108 return addEvent( event );
109}
110
111bool CalendarLocal::addEvent( Event *event )
112{
113 insertEvent( event );
114
115 event->registerObserver( this );
116
117 setModified( true );
118
119 return true;
120}
121
122void CalendarLocal::deleteEvent( Event *event )
123{
124
125
126 if ( mEventList.removeRef( event ) ) {
127 setModified( true );
128 }
129}
130
131
132Event *CalendarLocal::event( const QString &uid )
133{
134
135 Event *event;
136
137 for ( event = mEventList.first(); event; event = mEventList.next() ) {
138 if ( event->uid() == uid ) {
139 return event;
140 }
141 }
142
143 return 0;
144}
145bool CalendarLocal::addTodoNoDup( Todo *todo )
146{
147 Todo * eve;
148 for ( eve = mTodoList.first(); eve ; eve = mTodoList.next() ) {
149 if ( *eve == *todo ) {
150 //qDebug("duplicate todo found! not inserted! ");
151 return false;
152 }
153 }
154 return addTodo( todo );
155}
156bool CalendarLocal::addTodo( Todo *todo )
157{
158 mTodoList.append( todo );
159
160 todo->registerObserver( this );
161
162 // Set up subtask relations
163 setupRelations( todo );
164
165 setModified( true );
166
167 return true;
168}
169
170void CalendarLocal::deleteTodo( Todo *todo )
171{
172 // Handle orphaned children
173 removeRelations( todo );
174
175 if ( mTodoList.removeRef( todo ) ) {
176 setModified( true );
177 }
178}
179
180QPtrList<Todo> CalendarLocal::rawTodos()
181{
182 return mTodoList;
183}
184Todo *CalendarLocal::todo( int id )
185{
186 Todo *todo;
187 for ( todo = mTodoList.first(); todo; todo = mTodoList.next() ) {
188 if ( todo->zaurusId() == id ) return todo;
189 }
190
191 return 0;
192}
193
194Event *CalendarLocal::event( int id )
195{
196 Event *todo;
197 for ( todo = mEventList.first(); todo; todo = mEventList.next() ) {
198 if ( todo->zaurusId() == id ) return todo;
199 }
200
201 return 0;
202}
203Todo *CalendarLocal::todo( const QString &uid )
204{
205 Todo *todo;
206 for ( todo = mTodoList.first(); todo; todo = mTodoList.next() ) {
207 if ( todo->uid() == uid ) return todo;
208 }
209
210 return 0;
211}
212QString CalendarLocal::nextSummary() const
213{
214 return mNextSummary;
215}
216QDateTime CalendarLocal::nextAlarmEventDateTime() const
217{
218 return mNextAlarmEventDateTime;
219}
220void CalendarLocal::checkAlarmForIncidence( Incidence * incidence, bool deleted)
221{
222 //mNextAlarmIncidence
223 //mNextAlarmDateTime
224 //return mNextSummary;
225 //return mNextAlarmEventDateTime;
226 bool newNextAlarm = false;
227 bool computeNextAlarm = false;
228 bool ok;
229 int offset;
230 QDateTime nextA;
231 // QString nextSum;
232 //QDateTime nextEvent;
233 if ( mNextAlarmIncidence == 0 || incidence == 0 ) {
234 computeNextAlarm = true;
235 } else {
236 if ( ! deleted ) {
237 nextA = incidence->getNextAlarmDateTime(& ok, &offset ) ;
238 if ( ok ) {
239 if ( nextA < mNextAlarmDateTime ) {
240 deRegisterAlarm();
241 mNextAlarmDateTime = nextA;
242 mNextSummary = incidence->summary();
243 mNextAlarmEventDateTime = nextA.addSecs(offset ) ;
244 mNextAlarmEventDateTimeString = KGlobal::locale()->formatDateTime(mNextAlarmEventDateTime);
245 newNextAlarm = true;
246 mNextAlarmIncidence = incidence;
247 } else {
248 if ( incidence == mNextAlarmIncidence ) {
249 computeNextAlarm = true;
250 }
251 }
252 } else {
253 if ( mNextAlarmIncidence == incidence ) {
254 computeNextAlarm = true;
255 }
256 }
257 } else { // deleted
258 if ( incidence == mNextAlarmIncidence ) {
259 computeNextAlarm = true;
260 }
261 }
262 }
263 if ( computeNextAlarm ) {
264 deRegisterAlarm();
265 nextA = nextAlarm( 1000 );
266 if (! mNextAlarmIncidence ) {
267 return;
268 }
269 newNextAlarm = true;
270 }
271 if ( newNextAlarm )
272 registerAlarm();
273}
274QString CalendarLocal:: getAlarmNotification()
275{
276 QString ret;
277 // this should not happen
278 if (! mNextAlarmIncidence )
279 return "cal_alarm"+ mNextSummary.left( 25 )+"\n"+mNextAlarmEventDateTimeString;
280 Alarm* alarm = mNextAlarmIncidence->alarms().first();
281 if ( alarm->type() == Alarm::Procedure ) {
282 ret = "proc_alarm" + alarm->programFile()+"+++";
283 } else {
284 ret = "audio_alarm" +alarm->audioFile() +"+++";
285 }
286 ret += "cal_alarm"+ mNextSummary.left( 25 );
287 if ( mNextSummary.length() > 25 )
288 ret += "\n" + mNextSummary.mid(25, 25 );
289 ret+= "\n"+mNextAlarmEventDateTimeString;
290 return ret;
291}
292
293void CalendarLocal::registerAlarm()
294{
295 mLastAlarmNotificationString = getAlarmNotification();
296 // qDebug("++ register Alarm %s %s",mNextAlarmDateTime.toString().latin1(), mLastAlarmNotificationString.latin1() );
297 emit addAlarm ( mNextAlarmDateTime, mLastAlarmNotificationString );
298// #ifndef DESKTOP_VERSION
299// AlarmServer::addAlarm ( mNextAlarmDateTime,"koalarm", mLastAlarmNotificationString.latin1() );
300// #endif
301}
302void CalendarLocal::deRegisterAlarm()
303{
304 if ( mLastAlarmNotificationString.isNull() )
305 return;
306 //qDebug("-- deregister Alarm %s ", mLastAlarmNotificationString.latin1() );
307
308 emit removeAlarm ( mNextAlarmDateTime, mLastAlarmNotificationString );
309// #ifndef DESKTOP_VERSION
310// AlarmServer::deleteAlarm (mNextAlarmDateTime ,"koalarm" ,mLastAlarmNotificationString.latin1() );
311// #endif
312}
313
314QPtrList<Todo> CalendarLocal::todos( const QDate &date )
315{
316 QPtrList<Todo> todos;
317
318 Todo *todo;
319 for ( todo = mTodoList.first(); todo; todo = mTodoList.next() ) {
320 if ( todo->hasDueDate() && todo->dtDue().date() == date ) {
321 todos.append( todo );
322 }
323 }
324
325 filter()->apply( &todos );
326 return todos;
327}
328void CalendarLocal::reInitAlarmSettings()
329{
330 if ( !mNextAlarmIncidence ) {
331 nextAlarm( 1000 );
332 }
333 deRegisterAlarm();
334 mNextAlarmIncidence = 0;
335 checkAlarmForIncidence( 0, false );
336
337}
338
339
340
341QDateTime CalendarLocal::nextAlarm( int daysTo )
342{
343 QDateTime nextA = QDateTime::currentDateTime().addDays( daysTo );
344 QDateTime start = QDateTime::currentDateTime().addSecs( 30 );
345 QDateTime next;
346 Event *e;
347 bool ok;
348 bool found = false;
349 int offset;
350 mNextAlarmIncidence = 0;
351 for( e = mEventList.first(); e; e = mEventList.next() ) {
352 next = e->getNextAlarmDateTime(& ok, &offset ) ;
353 if ( ok ) {
354 if ( next < nextA ) {
355 nextA = next;
356 found = true;
357 mNextSummary = e->summary();
358 mNextAlarmEventDateTime = next.addSecs(offset ) ;
359 mNextAlarmIncidence = (Incidence *) e;
360 }
361 }
362 }
363 Todo *t;
364 for( t = mTodoList.first(); t; t = mTodoList.next() ) {
365 next = t->getNextAlarmDateTime(& ok, &offset ) ;
366 if ( ok ) {
367 if ( next < nextA ) {
368 nextA = next;
369 found = true;
370 mNextSummary = t->summary();
371 mNextAlarmEventDateTime = next.addSecs(offset );
372 mNextAlarmIncidence = (Incidence *) t;
373 }
374 }
375 }
376 if ( mNextAlarmIncidence ) {
377 mNextAlarmEventDateTimeString = KGlobal::locale()->formatDateTime(mNextAlarmEventDateTime);
378 mNextAlarmDateTime = nextA;
379 }
380 return nextA;
381}
382Alarm::List CalendarLocal::alarmsTo( const QDateTime &to )
383{
384 return alarms( QDateTime( QDate( 1900, 1, 1 ) ), to );
385}
386
387Alarm::List CalendarLocal::alarms( const QDateTime &from, const QDateTime &to )
388{
389 kdDebug(5800) << "CalendarLocal::alarms(" << from.toString() << " - "
390 << to.toString() << ")\n";
391
392 Alarm::List alarms;
393
394 Event *e;
395
396 for( e = mEventList.first(); e; e = mEventList.next() ) {
397 if ( e->doesRecur() ) appendRecurringAlarms( alarms, e, from, to );
398 else appendAlarms( alarms, e, from, to );
399 }
400
401 Todo *t;
402 for( t = mTodoList.first(); t; t = mTodoList.next() ) {
403 appendAlarms( alarms, t, from, to );
404 }
405
406 return alarms;
407}
408
409void CalendarLocal::appendAlarms( Alarm::List &alarms, Incidence *incidence,
410 const QDateTime &from, const QDateTime &to )
411{
412 QPtrList<Alarm> alarmList = incidence->alarms();
413 Alarm *alarm;
414 for( alarm = alarmList.first(); alarm; alarm = alarmList.next() ) {
415// kdDebug(5800) << "CalendarLocal::appendAlarms() '" << alarm->text()
416// << "': " << alarm->time().toString() << " - " << alarm->enabled() << endl;
417 if ( alarm->enabled() ) {
418 if ( alarm->time() >= from && alarm->time() <= to ) {
419 kdDebug(5800) << "CalendarLocal::appendAlarms() '" << incidence->summary()
420 << "': " << alarm->time().toString() << endl;
421 alarms.append( alarm );
422 }
423 }
424 }
425}
426
427void CalendarLocal::appendRecurringAlarms( Alarm::List &alarms,
428 Incidence *incidence,
429 const QDateTime &from,
430 const QDateTime &to )
431{
432
433 QPtrList<Alarm> alarmList = incidence->alarms();
434 Alarm *alarm;
435 QDateTime qdt;
436 for( alarm = alarmList.first(); alarm; alarm = alarmList.next() ) {
437 if (incidence->recursOn(from.date())) {
438 qdt.setTime(alarm->time().time());
439 qdt.setDate(from.date());
440 }
441 else qdt = alarm->time();
442 // qDebug("1 %s %s %s", qdt.toString().latin1(), from.toString().latin1(), to.toString().latin1());
443 if ( alarm->enabled() ) {
444 if ( qdt >= from && qdt <= to ) {
445 alarms.append( alarm );
446 }
447 }
448 }
449}
450
451
452/****************************** PROTECTED METHODS ****************************/
453
454// after changes are made to an event, this should be called.
455void CalendarLocal::update( IncidenceBase *incidence )
456{
457 incidence->setSyncStatus( Event::SYNCMOD );
458 incidence->setLastModified( QDateTime::currentDateTime() );
459 // we should probably update the revision number here,
460 // or internally in the Event itself when certain things change.
461 // need to verify with ical documentation.
462
463 setModified( true );
464}
465
466void CalendarLocal::insertEvent( Event *event )
467{
468 if ( mEventList.findRef( event ) < 0 ) mEventList.append( event );
469}
470
471
472QPtrList<Event> CalendarLocal::rawEventsForDate( const QDate &qd, bool sorted )
473{
474 QPtrList<Event> eventList;
475
476 Event *event;
477 for( event = mEventList.first(); event; event = mEventList.next() ) {
478 if ( event->doesRecur() ) {
479 if ( event->isMultiDay() ) {
480 int extraDays = event->dtStart().date().daysTo( event->dtEnd().date() );
481 int i;
482 for ( i = 0; i <= extraDays; i++ ) {
483 if ( event->recursOn( qd.addDays( -i ) ) ) {
484 eventList.append( event );
485 break;
486 }
487 }
488 } else {
489 if ( event->recursOn( qd ) )
490 eventList.append( event );
491 }
492 } else {
493 if ( event->dtStart().date() <= qd && event->dtEnd().date() >= qd ) {
494 eventList.append( event );
495 }
496 }
497 }
498
499 if ( !sorted ) {
500 return eventList;
501 }
502
503 // kdDebug(5800) << "Sorting events for date\n" << endl;
504 // now, we have to sort it based on dtStart.time()
505 QPtrList<Event> eventListSorted;
506 Event *sortEvent;
507 for ( event = eventList.first(); event; event = eventList.next() ) {
508 sortEvent = eventListSorted.first();
509 int i = 0;
510 while ( sortEvent && event->dtStart().time()>=sortEvent->dtStart().time() )
511 {
512 i++;
513 sortEvent = eventListSorted.next();
514 }
515 eventListSorted.insert( i, event );
516 }
517 return eventListSorted;
518}
519
520
521QPtrList<Event> CalendarLocal::rawEvents( const QDate &start, const QDate &end,
522 bool inclusive )
523{
524 Event *event = 0;
525
526 QPtrList<Event> eventList;
527
528 // Get non-recurring events
529 for( event = mEventList.first(); event; event = mEventList.next() ) {
530 if ( event->doesRecur() ) {
531 QDate rStart = event->dtStart().date();
532 bool found = false;
533 if ( inclusive ) {
534 if ( rStart >= start && rStart <= end ) {
535 // Start date of event is in range. Now check for end date.
536 // if duration is negative, event recurs forever, so do not include it.
537 if ( event->recurrence()->duration() == 0 ) { // End date set
538 QDate rEnd = event->recurrence()->endDate();
539 if ( rEnd >= start && rEnd <= end ) { // End date within range
540 found = true;
541 }
542 } else if ( event->recurrence()->duration() > 0 ) { // Duration set
543 // TODO: Calculate end date from duration. Should be done in Event
544 // For now exclude all events with a duration.
545 }
546 }
547 } else {
548 bool founOne;
549 QDate next = event->getNextOccurence( start, &founOne ).date();
550 if ( founOne ) {
551 if ( next <= end ) {
552 found = true;
553 }
554 }
555
556 /*
557 // crap !!!
558 if ( rStart <= end ) { // Start date not after range
559 if ( rStart >= start ) { // Start date within range
560 found = true;
561 } else if ( event->recurrence()->duration() == -1 ) { // Recurs forever
562 found = true;
563 } else if ( event->recurrence()->duration() == 0 ) { // End date set
564 QDate rEnd = event->recurrence()->endDate();
565 if ( rEnd >= start && rEnd <= end ) { // End date within range
566 found = true;
567 }
568 } else { // Duration set
569 // TODO: Calculate end date from duration. Should be done in Event
570 // For now include all events with a duration.
571 found = true;
572 }
573 }
574 */
575
576 }
577
578 if ( found ) eventList.append( event );
579 } else {
580 QDate s = event->dtStart().date();
581 QDate e = event->dtEnd().date();
582
583 if ( inclusive ) {
584 if ( s >= start && e <= end ) {
585 eventList.append( event );
586 }
587 } else {
588 if ( ( s >= start && s <= end ) || ( e >= start && e <= end ) ) {
589 eventList.append( event );
590 }
591 }
592 }
593 }
594
595 return eventList;
596}
597
598QPtrList<Event> CalendarLocal::rawEventsForDate( const QDateTime &qdt )
599{
600 return rawEventsForDate( qdt.date() );
601}
602
603QPtrList<Event> CalendarLocal::rawEvents()
604{
605 return mEventList;
606}
607
608bool CalendarLocal::addJournal(Journal *journal)
609{
610 if ( journal->dtStart().isValid())
611 kdDebug(5800) << "Adding Journal on " << journal->dtStart().toString() << endl;
612 else
613 kdDebug(5800) << "Adding Journal without a DTSTART" << endl;
614
615 mJournalList.append(journal);
616
617 journal->registerObserver( this );
618
619 setModified( true );
620
621 return true;
622}
623
624void CalendarLocal::deleteJournal( Journal *journal )
625{
626 if ( mJournalList.removeRef(journal) ) {
627 setModified( true );
628 }
629}
630
631Journal *CalendarLocal::journal( const QDate &date )
632{
633// kdDebug(5800) << "CalendarLocal::journal() " << date.toString() << endl;
634
635 for ( Journal *it = mJournalList.first(); it; it = mJournalList.next() )
636 if ( it->dtStart().date() == date )
637 return it;
638
639 return 0;
640}
641
642Journal *CalendarLocal::journal( const QString &uid )
643{
644 for ( Journal *it = mJournalList.first(); it; it = mJournalList.next() )
645 if ( it->uid() == uid )
646 return it;
647
648 return 0;
649}
650
651QPtrList<Journal> CalendarLocal::journals()
652{
653 return mJournalList;
654}
655
diff --git a/libkcal/calendarlocal.h b/libkcal/calendarlocal.h
new file mode 100644
index 0000000..a17cf11
--- a/dev/null
+++ b/libkcal/calendarlocal.h
@@ -0,0 +1,216 @@
1/*
2 This file is part of libkcal.
3
4 Copyright (c) 1998 Preston Brown
5 Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21*/
22#ifndef KCAL_CALENDARLOCAL_H
23#define KCAL_CALENDARLOCAL_H
24
25#include "calendar.h"
26
27namespace KCal {
28
29class CalFormat;
30
31/**
32 This class provides a calendar stored as a local file.
33*/
34class CalendarLocal : public Calendar
35{
36 public:
37 /**
38 Constructs a new calendar, with variables initialized to sane values.
39 */
40 CalendarLocal();
41 /**
42 Constructs a new calendar, with variables initialized to sane values.
43 */
44 CalendarLocal( const QString &timeZoneId );
45 ~CalendarLocal();
46
47 /**
48 Loads a calendar on disk in vCalendar or iCalendar format into the current
49 calendar. Any information already present is lost.
50 @return true, if successfull, false on error.
51 @param fileName the name of the calendar on disk.
52 */
53 bool load( const QString &fileName );
54 /**
55 Writes out the calendar to disk in the specified \a format.
56 CalendarLocal takes ownership of the CalFormat object.
57 @return true, if successfull, false on error.
58 @param fileName the name of the file
59 */
60 bool save( const QString &fileName, CalFormat *format = 0 );
61
62 /**
63 Clears out the current calendar, freeing all used memory etc. etc.
64 */
65 void close();
66
67 void save() {}
68
69 /**
70 Add Event to calendar.
71 */
72 bool addEventNoDup( Event *event );
73 bool addEvent( Event *event );
74 /**
75 Deletes an event from this calendar.
76 */
77 void deleteEvent( Event *event );
78
79 /**
80 Retrieves an event on the basis of the unique string ID.
81 */
82 Event *event( const QString &uid );
83 /**
84 Return unfiltered list of all events in calendar.
85 */
86 QPtrList<Event> rawEvents();
87
88 /**
89 Add a todo to the todolist.
90 */
91 bool addTodo( Todo *todo );
92 bool addTodoNoDup( Todo *todo );
93 /**
94 Remove a todo from the todolist.
95 */
96 void deleteTodo( Todo * );
97 /**
98 Searches todolist for an event with this unique string identifier,
99 returns a pointer or null.
100 */
101 Todo *todo( const QString &uid );
102 /**
103 Return list of all todos.
104 */
105 QPtrList<Todo> rawTodos();
106 /**
107 Returns list of todos due on the specified date.
108 */
109 QPtrList<Todo> todos( const QDate &date );
110 /**
111 Return list of all todos.
112
113 Workaround because compiler does not recognize function of base class.
114 */
115 QPtrList<Todo> todos() { return Calendar::todos(); }
116
117 /**
118 Add a Journal entry to calendar.
119 */
120 bool addJournal( Journal * );
121 /**
122 Remove a Journal from the calendar.
123 */
124 void deleteJournal( Journal * );
125 /**
126 Return Journal for given date.
127 */
128 Journal *journal( const QDate & );
129 /**
130 Return Journal with given UID.
131 */
132 Journal *journal( const QString &uid );
133 /**
134 Return list of all Journals stored in calendar.
135 */
136 QPtrList<Journal> journals();
137
138 /**
139 Return all alarms, which ocur in the given time interval.
140 */
141 Alarm::List alarms( const QDateTime &from, const QDateTime &to );
142
143 /**
144 Return all alarms, which ocur before given date.
145 */
146 Alarm::List alarmsTo( const QDateTime &to );
147
148 QDateTime nextAlarm( int daysTo ) ;
149 QDateTime nextAlarmEventDateTime() const;
150 void checkAlarmForIncidence( Incidence *, bool deleted ) ;
151 void registerAlarm();
152 void deRegisterAlarm();
153 QString getAlarmNotification();
154 QString nextSummary() const ;
155 /**
156 This method should be called whenever a Event is modified directly
157 via it's pointer. It makes sure that the calendar is internally
158 consistent.
159 */
160 void update( IncidenceBase *incidence );
161
162 /**
163 Builds and then returns a list of all events that match for the
164 date specified. useful for dayView, etc. etc.
165 */
166 QPtrList<Event> rawEventsForDate( const QDate &date, bool sorted = false );
167 /**
168 Get unfiltered events for date \a qdt.
169 */
170 QPtrList<Event> rawEventsForDate( const QDateTime &qdt );
171 /**
172 Get unfiltered events in a range of dates. If inclusive is set to true,
173 only events are returned, which are completely included in the range.
174 */
175 QPtrList<Event> rawEvents( const QDate &start, const QDate &end,
176 bool inclusive = false );
177 Todo *CalendarLocal::todo( int uid );
178 Event *CalendarLocal::event( int uid );
179
180
181
182 protected:
183
184 // Event* mNextAlarmEvent;
185 QString mNextSummary;
186 QString mNextAlarmEventDateTimeString;
187 QString mLastAlarmNotificationString;
188 QDateTime mNextAlarmEventDateTime;
189 QDateTime mNextAlarmDateTime;
190 void reInitAlarmSettings();
191
192 /** Notification function of IncidenceBase::Observer. */
193 void incidenceUpdated( IncidenceBase *i ) { update( i ); }
194
195 /** inserts an event into its "proper place" in the calendar. */
196 void insertEvent( Event *event );
197
198 /** Append alarms of incidence in interval to list of alarms. */
199 void appendAlarms( Alarm::List &alarms, Incidence *incidence,
200 const QDateTime &from, const QDateTime &to );
201
202 /** Append alarms of recurring events in interval to list of alarms. */
203 void appendRecurringAlarms( Alarm::List &alarms, Incidence *incidence,
204 const QDateTime &from, const QDateTime &to );
205
206 private:
207 void init();
208
209 QPtrList<Event> mEventList;
210 QPtrList<Todo> mTodoList;
211 QPtrList<Journal> mJournalList;
212};
213
214}
215
216#endif
diff --git a/libkcal/calendarresources.h b/libkcal/calendarresources.h
new file mode 100644
index 0000000..a218dd7
--- a/dev/null
+++ b/libkcal/calendarresources.h
@@ -0,0 +1,17 @@
1#ifndef MICRO_KCAL_CALENDARRESOURCES_H
2#define MICRO_KCAL_CALENDARRESOURCES_H
3
4#include "calendar.h"
5#include "resourcecalendar.h"
6
7namespace KCal {
8
9class CalendarResources : public Calendar
10{
11 public:
12 CalendarResourceManager *resourceManager() { return 0; }
13};
14
15}
16
17#endif
diff --git a/libkcal/calfilter.cpp b/libkcal/calfilter.cpp
new file mode 100644
index 0000000..c182db5
--- a/dev/null
+++ b/libkcal/calfilter.cpp
@@ -0,0 +1,201 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <kdebug.h>
22
23#include "calfilter.h"
24
25using namespace KCal;
26
27CalFilter::CalFilter()
28{
29 mEnabled = true;
30 mCriteria = ShowPublic | ShowPrivate| ShowConfidential ;
31}
32
33CalFilter::CalFilter(const QString &name)
34{
35 mName = name;
36 mEnabled = true;
37 mCriteria = ShowPublic | ShowPrivate| ShowConfidential ;
38}
39
40CalFilter::~CalFilter()
41{
42}
43
44void CalFilter::apply(QPtrList<Event> *eventlist)
45{
46 if (!mEnabled) return;
47
48// kdDebug(5800) << "CalFilter::apply()" << endl;
49
50 Event *event = eventlist->first();
51 while(event) {
52 if (!filterEvent(event)) {
53 eventlist->remove();
54 event = eventlist->current();
55 } else {
56 event = eventlist->next();
57 }
58 }
59
60// kdDebug(5800) << "CalFilter::apply() done" << endl;
61}
62
63// TODO: avoid duplicating apply() code
64void CalFilter::apply(QPtrList<Todo> *eventlist)
65{
66 if (!mEnabled) return;
67
68// kdDebug(5800) << "CalFilter::apply()" << endl;
69
70 Todo *event = eventlist->first();
71 while(event) {
72 if (!filterTodo(event)) {
73 eventlist->remove();
74 event = eventlist->current();
75 } else {
76 event = eventlist->next();
77 }
78 }
79
80// kdDebug(5800) << "CalFilter::apply() done" << endl;
81}
82
83bool CalFilter::filterEvent(Event *event)
84{
85// kdDebug(5800) << "CalFilter::filterEvent(): " << event->getSummary() << endl;
86
87 if (mCriteria & HideRecurring) {
88 if (event->recurrence()->doesRecur()) return false;
89 }
90
91 return filterIncidence(event);
92}
93
94bool CalFilter::filterTodo(Todo *todo)
95{
96// kdDebug(5800) << "CalFilter::filterEvent(): " << event->getSummary() << endl;
97
98 if (mCriteria & HideCompleted) {
99 if (todo->isCompleted()) return false;
100 }
101
102 return filterIncidence(todo);
103}
104bool CalFilter::showCategories()
105{
106 return mCriteria & ShowCategories;
107}
108int CalFilter::getSecrecy()
109{
110 if ( (mCriteria & ShowPublic ))
111 return Incidence::SecrecyPublic;
112 if ( (mCriteria & ShowPrivate ))
113 return Incidence::SecrecyPrivate;
114 if ( (mCriteria & ShowConfidential ))
115 return Incidence::SecrecyConfidential;
116 return Incidence::SecrecyPublic;
117}
118bool CalFilter::filterIncidence(Incidence *incidence)
119{
120 if ( mCriteria > 7 ) {
121 switch (incidence->secrecy()) {
122 case Incidence::SecrecyPublic:
123 if (! (mCriteria & ShowPublic ))
124 return false;
125 break;
126 case Incidence::SecrecyPrivate:
127 if (! (mCriteria & ShowPrivate ))
128 return false;
129 break;
130 case Incidence::SecrecyConfidential:
131 if (! (mCriteria & ShowConfidential ))
132 return false;
133 break;
134 default:
135 return false;
136 break;
137 }
138 }
139
140 // kdDebug(5800) << "CalFilter::filterEvent(): " << event->getSummary() << endl;
141
142 if (mCriteria & ShowCategories) {
143 for (QStringList::Iterator it = mCategoryList.begin();
144 it != mCategoryList.end(); ++it ) {
145 QStringList incidenceCategories = incidence->categories();
146 for (QStringList::Iterator it2 = incidenceCategories.begin();
147 it2 != incidenceCategories.end(); ++it2 ) {
148 if ((*it) == (*it2)) {
149 return true;
150 }
151 }
152 }
153 return false;
154 } else {
155 for (QStringList::Iterator it = mCategoryList.begin();
156 it != mCategoryList.end(); ++it ) {
157 QStringList incidenceCategories = incidence->categories();
158 for (QStringList::Iterator it2 = incidenceCategories.begin();
159 it2 != incidenceCategories.end(); ++it2 ) {
160 if ((*it) == (*it2)) {
161 return false;
162 }
163 }
164 }
165 return true;
166 }
167
168// kdDebug(5800) << "CalFilter::filterEvent(): passed" << endl;
169
170 return true;
171}
172
173void CalFilter::setEnabled(bool enabled)
174{
175 mEnabled = enabled;
176}
177
178bool CalFilter::isEnabled()
179{
180 return mEnabled;
181}
182
183void CalFilter::setCriteria(int criteria)
184{
185 mCriteria = criteria;
186}
187
188int CalFilter::criteria()
189{
190 return mCriteria;
191}
192
193void CalFilter::setCategoryList(const QStringList &categoryList)
194{
195 mCategoryList = categoryList;
196}
197
198QStringList CalFilter::categoryList()
199{
200 return mCategoryList;
201}
diff --git a/libkcal/calfilter.h b/libkcal/calfilter.h
new file mode 100644
index 0000000..d6d4717
--- a/dev/null
+++ b/libkcal/calfilter.h
@@ -0,0 +1,128 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#ifndef _CALFILTER_H
22#define _CALFILTER_H
23
24#include <qstring.h>
25#include <qptrlist.h>
26
27#include "event.h"
28#include "todo.h"
29
30namespace KCal {
31
32/**
33 Filter for calendar objects.
34*/
35class CalFilter {
36 public:
37 /** Construct filter. */
38 CalFilter();
39 /** Construct filter with name */
40 CalFilter(const QString &name);
41 /** Destruct filter. */
42 ~CalFilter();
43
44 /**
45 Set name of filter.
46 */
47 void setName(const QString &name) { mName = name; }
48 /**
49 Return name of filter.
50 */
51 QString name() const { return mName; }
52
53 /**
54 Apply filter to eventlist, all events not matching filter criterias are
55 removed from the list.
56 */
57 void apply(QPtrList<Event> *eventlist);
58
59 /**
60 Apply filter to todolist, all todos not matching filter criterias are
61 removed from the list.
62 */
63 void apply(QPtrList<Todo> *todolist);
64
65 /**
66 Apply filter criteria on the specified event. Return true, if event passes
67 criteria, otherwise return false.
68 */
69 bool filterEvent(Event *);
70
71 /**
72 Apply filter criteria on the specified todo. Return true, if event passes
73 criteria, otherwise return false.
74 */
75 bool filterTodo(Todo *);
76
77 /**
78 Apply filter criteria on the specified incidence. Return true, if event passes
79 criteria, otherwise return false.
80 */
81 bool filterIncidence(Incidence *);
82
83 /**
84 Enable or disable filter.
85 */
86 void setEnabled(bool);
87 /**
88 Return wheter the filter is enabled or not.
89 */
90 bool isEnabled();
91 bool showCategories();
92 int getSecrecy();
93 /**
94 Set list of categories, which is used for showing/hiding categories of
95 events.
96 See related functions.
97 */
98 void setCategoryList(const QStringList &);
99 /**
100 Return category list, used for showing/hiding categories of events.
101 See related functions.
102 */
103 QStringList categoryList();
104
105 enum { HideRecurring = 1, HideCompleted = 2, ShowCategories = 4 ,ShowPublic = 8, ShowPrivate = 16, ShowConfidential = 32 };
106
107 /**
108 Set criteria, which have to be fulfilled by events passing the filter.
109 */
110 void setCriteria(int);
111 /**
112 Get inclusive filter criteria.
113 */
114 int criteria();
115
116 private:
117 QString mName;
118
119 int mCriteria;
120
121 bool mEnabled;
122
123 QStringList mCategoryList;
124};
125
126}
127
128#endif /* _CALFILTER_H */
diff --git a/libkcal/calformat.cpp b/libkcal/calformat.cpp
new file mode 100644
index 0000000..8a3d069
--- a/dev/null
+++ b/libkcal/calformat.cpp
@@ -0,0 +1,98 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <klocale.h>
22#include <kdebug.h>
23#include <kapplication.h>
24
25#include "calformat.h"
26
27using namespace KCal;
28
29QString CalFormat::mApplication = QString::fromLatin1("libkcal");
30QString CalFormat::mProductId = QString::fromLatin1("-//K Desktop Environment//NONSGML libkcal 3.1//EN");
31
32// An array containing the PRODID strings indexed against the calendar file format version used.
33// Every time the calendar file format is changed, add an entry/entries to this list.
34struct CalVersion {
35 int version;
36 QString prodId;
37};
38static CalVersion prodIds[] = {
39 { 220, QString::fromLatin1("-//K Desktop Environment//NONSGML KOrganizer 2.2//EN") },
40 { 300, QString::fromLatin1("-//K Desktop Environment//NONSGML KOrganizer 3.0//EN") },
41 { 310, QString::fromLatin1("-//K Desktop Environment//NONSGML KOrganizer 3.1//EN") },
42 { 0 , QString() }
43};
44
45
46CalFormat::CalFormat()
47{
48 mException = 0;
49}
50
51CalFormat::~CalFormat()
52{
53 delete mException;
54}
55
56void CalFormat::clearException()
57{
58 delete mException;
59 mException = 0;
60}
61
62void CalFormat::setException(ErrorFormat *exception)
63{
64 delete mException;
65 mException = exception;
66}
67
68ErrorFormat *CalFormat::exception()
69{
70 return mException;
71}
72
73void CalFormat::setApplication(const QString& application, const QString& productID)
74{
75 mApplication = application;
76 mProductId = productID;
77}
78
79QString CalFormat::createUniqueId()
80{
81 int hashTime = QTime::currentTime().hour() +
82 QTime::currentTime().minute() + QTime::currentTime().second() +
83 QTime::currentTime().msec();
84 QString uidStr = QString("%1-%2.%3")
85 .arg(mApplication)
86 .arg(KApplication::random())
87 .arg(hashTime);
88 return uidStr;
89}
90
91int CalFormat::calendarVersion(const char* prodId)
92{
93 for (const CalVersion* cv = prodIds; cv->version; ++cv) {
94 if (!strcmp(prodId, cv->prodId.local8Bit()))
95 return cv->version;
96 }
97 return 0;
98}
diff --git a/libkcal/calformat.h b/libkcal/calformat.h
new file mode 100644
index 0000000..0c7ee7e
--- a/dev/null
+++ b/libkcal/calformat.h
@@ -0,0 +1,111 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef _CALFORMAT_H
21#define _CALFORMAT_H
22
23#include <qstring.h>
24#include <qdatetime.h>
25#include <qevent.h>
26
27#include "exceptions.h"
28#include "event.h"
29
30namespace KCal {
31
32class VCalDrag;
33class Calendar;
34
35/**
36 This is the base class for calendar formats. It provides an interface for the
37 generation/interpretation of a textual representation of a calendar.
38
39 @short Class providing in interface to a calendar format
40*/
41class CalFormat {
42 public:
43 /** Constructs a new format. */
44 CalFormat();
45 /** Destruct calendar format. */
46 virtual ~CalFormat();
47
48 /**
49 loads a calendar on disk into the calendar associated with this format.
50 Returns TRUE if successful,else returns FALSE.
51 @param fileName the name of the calendar on disk.
52 */
53 virtual bool load(Calendar *, const QString &fileName) = 0;
54 /** writes out the calendar to disk. Returns true if
55 * successful and false on error.
56 * @param fileName the name of the file
57 */
58 virtual bool save(Calendar *, const QString &fileName) = 0;
59
60 /**
61 Parse string and populate calendar with that information.
62 */
63 virtual bool fromString(Calendar *, const QString & ) = 0;
64 /**
65 Return calendar information as string.
66 */
67 virtual QString toString(Calendar *) = 0;
68
69 /** Clear exception status of this format object */
70 void clearException();
71 /**
72 Return exception, if there is any, containing information about the last
73 error that occured.
74 */
75 ErrorFormat *exception();
76
77 /** Set the application name for use in unique IDs and error messages,
78 * and product ID for incidence PRODID property
79 */
80 static void setApplication(const QString& app, const QString& productID);
81 /** Return the application name used in unique IDs and error messages */
82 static const QString& application() { return mApplication; }
83 /** Return the PRODID string to write into calendar files */
84 static const QString& productId() { return mProductId; }
85 /** Return the KDE calendar format version indicated by a PRODID property */
86 static int calendarVersion(const char* prodId);
87 /** Return the PRODID string loaded from calendar file */
88 const QString &loadedProductId() { return mLoadedProductId; }
89
90 /** Create a unique id string. */
91 static QString createUniqueId();
92
93 /**
94 Set exception for this object. This is used by the functions of this
95 class to report errors.
96 */
97 void setException(ErrorFormat *error);
98
99 protected:
100 QString mLoadedProductId; // PRODID string loaded from calendar file
101
102 private:
103 ErrorFormat *mException;
104
105 static QString mApplication; // name of application for unique ID strings
106 static QString mProductId; // PRODID string to write to calendar files
107};
108
109}
110
111#endif
diff --git a/libkcal/calstorage.h b/libkcal/calstorage.h
new file mode 100644
index 0000000..72972ea
--- a/dev/null
+++ b/libkcal/calstorage.h
@@ -0,0 +1,52 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef KCAL_CALSTORAGE_H
21#define KCAL_CALSTORAGE_H
22
23namespace KCal {
24
25class Calendar;
26
27/**
28 This class provides the interface to the storage of a calendar.
29*/
30class CalStorage
31{
32 public:
33 CalStorage( Calendar *calendar )
34 {
35 mCalendar = calendar;
36 }
37 virtual ~CalStorage() {}
38
39 Calendar *calendar() const { return mCalendar; }
40
41 virtual bool open() = 0;
42 virtual bool load(bool = false ) = 0;
43 virtual bool save() = 0;
44 virtual bool close() = 0;
45
46 private:
47 Calendar *mCalendar;
48};
49
50}
51
52#endif
diff --git a/libkcal/compat.cpp b/libkcal/compat.cpp
new file mode 100644
index 0000000..070e082
--- a/dev/null
+++ b/libkcal/compat.cpp
@@ -0,0 +1,37 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include "compat.h"
22
23#include <kdebug.h>
24
25#include <qregexp.h>
26
27using namespace KCal;
28
29Compat *CompatFactory::createCompat( const QString & )
30{
31 return new Compat;
32}
33
34void CompatPre31::fixFloatingEnd( QDate &endDate )
35{
36 endDate = endDate.addDays( 1 );
37}
diff --git a/libkcal/compat.h b/libkcal/compat.h
new file mode 100644
index 0000000..42d44fa
--- a/dev/null
+++ b/libkcal/compat.h
@@ -0,0 +1,53 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef KCAL_COMPAT_H
21#define KCAL_COMPAT_H
22
23#include <qstring.h>
24#include <qdatetime.h>
25
26namespace KCal {
27
28class Compat;
29
30class CompatFactory
31{
32 public:
33 static Compat *createCompat( const QString &productId );
34};
35
36class Compat
37{
38 public:
39 Compat() {};
40 virtual ~Compat() {};
41
42 virtual void fixFloatingEnd( QDate & ) {}
43};
44
45class CompatPre31 : public Compat
46{
47 public:
48 void fixFloatingEnd( QDate & );
49};
50
51}
52
53#endif
diff --git a/libkcal/customproperties.cpp b/libkcal/customproperties.cpp
new file mode 100644
index 0000000..adc1710
--- a/dev/null
+++ b/libkcal/customproperties.cpp
@@ -0,0 +1,114 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2002 David Jarvie <software@astrojar.org.uk>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include "customproperties.h"
22
23using namespace KCal;
24
25CustomProperties::CustomProperties()
26{
27}
28
29CustomProperties::CustomProperties(const CustomProperties &cp)
30 : mProperties(cp.mProperties)
31{
32}
33
34CustomProperties::~CustomProperties()
35{
36}
37
38void CustomProperties::setCustomProperty(const QCString &app, const QCString &key,
39 const QString &value)
40{
41 if (value.isNull() || key.isEmpty() || app.isEmpty())
42 return;
43 QCString property = "X-KDE-" + app + "-" + key;
44 if (!checkName(property))
45 return;
46 mProperties[property] = value;
47}
48
49void CustomProperties::removeCustomProperty(const QCString &app, const QCString &key)
50{
51 removeNonKDECustomProperty(QCString("X-KDE-" + app + "-" + key));
52}
53
54QString CustomProperties::customProperty(const QCString &app, const QCString &key) const
55{
56 return nonKDECustomProperty(QCString("X-KDE-" + app + "-" + key));
57}
58
59void CustomProperties::setNonKDECustomProperty(const QCString &name, const QString &value)
60{
61 if (value.isNull() || !checkName(name))
62 return;
63 mProperties[name] = value;
64}
65
66void CustomProperties::removeNonKDECustomProperty(const QCString &name)
67{
68 QMap<QCString, QString>::Iterator it = mProperties.find(name);
69 if (it != mProperties.end())
70 mProperties.remove(it);
71}
72
73QString CustomProperties::nonKDECustomProperty(const QCString &name) const
74{
75 QMap<QCString, QString>::ConstIterator it = mProperties.find(name);
76 if (it == mProperties.end())
77 return QString::null;
78 return it.data();
79}
80
81void CustomProperties::setCustomProperties(const QMap<QCString, QString> &properties)
82{
83 for (QMap<QCString, QString>::ConstIterator it = properties.begin(); it != properties.end(); ++it) {
84 // Validate the property name and convert any null string to empty string
85 if (checkName(it.key())) {
86 mProperties[it.key()] = it.data().isNull() ? QString("") : it.data();
87 }
88 }
89}
90
91QMap<QCString, QString> CustomProperties::customProperties() const
92{
93 return mProperties;
94}
95
96bool CustomProperties::checkName(const QCString &name)
97{
98 // Check that the property name starts with 'X-' and contains
99 // only the permitted characters
100 const char* n = name;
101 int len = name.length();
102 if (len < 2 || n[0] != 'X' || n[1] != '-')
103 return false;
104 for (int i = 2; i < len; ++i) {
105 char ch = n[i];
106 if (ch >= 'A' && ch <= 'Z'
107 || ch >= 'a' && ch <= 'z'
108 || ch >= '0' && ch <= '9'
109 || ch == '-')
110 continue;
111 return false; // invalid character found
112 }
113 return true;
114}
diff --git a/libkcal/customproperties.h b/libkcal/customproperties.h
new file mode 100644
index 0000000..0cbfdcd
--- a/dev/null
+++ b/libkcal/customproperties.h
@@ -0,0 +1,97 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2002 David Jarvie <software@astrojar.org.uk>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#ifndef KCAL_CUSTOM_PROPERTIES_H
22#define KCAL_CUSTOM_PROPERTIES_H
23
24#include <qstring.h>
25#include <qmap.h>
26
27namespace KCal {
28
29/**
30 This class represents custom calendar properties.
31 It is used as a base class for classes which represent calendar components.
32 A custom property name written by libkcal has the form X-KDE-APP-KEY where
33 APP represents the application name, and KEY distinguishes individual
34 properties for the application.
35 In keeping with RFC2445, property names must be composed only of the
36 characters A-Z, a-z, 0-9 and '-'.
37*/
38class CustomProperties
39{
40 public:
41 /** Construct a new empty custom properties instance */
42 CustomProperties();
43 CustomProperties(const CustomProperties &);
44 ~CustomProperties();
45
46 /** Create or modify a custom calendar property.
47 @param app Application name as it appears in the custom property name.
48 @param key Property identifier specific to the application.
49 @param value The property's value. A call with a value of QString::null
50 will be ignored.
51 */
52 void setCustomProperty(const QCString &app, const QCString &key,
53 const QString &value);
54 /** Delete a custom calendar property.
55 @param app Application name as it appears in the custom property name.
56 @param key Property identifier specific to the application.
57 */
58 void removeCustomProperty(const QCString &app, const QCString &key);
59 /** Return the value of a custom calendar property.
60 @param app Application name as it appears in the custom property name.
61 @param key Property identifier specific to the application.
62 @return Property value, or QString::null if (and only if) the property does not exist.
63 */
64 QString customProperty(const QCString &app, const QCString &key) const;
65
66 /** Create or modify a non-KDE or non-standard custom calendar property.
67 @param name Full property name
68 @param value The property's value. A call with a value of QString::null
69 will be ignored.
70 */
71 void setNonKDECustomProperty(const QCString &name, const QString &value);
72 /** Delete a non-KDE or non-standard custom calendar property.
73 @param name Full property name
74 */
75 void removeNonKDECustomProperty(const QCString &name);
76 /** Return the value of a non-KDE or non-standard custom calendar property.
77 @param name Full property name
78 @return Property value, or QString::null if (and only if) the property does not exist.
79 */
80 QString nonKDECustomProperty(const QCString& name) const;
81
82 /** Initialise the alarm's custom calendar properties to the specified
83 key/value pairs.
84 */
85 void setCustomProperties(const QMap<QCString, QString> &properties);
86 /** Return all custom calendar property key/value pairs. */
87 QMap<QCString, QString> customProperties() const;
88
89 private:
90 static bool checkName(const QCString& name);
91
92 QMap<QCString, QString> mProperties; // custom calendar properties
93};
94
95}
96
97#endif
diff --git a/libkcal/dndfactory.h b/libkcal/dndfactory.h
new file mode 100644
index 0000000..6b73f34
--- a/dev/null
+++ b/libkcal/dndfactory.h
@@ -0,0 +1,62 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001,2002 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22// $Id$
23
24#ifndef KCAL_DNDFACTORY_H
25#define KCAL_DNDFACTORY_H
26
27#include "vcalformat.h"
28
29class QDropEvent;
30
31namespace KCal {
32
33/**
34 This class implements functions to create Drag and Drop objects used for
35 Drag-and-Drop and Copy-and-Paste.
36
37 @short vCalendar Drag-and-Drop object factory.
38*/
39class DndFactory {
40 public:
41 DndFactory( Calendar * ) {}
42
43 /** create an object to be used with the Xdnd Drag And Drop protocol. */
44 ICalDrag *createDrag(Event *, QWidget *) { return 0; }
45 /** create an object to be used with the Xdnd Drag And Drop protocol. */
46 ICalDrag *createDragTodo(Todo *, QWidget *) { return 0; }
47 /** Create Todo object from drop event */
48 Todo *createDropTodo(QDropEvent *) { return 0; }
49 /** Create Event object from drop event */
50 Event *createDrop(QDropEvent *) { return 0; }
51
52 /** cut event to clipboard */
53 void cutEvent(Event *) {}
54 /** cut, copy, and paste operations follow. */
55 bool copyEvent(Event *) { return false; }
56 /** pastes the event and returns a pointer to the new event pasted. */
57 Event *pasteEvent(const QDate &, const QTime *newTime = 0) { return 0; }
58};
59
60}
61
62#endif
diff --git a/libkcal/dummyscheduler.cpp b/libkcal/dummyscheduler.cpp
new file mode 100644
index 0000000..ae40e6d
--- a/dev/null
+++ b/libkcal/dummyscheduler.cpp
@@ -0,0 +1,119 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21//
22// DummyScheduler - iMIP implementation of iTIP methods
23//
24
25#include <qfile.h>
26#include <qtextstream.h>
27
28#include <kdebug.h>
29
30#include "event.h"
31#include "icalformat.h"
32
33#include "dummyscheduler.h"
34
35using namespace KCal;
36
37DummyScheduler::DummyScheduler(Calendar *calendar)
38 : Scheduler(calendar)
39{
40}
41
42DummyScheduler::~DummyScheduler()
43{
44}
45
46bool DummyScheduler::publish (IncidenceBase *incidence,const QString &recipients)
47{
48 QString messageText = mFormat->createScheduleMessage(incidence,
49 Scheduler::Publish);
50
51 return saveMessage(messageText);
52}
53
54bool DummyScheduler::performTransaction(IncidenceBase *incidence,Method method,const QString &recipients)
55{
56 QString messageText = mFormat->createScheduleMessage(incidence,method);
57
58 return saveMessage(messageText);
59}
60
61bool DummyScheduler::performTransaction(IncidenceBase *incidence,Method method)
62{
63 QString messageText = mFormat->createScheduleMessage(incidence,method);
64
65 return saveMessage(messageText);
66}
67
68bool DummyScheduler::saveMessage(const QString &message)
69{
70 QFile f("dummyscheduler.store");
71 if (f.open(IO_WriteOnly | IO_Append)) {
72 QTextStream t(&f);
73 t << message << endl;
74 f.close();
75 return true;
76 } else {
77 return false;
78 }
79}
80
81QPtrList<ScheduleMessage> DummyScheduler::retrieveTransactions()
82{
83 QPtrList<ScheduleMessage> messageList;
84
85 QFile f("dummyscheduler.store");
86 if (!f.open(IO_ReadOnly)) {
87 kdDebug(5800) << "DummyScheduler::retrieveTransactions(): Can't open file"
88 << endl;
89 } else {
90 QTextStream t(&f);
91 QString messageString;
92 QString messageLine = t.readLine();
93 while (!messageLine.isNull()) {
94// kdDebug(5800) << "++++++++" << messageLine << endl;
95 messageString += messageLine + "\n";
96 if (messageLine.find("END:VCALENDAR") >= 0) {
97 kdDebug(5800) << "---------------" << messageString << endl;
98 ScheduleMessage *message = mFormat->parseScheduleMessage(mCalendar,
99 messageString);
100 kdDebug(5800) << "--Parsed" << endl;
101 if (message) {
102 messageList.append(message);
103 } else {
104 QString errorMessage;
105 if (mFormat->exception()) {
106 errorMessage = mFormat->exception()->message();
107 }
108 kdDebug(5800) << "DummyScheduler::retrieveTransactions() Error parsing "
109 "message: " << errorMessage << endl;
110 }
111 messageString="";
112 }
113 messageLine = t.readLine();
114 }
115 f.close();
116 }
117
118 return messageList;
119}
diff --git a/libkcal/dummyscheduler.h b/libkcal/dummyscheduler.h
new file mode 100644
index 0000000..df42153
--- a/dev/null
+++ b/libkcal/dummyscheduler.h
@@ -0,0 +1,51 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef DUMMYSCHEDULER_H
21#define DUMMYSCHEDULER_H
22//
23// Dummy implementation of iTIP methods
24//
25
26#include "scheduler.h"
27
28namespace KCal {
29
30/**
31 This class implements the iTIP interface as a primitive local version for
32 testing. It uses a file dummyscheduler.store as inbox/outbox.
33*/
34class DummyScheduler : public Scheduler {
35 public:
36 DummyScheduler(Calendar *);
37 virtual ~DummyScheduler();
38
39 bool publish (IncidenceBase *incidence,const QString &recipients);
40 bool performTransaction(IncidenceBase *incidence,Method method);
41 bool performTransaction(IncidenceBase *incidence,Method method,const QString &recipients);
42 QPtrList<ScheduleMessage> retrieveTransactions();
43
44 protected:
45 bool saveMessage(const QString &);
46};
47
48}
49
50#endif // DUMMYSCHEDULER_H
51
diff --git a/libkcal/duration.cpp b/libkcal/duration.cpp
new file mode 100644
index 0000000..3d57136
--- a/dev/null
+++ b/libkcal/duration.cpp
@@ -0,0 +1,59 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <kdebug.h>
22#include <klocale.h>
23
24#include "duration.h"
25
26using namespace KCal;
27
28Duration::Duration()
29{
30 mSeconds = 0;
31}
32
33Duration::Duration( const QDateTime &start, const QDateTime &end )
34{
35 mSeconds = start.secsTo( end );
36}
37
38Duration::Duration( int seconds )
39{
40 mSeconds = seconds;
41}
42
43
44bool KCal::operator==( const Duration& d1, const Duration& d2 )
45{
46 return ( d1.asSeconds() == d2.asSeconds() );
47}
48
49
50
51QDateTime Duration::end( const QDateTime &start ) const
52{
53 return start.addSecs( mSeconds );
54}
55
56int Duration::asSeconds() const
57{
58 return mSeconds;
59}
diff --git a/libkcal/duration.h b/libkcal/duration.h
new file mode 100644
index 0000000..81274dd
--- a/dev/null
+++ b/libkcal/duration.h
@@ -0,0 +1,48 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef KCAL_DURATION_H
21#define KCAL_DURATION_H
22
23#include <qdatetime.h>
24
25namespace KCal {
26
27class Duration
28{
29 public:
30 Duration();
31 Duration( const QDateTime &start, const QDateTime &end );
32 Duration( int seconds );
33
34 QDateTime end( const QDateTime &start ) const;
35
36 int asSeconds() const;
37
38 private:
39 int mSeconds;
40};
41
42 bool operator==( const Duration&, const Duration& );
43 inline bool operator!=( const Duration &d1, const Duration &d2 )
44 { return !operator==( d1, d2 ); }
45
46}
47
48#endif
diff --git a/libkcal/event.cpp b/libkcal/event.cpp
new file mode 100644
index 0000000..dd67252
--- a/dev/null
+++ b/libkcal/event.cpp
@@ -0,0 +1,178 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <kglobal.h>
22#include <klocale.h>
23#include <kdebug.h>
24
25#include "event.h"
26
27using namespace KCal;
28
29Event::Event() :
30 mHasEndDate( false ), mTransparency( Opaque )
31{
32}
33
34Event::Event(const Event &e) : Incidence(e)
35{
36 mDtEnd = e.mDtEnd;
37 mHasEndDate = e.mHasEndDate;
38 mTransparency = e.mTransparency;
39}
40
41Event::~Event()
42{
43}
44
45Incidence *Event::clone()
46{
47 kdDebug(5800) << "Event::clone()" << endl;
48 return new Event(*this);
49}
50
51bool KCal::operator==( const Event& e1, const Event& e2 )
52{
53 return operator==( (const Incidence&)e1, (const Incidence&)e2 ) &&
54 e1.dtEnd() == e2.dtEnd() &&
55 e1.hasEndDate() == e2.hasEndDate() &&
56 e1.transparency() == e2.transparency();
57}
58
59
60
61void Event::setDtEnd(const QDateTime &dtEnd)
62{
63 if (mReadOnly) return;
64
65 mDtEnd = getEvenTime( dtEnd );
66
67 setHasEndDate(true);
68 setHasDuration(false);
69
70 updated();
71}
72
73QDateTime Event::dtEnd() const
74{
75 if (hasEndDate()) return mDtEnd;
76 if (hasDuration()) return dtStart().addSecs(duration());
77
78 kdDebug(5800) << "Warning! Event '" << summary()
79 << "' does have neither end date nor duration." << endl;
80 return dtStart();
81}
82
83QString Event::dtEndTimeStr() const
84{
85 return KGlobal::locale()->formatTime(mDtEnd.time());
86}
87
88QString Event::dtEndDateStr(bool shortfmt) const
89{
90 return KGlobal::locale()->formatDate(mDtEnd.date(),shortfmt);
91}
92
93QString Event::dtEndStr(bool shortfmt) const
94{
95 return KGlobal::locale()->formatDateTime(mDtEnd, shortfmt);
96}
97
98void Event::setHasEndDate(bool b)
99{
100 mHasEndDate = b;
101}
102
103bool Event::hasEndDate() const
104{
105 return mHasEndDate;
106}
107
108bool Event::isMultiDay() const
109{
110 bool multi = !(dtStart().date() == dtEnd().date());
111 return multi;
112}
113
114void Event::setTransparency(Event::Transparency transparency)
115{
116 if (mReadOnly) return;
117 mTransparency = transparency;
118 updated();
119}
120
121Event::Transparency Event::transparency() const
122{
123 return mTransparency;
124}
125
126void Event::setDuration(int seconds)
127{
128 setHasEndDate(false);
129 Incidence::setDuration(seconds);
130}
131QDateTime Event::getNextAlarmDateTime( bool * ok, int * offset ) const
132{
133
134 bool yes;
135 QDateTime incidenceStart = getNextOccurence( QDateTime::currentDateTime(), &yes );
136 if ( ! yes || cancelled() ) {
137 *ok = false;
138 return QDateTime ();
139 }
140
141 bool enabled = false;
142 Alarm* alarm;
143 int off;
144 QDateTime alarmStart = QDateTime::currentDateTime().addDays( 3650 );;
145 // if ( QDateTime::currentDateTime() > incidenceStart ){
146// *ok = false;
147// return incidenceStart;
148// }
149 for (QPtrListIterator<Alarm> it(mAlarms); (alarm = it.current()) != 0; ++it) {
150 if (alarm->enabled()) {
151 if ( alarm->hasTime () ) {
152 if ( alarm->time() < alarmStart ) {
153 alarmStart = alarm->time();
154 enabled = true;
155 off = alarmStart.secsTo( incidenceStart );
156 }
157
158 } else {
159 int secs = alarm->startOffset().asSeconds();
160 if ( incidenceStart.addSecs( secs ) < alarmStart ) {
161 alarmStart = incidenceStart.addSecs( secs );
162 enabled = true;
163 off = -secs;
164 }
165 }
166 }
167 }
168 if ( enabled ) {
169 if ( alarmStart > QDateTime::currentDateTime() ) {
170 *ok = true;
171 * offset = off;
172 return alarmStart;
173 }
174 }
175 *ok = false;
176 return QDateTime ();
177
178}
diff --git a/libkcal/event.h b/libkcal/event.h
new file mode 100644
index 0000000..2a8bd95
--- a/dev/null
+++ b/libkcal/event.h
@@ -0,0 +1,88 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#ifndef EVENT_H
22#define EVENT_H
23//
24// Event component, representing a VEVENT object
25//
26
27#include "incidence.h"
28namespace KCal {
29
30/**
31 This class provides an Event in the sense of RFC2445.
32*/
33class Event : public Incidence
34{
35 public:
36 enum Transparency { Opaque, Transparent };
37 typedef ListBase<Event> List;
38 Event();
39 Event(const Event &);
40 ~Event();
41
42 QCString type() const { return "Event"; }
43
44 Incidence *clone();
45 QDateTime getNextAlarmDateTime( bool * ok, int * offset ) const;
46
47 /** for setting an event's ending date/time with a QDateTime. */
48 void setDtEnd(const QDateTime &dtEnd);
49 /** Return the event's ending date/time as a QDateTime. */
50 virtual QDateTime dtEnd() const;
51 /** returns an event's end time as a string formatted according to the
52 users locale settings */
53 QString dtEndTimeStr() const;
54 /** returns an event's end date as a string formatted according to the
55 users locale settings */
56 QString dtEndDateStr(bool shortfmt=true) const;
57 /** returns an event's end date and time as a string formatted according
58 to the users locale settings */
59 QString dtEndStr(bool shortfmt=true) const;
60 void setHasEndDate(bool);
61 /** Return whether the event has an end date/time. */
62 bool hasEndDate() const;
63
64 /** Return true if the event spans multiple days, otherwise return false. */
65 bool isMultiDay() const;
66
67 /** set the event's time transparency level. */
68 void setTransparency(Transparency transparency);
69 /** get the event's time transparency level. */
70 Transparency transparency() const;
71
72 void setDuration(int seconds);
73
74 private:
75 bool accept(Visitor &v) { return v.visit(this); }
76
77 QDateTime mDtEnd;
78 bool mHasEndDate;
79 Transparency mTransparency;
80};
81
82bool operator==( const Event&, const Event& );
83
84
85}
86
87
88#endif
diff --git a/libkcal/exceptions.cpp b/libkcal/exceptions.cpp
new file mode 100644
index 0000000..bc298f9
--- a/dev/null
+++ b/libkcal/exceptions.cpp
@@ -0,0 +1,90 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <klocale.h>
22
23#include "calformat.h"
24#include "exceptions.h"
25
26using namespace KCal;
27
28Exception::Exception(const QString &message)
29{
30 mMessage = message;
31}
32
33Exception::~Exception()
34{
35}
36
37QString Exception::message()
38{
39 if (mMessage.isEmpty()) return i18n("%1 Error").arg(CalFormat::application());
40 else return mMessage;
41}
42
43
44ErrorFormat::ErrorFormat(ErrorCodeFormat code,const QString &message) :
45 Exception(message)
46{
47 mCode = code;
48}
49
50QString ErrorFormat::message()
51{
52 QString message = "";
53
54 switch (mCode) {
55 case LoadError:
56 message = i18n("Load Error");
57 break;
58 case SaveError:
59 message = i18n("Save Error");
60 break;
61 case ParseErrorIcal:
62 message = i18n("Parse Error in libical");
63 break;
64 case ParseErrorKcal:
65 message = i18n("Parse Error in libkcal");
66 break;
67 case NoCalendar:
68 message = i18n("No calendar component found.");
69 break;
70 case CalVersion1:
71 message = i18n("vCalendar Version 1.0 detected.");
72 break;
73 case CalVersion2:
74 message = i18n("iCalendar Version 2.0 detected.");
75 break;
76 case Restriction:
77 message = i18n("Restriction violation");
78 default:
79 break;
80 }
81
82 if (!mMessage.isEmpty()) message += ": " + mMessage;
83
84 return message;
85}
86
87ErrorFormat::ErrorCodeFormat ErrorFormat::errorCode()
88{
89 return mCode;
90}
diff --git a/libkcal/exceptions.h b/libkcal/exceptions.h
new file mode 100644
index 0000000..4b75df8
--- a/dev/null
+++ b/libkcal/exceptions.h
@@ -0,0 +1,75 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#ifndef KCAL_EXCEPTIONS_H
22#define KCAL_EXCEPTIONS_H
23//
24// Exception classes of libkcal.
25//
26// We don't use actual C++ exceptions right now. These classes are currently
27// returned by an error function, but we can build upon them, when we start
28// to use C++ exceptions.
29
30#include <qstring.h>
31
32namespace KCal {
33
34/**
35 KOrganizer exceptions base class. This is currently used as a fancy kind of error code not as an
36 C++ exception.
37*/
38class Exception {
39 public:
40 /** Construct exception with descriptive message \a message. */
41 Exception(const QString &message=QString::null);
42 virtual ~Exception();
43
44 /** Return descriptive message of exception. */
45 virtual QString message();
46
47 protected:
48 QString mMessage;
49};
50
51/** Calendar format related error class */
52class ErrorFormat : public Exception {
53 public:
54 enum ErrorCodeFormat { LoadError, SaveError,
55 ParseErrorIcal, ParseErrorKcal,
56 NoCalendar,
57 CalVersion1,CalVersion2,
58 CalVersionUnknown,
59 Restriction };
60
61 /** Create format error exception. */
62 ErrorFormat(ErrorCodeFormat code,const QString &message = QString::null);
63
64 /** Return format error message. */
65 QString message();
66 /** Return format error code. */
67 ErrorCodeFormat errorCode();
68
69 private:
70 ErrorCodeFormat mCode;
71};
72
73}
74
75#endif
diff --git a/libkcal/filestorage.cpp b/libkcal/filestorage.cpp
new file mode 100644
index 0000000..00c15d9
--- a/dev/null
+++ b/libkcal/filestorage.cpp
@@ -0,0 +1,140 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <stdlib.h>
22
23#include <qdatetime.h>
24#include <qstring.h>
25#include <qptrlist.h>
26
27#include <kdebug.h>
28
29#include "calendar.h"
30#include "vcaldrag.h"
31#include "vcalformat.h"
32#include "icalformat.h"
33
34#include "filestorage.h"
35
36using namespace KCal;
37
38FileStorage::FileStorage( Calendar *cal, const QString &fileName,
39 CalFormat *format )
40 : CalStorage( cal ),
41 mFileName( fileName ),
42 mSaveFormat( format )
43{
44}
45
46FileStorage::~FileStorage()
47{
48 delete mSaveFormat;
49}
50
51void FileStorage::setFileName( const QString &fileName )
52{
53 mFileName = fileName;
54}
55
56QString FileStorage::fileName()const
57{
58 return mFileName;
59}
60
61
62void FileStorage::setSaveFormat( CalFormat *format )
63{
64 delete mSaveFormat;
65 mSaveFormat = format;
66}
67
68CalFormat *FileStorage::saveFormat()const
69{
70 return mSaveFormat;
71}
72
73
74bool FileStorage::open()
75{
76 return true;
77}
78
79bool FileStorage::load( bool quick )
80{
81 kdDebug(5800) << "FileStorage::load(): '" << mFileName << "'" << endl;
82
83 // do we want to silently accept this, or make some noise? Dunno...
84 // it is a semantical thing vs. a practical thing.
85 if (mFileName.isEmpty()) return false;
86
87 // Always try to load with iCalendar. It will detect, if it is actually a
88 // vCalendar file.
89 ICalFormat iCal (quick );
90
91 bool success = iCal.load( calendar(), mFileName);
92
93 if ( !success ) {
94 if ( iCal.exception() ) {
95// kdDebug(5800) << "---Error: " << mFormat->exception()->errorCode() << endl;
96 if ( iCal.exception()->errorCode() == ErrorFormat::CalVersion1 ) {
97 // Expected non vCalendar file, but detected vCalendar
98 kdDebug(5800) << "FileStorage::load() Fallback to VCalFormat" << endl;
99 VCalFormat vCal;
100 success = vCal.load( calendar(), mFileName );
101 calendar()->setLoadedProductId( vCal.productId() );
102 } else {
103 return false;
104 }
105 } else {
106 kdDebug(5800) << "Warning! There should be set an exception." << endl;
107 return false;
108 }
109 } else {
110// kdDebug(5800) << "---Success" << endl;
111 calendar()->setLoadedProductId( iCal.loadedProductId() );
112 }
113
114 calendar()->setModified( false );
115
116 return true;
117}
118
119bool FileStorage::save()
120{
121 if ( mFileName.isEmpty() ) return false;
122
123 bool success;
124
125 if ( mSaveFormat ) {
126 success = mSaveFormat->save( calendar(), mFileName);
127 } else {
128 ICalFormat iCal;
129 success = iCal.save( calendar(), mFileName);
130 }
131
132 if ( success ) calendar()->setModified( false );
133
134 return success;
135}
136
137bool FileStorage::close()
138{
139 return true;
140}
diff --git a/libkcal/filestorage.h b/libkcal/filestorage.h
new file mode 100644
index 0000000..e9dc15e
--- a/dev/null
+++ b/libkcal/filestorage.h
@@ -0,0 +1,58 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef KCAL_FILESTORAGE_H
21#define KCAL_FILESTORAGE_H
22
23#include "calstorage.h"
24
25namespace KCal {
26
27/**
28 This class provides a calendar storage as a local file.
29*/
30class FileStorage : public CalStorage
31{
32 public:
33 FileStorage( Calendar *, const QString &fileName = QString::null,
34 CalFormat *format = 0 );
35 virtual ~FileStorage();
36
37 void setFileName( const QString &mFileName );
38 QString fileName()const;
39
40 /**
41 FileStorage takes ownership of format object.
42 */
43 void setSaveFormat( CalFormat * );
44 CalFormat *saveFormat()const;
45
46 bool open();
47 bool load(bool quick = false );
48 bool save();
49 bool close();
50
51 private:
52 QString mFileName;
53 CalFormat *mSaveFormat;
54};
55
56}
57
58#endif
diff --git a/libkcal/freebusy.cpp b/libkcal/freebusy.cpp
new file mode 100644
index 0000000..ba15d6d
--- a/dev/null
+++ b/libkcal/freebusy.cpp
@@ -0,0 +1,184 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <kdebug.h>
22
23#include "freebusy.h"
24
25using namespace KCal;
26
27FreeBusy::FreeBusy()
28{
29}
30
31FreeBusy::FreeBusy(const QDateTime &start, const QDateTime &end)
32{
33 setDtStart(start);
34 setDtEnd(end);
35}
36
37FreeBusy::FreeBusy( Calendar *calendar, const QDateTime &start, const QDateTime &end )
38{
39 kdDebug() << "FreeBusy::FreeBusy" << endl;
40 mCalendar = calendar;
41
42 setDtStart(start);
43 setDtEnd(end);
44
45 //Gets all the events in the calendar
46 QPtrList<Event> eventList = mCalendar->events();
47 Event *event;
48
49 int extraDays, i, x, duration;
50 duration = start.daysTo(end);
51 QDate day;
52 QDateTime tmpStart;
53 QDateTime tmpEnd;
54 //Loops through every event in the calendar
55 for( event = eventList.first(); event; event = eventList.next() ) {
56 //This whole for loop is for recurring events, it loops through
57 //each of the days of the freebusy request
58
59 //First check if this is transparent. If it is, it shouldn't be in the
60 //freebusy list
61 if ( event->transparency() == Event::Transparent )
62 // Transparent
63 continue;
64
65 for(i=0; i<=duration; i++) {
66 day=(start.addDays(i).date());
67 tmpStart.setDate(day);
68 tmpEnd.setDate(day);
69
70 if( (*(event->recurrence())).doesRecur() ) {
71 if ( event->isMultiDay() ) {
72 extraDays = event->dtStart().date().daysTo(event->dtEnd().date());
73 for (x=0; x<=extraDays; x++) {
74 if ( event->recursOn(day.addDays(-x))) {
75 tmpStart.setDate(day.addDays(-x));
76 tmpStart.setTime(event->dtStart().time());
77 tmpEnd=tmpStart.addSecs( (event->duration()) );
78
79 addLocalPeriod( tmpStart, tmpEnd );
80 break;
81 }
82 }
83 } else {
84 if (event->recursOn(day)) {
85 tmpStart.setTime(event->dtStart().time());
86 tmpEnd.setTime(event->dtEnd().time());
87
88 addLocalPeriod (tmpStart, tmpEnd);
89 }
90 }
91 }
92
93 }
94 //Non-reocurring events
95 addLocalPeriod(event->dtStart(), event->dtEnd());
96 }
97
98 sortList();
99}
100
101FreeBusy::~FreeBusy()
102{
103}
104
105bool FreeBusy::setDtEnd( const QDateTime &end )
106{
107 mDtEnd = end;
108 return true;
109}
110
111QDateTime FreeBusy::dtEnd() const
112{
113 return mDtEnd;
114}
115
116QValueList<Period> FreeBusy::busyPeriods() const
117{
118 return mBusyPeriods;
119}
120
121bool FreeBusy::addLocalPeriod(const QDateTime &eventStart, const QDateTime &eventEnd ) {
122 QDateTime tmpStart;
123 QDateTime tmpEnd;
124
125 //Check to see if the start *or* end of the event is
126 //between the start and end of the freebusy dates.
127 if (!((((this->dtStart()).secsTo(eventStart)>=0)&&(eventStart.secsTo(this->dtEnd())>=0))
128 ||(((this->dtStart()).secsTo(eventEnd) >= 0)&&(eventEnd.secsTo(this->dtEnd()) >= 0))))
129 return false;
130
131 if ( eventStart.secsTo(this->dtStart())>=0) {
132 tmpStart = this->dtStart();
133 } else {
134 tmpStart = eventStart;
135 }
136
137 if ( eventEnd.secsTo(this->dtEnd())<=0 ) {
138 tmpEnd = this->dtEnd();
139 } else {
140 tmpEnd = eventEnd;
141 }
142
143 Period p(tmpStart, tmpEnd);
144 mBusyPeriods.append( p );
145
146 return true;
147}
148
149FreeBusy::FreeBusy(QValueList<Period> busyPeriods)
150{
151 mBusyPeriods = busyPeriods;
152}
153
154void FreeBusy::sortList()
155{
156 typedef QValueList<Period> PeriodList;
157
158 PeriodList::Iterator tmpPeriod, earlyPeriod;
159 PeriodList sortedList;
160 QDateTime earlyTime;
161
162 while( mBusyPeriods.count() > 0 ) {
163 earlyTime=(*mBusyPeriods.begin()).start();
164 for (tmpPeriod=mBusyPeriods.begin(); tmpPeriod!=mBusyPeriods.end(); tmpPeriod++) {
165 if (earlyTime.secsTo((*tmpPeriod).start()) <= 0) {
166 earlyTime=(*tmpPeriod).start();
167 earlyPeriod=tmpPeriod;
168 }
169 }
170 //Move tmpPeriod to sortedList
171 Period tmpPeriod( (*earlyPeriod).start(), (*earlyPeriod).end() );
172 sortedList.append( tmpPeriod );
173 mBusyPeriods.remove( earlyPeriod );
174 }
175 mBusyPeriods=sortedList;
176}
177
178void FreeBusy::addPeriod(const QDateTime &start, const QDateTime &end)
179{
180 Period p(start, end);
181 mBusyPeriods.append( p );
182
183 sortList();
184}
diff --git a/libkcal/freebusy.h b/libkcal/freebusy.h
new file mode 100644
index 0000000..054feda
--- a/dev/null
+++ b/libkcal/freebusy.h
@@ -0,0 +1,72 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef KCAL_FREEBUSY_H
21#define KCAL_FREEBUSY_H
22//
23// FreeBusy - information about free/busy times
24//
25
26#include <qdatetime.h>
27#include <qvaluelist.h>
28#include <qptrlist.h>
29
30#include "period.h"
31#include "calendar.h"
32
33#include "incidencebase.h"
34
35namespace KCal {
36
37/**
38 This class provides information about free/busy time of a calendar user.
39*/
40class FreeBusy : public IncidenceBase
41{
42 public:
43 FreeBusy();
44 FreeBusy(const QDateTime &start, const QDateTime &end);
45 FreeBusy(Calendar *calendar, const QDateTime &start, const QDateTime &end);
46 FreeBusy(QValueList<Period> busyPeriods);
47
48 ~FreeBusy();
49
50 QCString type() const { return "FreeBusy"; }
51
52 virtual QDateTime dtEnd() const;
53 bool setDtEnd( const QDateTime &end );
54
55 QValueList<Period> busyPeriods() const;
56
57 void addPeriod(const QDateTime &start, const QDateTime &end);
58 void sortList();
59
60 private:
61
62 //This is used for creating a freebusy object for the current user
63 bool addLocalPeriod(const QDateTime &start, const QDateTime &end);
64
65 QDateTime mDtEnd;
66 QValueList<Period> mBusyPeriods;
67 Calendar *mCalendar;
68};
69
70}
71
72#endif
diff --git a/libkcal/icaldrag.cpp b/libkcal/icaldrag.cpp
new file mode 100644
index 0000000..446a115
--- a/dev/null
+++ b/libkcal/icaldrag.cpp
@@ -0,0 +1,58 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#include "icaldrag.h"
23
24#include "icalformat.h"
25
26#include <kdebug.h>
27
28using namespace KCal;
29
30ICalDrag::ICalDrag( Calendar *cal, QWidget *parent, const char *name )
31 : QStoredDrag( "text/calendar", parent, name )
32{
33 ICalFormat icf;
34 QString scal = icf.toString( cal );
35
36 setEncodedData( scal.utf8() );
37}
38
39bool ICalDrag::canDecode( QMimeSource *me )
40{
41 return me->provides( "text/calendar" );
42}
43
44bool ICalDrag::decode( QMimeSource *de, Calendar *cal )
45{
46 bool success = false;
47
48 QByteArray payload = de->encodedData( "text/calendar" );
49 if ( payload.size() ) {
50 QString txt = QString::fromUtf8( payload.data() );
51
52 ICalFormat icf;
53 success = icf.fromString( cal, txt );
54 }
55
56 return success;
57}
58
diff --git a/libkcal/icaldrag.h b/libkcal/icaldrag.h
new file mode 100644
index 0000000..fdf32b7
--- a/dev/null
+++ b/libkcal/icaldrag.h
@@ -0,0 +1,46 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#ifndef ICALDRAG_H
23#define ICALDRAG_H
24
25#include <qdragobject.h>
26#include "calendar.h"
27
28namespace KCal {
29
30/** iCalendar drag&drop class. */
31class ICalDrag : public QStoredDrag
32{
33 public:
34 /** Create a drag&drop object for iCalendar component \a ical. */
35 ICalDrag( Calendar *cal, QWidget *parent = 0, const char *name = 0 );
36 ~ICalDrag() {};
37
38 /** Return, if drag&drop object can be decode to iCalendar. */
39 static bool canDecode( QMimeSource * );
40 /** Decode drag&drop object to iCalendar component \a cal. */
41 static bool decode( QMimeSource *e, Calendar *cal );
42};
43
44}
45
46#endif
diff --git a/libkcal/icalformat.cpp b/libkcal/icalformat.cpp
new file mode 100644
index 0000000..5893db5
--- a/dev/null
+++ b/libkcal/icalformat.cpp
@@ -0,0 +1,478 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <qdatetime.h>
22#include <qstring.h>
23#include <qptrlist.h>
24#include <qregexp.h>
25#include <qclipboard.h>
26#include <qfile.h>
27#include <qtextstream.h>
28#include <qtextcodec.h>
29#include <stdlib.h>
30
31#include <kdebug.h>
32#include <kglobal.h>
33#include <klocale.h>
34
35extern "C" {
36 #include <ical.h>
37 #include <icalss.h>
38 #include <icalparser.h>
39 #include <icalrestriction.h>
40}
41
42#include "calendar.h"
43#include "calendarlocal.h"
44#include "journal.h"
45
46#include "icalformat.h"
47#include "icalformatimpl.h"
48
49#define _ICAL_VERSION "2.0"
50
51using namespace KCal;
52
53ICalFormat::ICalFormat(bool quick )
54{
55 mQuicksave = false; //quick;
56 mImpl = new ICalFormatImpl( this );
57 tzOffsetMin = 0;
58 //qDebug("new ICalFormat() ");
59}
60
61ICalFormat::~ICalFormat()
62{
63 delete mImpl;
64 //qDebug("delete ICalFormat ");
65}
66
67bool ICalFormat::load( Calendar *calendar, const QString &fileName)
68{
69
70 clearException();
71
72 QFile file( fileName );
73 if (!file.open( IO_ReadOnly ) ) {
74 setException(new ErrorFormat(ErrorFormat::LoadError));
75 return false;
76 }
77 QTextStream ts( &file );
78 QString text;
79#if 0
80 if ( !mQuicksave ) {
81 qDebug("KO: No quickload!");
82 ts.setEncoding( QTextStream::Latin1 );
83 text = ts.read();
84 } else {
85 ts.setCodec( QTextCodec::codecForName("utf8") );
86 text = ts.read();
87 }
88#endif
89 ts.setEncoding( QTextStream::Latin1 );
90 text = ts.read();
91 file.close();
92
93 return fromString( calendar, text );
94}
95
96//#include <qdatetime.h>
97bool ICalFormat::save( Calendar *calendar, const QString &fileName )
98{
99 //kdDebug(5800) << "ICalFormat::save(): " << fileName << endl;
100 //qDebug("ICalFormat::save ");
101 clearException();
102 QString text = toString( calendar );
103 //return false;
104 // qDebug("to string takes ms: %d ",is.elapsed() );
105 if ( text.isNull() ) return false;
106
107 // TODO: write backup file
108 //is.restart();
109 QFile file( fileName );
110 if (!file.open( IO_WriteOnly ) ) {
111 setException(new ErrorFormat(ErrorFormat::SaveError,
112 i18n("Could not open file '%1'").arg(fileName)));
113 return false;
114 }
115 QTextStream ts( &file );
116
117// #ifdef DESKTOP_VERSION
118// mQuicksave = false;
119// #endif
120// if ( mQuicksave ) {
121// ts << text.utf8();
122// } else {
123// ts.setEncoding( QTextStream::Latin1 );
124// ts << text;
125// //ts << text.latin1();
126// }
127 ts.setEncoding( QTextStream::Latin1 );
128 ts << text;
129 file.close();
130 //qDebug("saving file takes ms: %d ", is.elapsed() );
131 return true;
132}
133
134bool ICalFormat::fromString( Calendar *cal, const QString &text )
135{
136 setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );
137 // qDebug("ICalFormat::fromString tz: %s ", cal->timeZoneId().latin1());
138 // Get first VCALENDAR component.
139 // TODO: Handle more than one VCALENDAR or non-VCALENDAR top components
140 icalcomponent *calendar;
141
142 //calendar = icalcomponent_new_from_string( text.local8Bit().data());
143 // good calendar = icalcomponent_new_from_string( text.utf8().data());
144 calendar = icalcomponent_new_from_string( (char*)text.latin1());
145 if (!calendar) {
146 setException(new ErrorFormat(ErrorFormat::ParseErrorIcal));
147 return false;
148 }
149
150 bool success = true;
151
152 if (icalcomponent_isa(calendar) != ICAL_VCALENDAR_COMPONENT) {
153 setException(new ErrorFormat(ErrorFormat::NoCalendar));
154 success = false;
155 } else {
156 // put all objects into their proper places
157 if ( !mImpl->populate( cal, calendar ) ) {
158 if ( !exception() ) {
159 setException(new ErrorFormat(ErrorFormat::ParseErrorKcal));
160 }
161 success = false;
162 } else
163 mLoadedProductId = mImpl->loadedProductId();
164 }
165
166 icalcomponent_free( calendar );
167
168 return success;
169}
170
171Incidence *ICalFormat::fromString( const QString &text )
172{
173 CalendarLocal cal( mTimeZoneId );
174 fromString(&cal, text);
175
176 Incidence *ical = 0;
177 QPtrList<Event> elist = cal.events();
178 if ( elist.count() > 0 ) {
179 ical = elist.first();
180 } else {
181 QPtrList<Todo> tlist = cal.todos();
182 if ( tlist.count() > 0 ) {
183 ical = tlist.first();
184 } else {
185 QPtrList<Journal> jlist = cal.journals();
186 if ( jlist.count() > 0 ) {
187 ical = jlist.first();
188 }
189 }
190 }
191 return ical;
192}
193#include <qapp.h>
194
195QString ICalFormat::toString( Calendar *cal )
196{
197
198 setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );
199
200 icalcomponent *calendar = mImpl->createCalendarComponent(cal);
201
202 icalcomponent *component;
203
204 // todos
205 QPtrList<Todo> todoList = cal->rawTodos();
206 QPtrListIterator<Todo> qlt(todoList);
207 for (; qlt.current(); ++qlt) {
208 component = mImpl->writeTodo(qlt.current());
209 icalcomponent_add_component(calendar,component);
210 //qDebug(" todos ");
211 qApp->processEvents();
212 }
213 // events
214 QPtrList<Event> events = cal->rawEvents();
215 Event *ev;
216 for(ev=events.first();ev;ev=events.next()) {
217 component = mImpl->writeEvent(ev);
218 icalcomponent_add_component(calendar,component);
219 //qDebug("events ");
220 qApp->processEvents();
221 }
222
223 // journals
224 QPtrList<Journal> journals = cal->journals();
225 Journal *j;
226 for(j=journals.first();j;j=journals.next()) {
227 component = mImpl->writeJournal(j);
228 icalcomponent_add_component(calendar,component);
229 //qDebug("journals ");
230 qApp->processEvents();
231 }
232 const char *text;
233 QString ret ="";
234 text = icalcomponent_as_ical_string( calendar );
235 qApp->processEvents();
236
237 // text = "BEGIN:VCALENDAR\nPRODID\n :-//K Desktop Environment//NONSGML libkcal 3.1//EN\nVERSION\n :2.0\nBEGIN:VEVENT\nDTSTAMP\n :20031231T213514Z\nORGANIZER\n :MAILTO:lutz@putz.de\nCREATED\n :20031231T213513Z\nUID\n :libkcal-1295166342.120\nSEQUENCE\n :0\nLAST-MODIFIED\n :20031231T213513Z\nSUMMARY\n :test1\nCLASS\n :PUBLIC\nPRIORITY\n :3\nDTSTART\n :20040101T090000Z\nDTEND\n :20040101T110000Z\nTRANSP\n :OPAQUE\nEND:VEVENT\nEND:VCALENDAR\n";
238
239
240 if ( text ) {
241 ret = QString ( text );
242 }
243 icalcomponent_free( calendar );
244
245 if (!text) {
246 setException(new ErrorFormat(ErrorFormat::SaveError,
247 i18n("libical error")));
248 return QString::null;
249 }
250
251 return ret;
252}
253
254QString ICalFormat::toICalString( Incidence *incidence )
255{
256 CalendarLocal cal( mTimeZoneId );
257 cal.addIncidence( incidence->clone() );
258 return toString( &cal );
259}
260
261QString ICalFormat::toString( Incidence *incidence )
262{
263 icalcomponent *component;
264
265 component = mImpl->writeIncidence( incidence );
266
267 const char *text = icalcomponent_as_ical_string( component );
268
269 icalcomponent_free( component );
270
271 return QString::fromLocal8Bit( text );
272}
273
274QString ICalFormat::toString( Recurrence *recurrence )
275{
276 icalproperty *property;
277 property = mImpl->writeRecurrenceRule( recurrence );
278 const char *text = icalproperty_as_ical_string( property );
279 icalproperty_free( property );
280 return QString::fromLocal8Bit( text );
281}
282/*
283bool ICalFormat::fromString( Recurrence * recurrence, const QString& rrule )
284{
285 bool success = true;
286 icalerror_clear_errno();
287 struct icalrecurrencetype recur = icalrecurrencetype_from_string( rrule );
288 if ( icalerrno != ICAL_NO_ERROR ) {
289 kdDebug() << "Recurrence parsing error: " << icalerror_strerror( icalerrno ) << endl;
290 success = false;
291 }
292
293 if ( success ) {
294 mImpl->readRecurrence( recur, recurrence );
295 }
296
297 return success;
298}
299*/
300
301QString ICalFormat::createScheduleMessage(IncidenceBase *incidence,
302 Scheduler::Method method)
303{
304 icalcomponent *message = mImpl->createScheduleComponent(incidence,method);
305
306 QString messageText = icalcomponent_as_ical_string(message);
307
308
309
310 return messageText;
311}
312
313ScheduleMessage *ICalFormat::parseScheduleMessage( Calendar *cal,
314 const QString &messageText )
315{
316 setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );
317 clearException();
318
319 if (messageText.isEmpty()) return 0;
320
321 icalcomponent *message;
322 message = icalparser_parse_string(messageText.local8Bit());
323
324 if (!message) return 0;
325
326 icalproperty *m = icalcomponent_get_first_property(message,
327 ICAL_METHOD_PROPERTY);
328
329 if (!m) return 0;
330
331 icalcomponent *c;
332
333 IncidenceBase *incidence = 0;
334 c = icalcomponent_get_first_component(message,ICAL_VEVENT_COMPONENT);
335 if (c) {
336 incidence = mImpl->readEvent(c);
337 }
338
339 if (!incidence) {
340 c = icalcomponent_get_first_component(message,ICAL_VTODO_COMPONENT);
341 if (c) {
342 incidence = mImpl->readTodo(c);
343 }
344 }
345
346 if (!incidence) {
347 c = icalcomponent_get_first_component(message,ICAL_VFREEBUSY_COMPONENT);
348 if (c) {
349 incidence = mImpl->readFreeBusy(c);
350 }
351 }
352
353 if (!incidence) {
354 kdDebug() << "ICalFormat:parseScheduleMessage: object is not a freebusy, event or todo" << endl;
355 return 0;
356 }
357
358 kdDebug(5800) << "ICalFormat::parseScheduleMessage() getting method..." << endl;
359
360 icalproperty_method icalmethod = icalproperty_get_method(m);
361 Scheduler::Method method;
362
363 switch (icalmethod) {
364 case ICAL_METHOD_PUBLISH:
365 method = Scheduler::Publish;
366 break;
367 case ICAL_METHOD_REQUEST:
368 method = Scheduler::Request;
369 break;
370 case ICAL_METHOD_REFRESH:
371 method = Scheduler::Refresh;
372 break;
373 case ICAL_METHOD_CANCEL:
374 method = Scheduler::Cancel;
375 break;
376 case ICAL_METHOD_ADD:
377 method = Scheduler::Add;
378 break;
379 case ICAL_METHOD_REPLY:
380 method = Scheduler::Reply;
381 break;
382 case ICAL_METHOD_COUNTER:
383 method = Scheduler::Counter;
384 break;
385 case ICAL_METHOD_DECLINECOUNTER:
386 method = Scheduler::Declinecounter;
387 break;
388 default:
389 method = Scheduler::NoMethod;
390 kdDebug(5800) << "ICalFormat::parseScheduleMessage(): Unknow method" << endl;
391 break;
392 }
393
394
395 if (!icalrestriction_check(message)) {
396 setException(new ErrorFormat(ErrorFormat::Restriction,
397 Scheduler::translatedMethodName(method) + ": " +
398 mImpl->extractErrorProperty(c)));
399 return 0;
400 }
401
402 icalcomponent *calendarComponent = mImpl->createCalendarComponent(cal);
403
404 Incidence *existingIncidence = cal->event(incidence->uid());
405 if (existingIncidence) {
406 // TODO: check, if cast is required, or if it can be done by virtual funcs.
407 if (existingIncidence->type() == "Todo") {
408 Todo *todo = static_cast<Todo *>(existingIncidence);
409 icalcomponent_add_component(calendarComponent,
410 mImpl->writeTodo(todo));
411 }
412 if (existingIncidence->type() == "Event") {
413 Event *event = static_cast<Event *>(existingIncidence);
414 icalcomponent_add_component(calendarComponent,
415 mImpl->writeEvent(event));
416 }
417 } else {
418 calendarComponent = 0;
419 }
420
421
422 icalclass result = icalclassify(message,calendarComponent,(char *)"");
423
424
425 ScheduleMessage::Status status;
426
427 switch (result) {
428 case ICAL_PUBLISH_NEW_CLASS:
429 status = ScheduleMessage::PublishNew;
430 break;
431 case ICAL_OBSOLETE_CLASS:
432 status = ScheduleMessage::Obsolete;
433 break;
434 case ICAL_REQUEST_NEW_CLASS:
435 status = ScheduleMessage::RequestNew;
436 break;
437 case ICAL_REQUEST_UPDATE_CLASS:
438 status = ScheduleMessage::RequestUpdate;
439 break;
440 case ICAL_UNKNOWN_CLASS:
441 default:
442 status = ScheduleMessage::Unknown;
443 break;
444 }
445
446 return new ScheduleMessage(incidence,method,status);
447}
448
449void ICalFormat::setTimeZone( const QString &id, bool utc )
450{
451
452
453 mTimeZoneId = id;
454 mUtc = utc;
455
456 tzOffsetMin = KGlobal::locale()->timezoneOffset(mTimeZoneId);
457
458 //qDebug("ICalFormat::setTimeZoneOffset %s %d ",mTimeZoneId.latin1(), tzOffsetMin);
459}
460
461QString ICalFormat::timeZoneId() const
462{
463 return mTimeZoneId;
464}
465
466bool ICalFormat::utc() const
467{
468 return mUtc;
469}
470int ICalFormat::timeOffset()
471{
472 return tzOffsetMin;
473}
474const char *ICalFormat::tzString()
475{
476 const char* ret = (const char* ) mTzString;
477 return ret;
478}
diff --git a/libkcal/icalformat.h b/libkcal/icalformat.h
new file mode 100644
index 0000000..236efbf
--- a/dev/null
+++ b/libkcal/icalformat.h
@@ -0,0 +1,116 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef ICALFORMAT_H
21#define ICALFORMAT_H
22
23#include <qstring.h>
24
25#include "scheduler.h"
26
27#include "calformat.h"
28
29namespace KCal {
30
31class ICalFormatImpl;
32
33/**
34 This class implements the iCalendar format. It provides methods for
35 loading/saving/converting iCalendar format data into the internal KOrganizer
36 representation as Calendar and Events.
37
38 @short iCalendar format implementation
39*/
40class ICalFormat : public CalFormat {
41 public:
42 /** Create new iCalendar format. */
43 ICalFormat( bool quick = false );
44 virtual ~ICalFormat();
45
46 /**
47 Loads a calendar on disk in iCalendar format into calendar.
48 Returns true if successful, else returns false. Provides more error
49 information by exception().
50 @param calendar Calendar object to be filled.
51 @param fileName The name of the calendar file on disk.
52 */
53 bool load( Calendar *, const QString &fileName );
54 /**
55 Writes out the calendar to disk in iCalendar format. Returns true if
56 successful and false on error.
57
58 @param calendar The Calendar object to be written.
59 @param fileName The name of the calendar file on disk.
60 */
61 bool save( Calendar *, const QString &fileName );
62
63 /**
64 Parse string and populate calendar with that information.
65 */
66 bool fromString( Calendar *, const QString & );
67 /**
68 Parse string and return first ical component.
69 */
70 Incidence *fromString( const QString & );
71 /**
72 Return calendar information as string.
73 */
74 QString toString( Calendar * );
75 /**
76 Return incidence as full iCalendar formatted text.
77 */
78 QString toICalString( Incidence * );
79 /**
80 Return incidence as iCalendar formatted text.
81 */
82 QString toString( Incidence * );
83 /**
84 Return recurrence as iCalendar formatted text.
85 */
86 QString toString( Recurrence * );
87 /**
88 Parse string and fill recurrence object with
89 that information
90 */
91 //bool fromString ( Recurrence *, const QString& );
92
93 /** Create a scheduling message for event \a e using method \m */
94 QString createScheduleMessage(IncidenceBase *e,Scheduler::Method m);
95 /** Parse scheduling message provided as string \s */
96 ScheduleMessage *parseScheduleMessage( Calendar *, const QString &s);
97
98 /** Set id of used time zone and whether this time zone is UTC or not. */
99 void setTimeZone( const QString &id, bool utc );
100 QString timeZoneId() const;
101 int timeOffset();
102 const char * tzString();
103 bool utc() const;
104
105 private:
106 ICalFormatImpl *mImpl;
107 bool mQuicksave;
108 QString mTimeZoneId;
109 QCString mTzString;
110 int tzOffsetMin;
111 bool mUtc;
112};
113
114}
115
116#endif
diff --git a/libkcal/icalformatimpl.cpp b/libkcal/icalformatimpl.cpp
new file mode 100644
index 0000000..e5c27a0
--- a/dev/null
+++ b/libkcal/icalformatimpl.cpp
@@ -0,0 +1,2173 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <qdatetime.h>
22#include <qstring.h>
23#include <qptrlist.h>
24#include <qfile.h>
25
26#include <kdebug.h>
27#include <klocale.h>
28#include <kglobal.h>
29
30extern "C" {
31 #include <ical.h>
32 #include <icalss.h>
33 #include <icalparser.h>
34 #include <icalrestriction.h>
35}
36
37#include "calendar.h"
38#include "journal.h"
39#include "icalformat.h"
40#include "icalformatimpl.h"
41#include "compat.h"
42
43#define _ICAL_VERSION "2.0"
44
45using namespace KCal;
46
47const int gSecondsPerMinute = 60;
48const int gSecondsPerHour = gSecondsPerMinute * 60;
49const int gSecondsPerDay = gSecondsPerHour * 24;
50const int gSecondsPerWeek = gSecondsPerDay * 7;
51
52ICalFormatImpl::ICalFormatImpl( ICalFormat *parent ) :
53 mParent( parent ), mCalendarVersion( 0 )
54{
55 mCompat = new Compat;
56}
57
58ICalFormatImpl::~ICalFormatImpl()
59{
60 delete mCompat;
61}
62
63class ToStringVisitor : public Incidence::Visitor
64{
65 public:
66 ToStringVisitor( ICalFormatImpl *impl ) : mImpl( impl ), mComponent( 0 ) {}
67
68 bool visit( Event *e ) { mComponent = mImpl->writeEvent( e ); return true; }
69 bool visit( Todo *e ) { mComponent = mImpl->writeTodo( e ); return true; }
70 bool visit( Journal *e ) { mComponent = mImpl->writeJournal( e ); return true; }
71
72 icalcomponent *component() { return mComponent; }
73
74 private:
75 ICalFormatImpl *mImpl;
76 icalcomponent *mComponent;
77};
78
79icalcomponent *ICalFormatImpl::writeIncidence(Incidence *incidence)
80{
81 ToStringVisitor v( this );
82 incidence->accept(v);
83 return v.component();
84}
85
86icalcomponent *ICalFormatImpl::writeTodo(Todo *todo)
87{
88 QString tmpStr;
89 QStringList tmpStrList;
90
91 icalcomponent *vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT);
92
93 writeIncidence(vtodo,todo);
94
95 // due date
96 if (todo->hasDueDate()) {
97 icaltimetype due;
98 if (todo->doesFloat()) {
99 due = writeICalDate(todo->dtDue().date());
100 } else {
101 due = writeICalDateTime(todo->dtDue());
102 }
103 icalcomponent_add_property(vtodo,icalproperty_new_due(due));
104 }
105
106 // start time
107 if (todo->hasStartDate()) {
108 icaltimetype start;
109 if (todo->doesFloat()) {
110// kdDebug(5800) << "§§ Incidence " << todo->summary() << " floats." << endl;
111 start = writeICalDate(todo->dtStart().date());
112 } else {
113// kdDebug(5800) << "§§ incidence " << todo->summary() << " has time." << endl;
114 start = writeICalDateTime(todo->dtStart());
115 }
116 icalcomponent_add_property(vtodo,icalproperty_new_dtstart(start));
117 }
118
119 // completion date
120 if (todo->isCompleted()) {
121 if (!todo->hasCompletedDate()) {
122 // If todo was created by KOrganizer <2.2 it has no correct completion
123 // date. Set it to now.
124 todo->setCompleted(QDateTime::currentDateTime());
125 }
126 icaltimetype completed = writeICalDateTime(todo->completed());
127 icalcomponent_add_property(vtodo,icalproperty_new_completed(completed));
128 }
129
130 icalcomponent_add_property(vtodo,
131 icalproperty_new_percentcomplete(todo->percentComplete()));
132
133 return vtodo;
134}
135
136icalcomponent *ICalFormatImpl::writeEvent(Event *event)
137{
138 kdDebug(5800) << "Write Event '" << event->summary() << "' (" << event->uid()
139 << ")" << endl;
140
141 QString tmpStr;
142 QStringList tmpStrList;
143
144 icalcomponent *vevent = icalcomponent_new(ICAL_VEVENT_COMPONENT);
145
146 writeIncidence(vevent,event);
147
148 // start time
149 icaltimetype start;
150 if (event->doesFloat()) {
151// kdDebug(5800) << "§§ Incidence " << event->summary() << " floats." << endl;
152 start = writeICalDate(event->dtStart().date());
153 } else {
154// kdDebug(5800) << "§§ incidence " << event->summary() << " has time." << endl;
155 start = writeICalDateTime(event->dtStart());
156 }
157 icalcomponent_add_property(vevent,icalproperty_new_dtstart(start));
158
159 if (event->hasEndDate()) {
160 // end time
161 icaltimetype end;
162 if (event->doesFloat()) {
163// kdDebug(5800) << "§§ Event " << event->summary() << " floats." << endl;
164 // +1 day because end date is non-inclusive.
165 end = writeICalDate( event->dtEnd().date().addDays( 1 ) );
166 } else {
167// kdDebug(5800) << "§§ Event " << event->summary() << " has time." << endl;
168 end = writeICalDateTime(event->dtEnd());
169 }
170 icalcomponent_add_property(vevent,icalproperty_new_dtend(end));
171 }
172
173// TODO: attachments, resources
174#if 0
175 // attachments
176 tmpStrList = anEvent->attachments();
177 for ( QStringList::Iterator it = tmpStrList.begin();
178 it != tmpStrList.end();
179 ++it )
180 addPropValue(vevent, VCAttachProp, (*it).utf8());
181
182 // resources
183 tmpStrList = anEvent->resources();
184 tmpStr = tmpStrList.join(";");
185 if (!tmpStr.isEmpty())
186 addPropValue(vevent, VCResourcesProp, tmpStr.utf8());
187
188#endif
189
190 // Transparency
191 switch( event->transparency() ) {
192 case Event::Transparent:
193 icalcomponent_add_property(vevent, icalproperty_new_transp("TRANSPARENT"));
194 break;
195 case Event::Opaque:
196 icalcomponent_add_property(vevent, icalproperty_new_transp("OPAQUE"));
197 break;
198 }
199
200 return vevent;
201}
202
203icalcomponent *ICalFormatImpl::writeFreeBusy(FreeBusy *freebusy,
204 Scheduler::Method method)
205{
206#if QT_VERSION >= 300
207 kdDebug(5800) << "icalformatimpl: writeFreeBusy: startDate: "
208 << freebusy->dtStart().toString("ddd MMMM d yyyy: h:m:s ap") << " End Date: "
209 << freebusy->dtEnd().toString("ddd MMMM d yyyy: h:m:s ap") << endl;
210#endif
211
212 icalcomponent *vfreebusy = icalcomponent_new(ICAL_VFREEBUSY_COMPONENT);
213
214 writeIncidenceBase(vfreebusy,freebusy);
215
216 icalcomponent_add_property(vfreebusy, icalproperty_new_dtstart(
217 writeICalDateTime(freebusy->dtStart())));
218
219 icalcomponent_add_property(vfreebusy, icalproperty_new_dtend(
220 writeICalDateTime(freebusy->dtEnd())));
221
222 if (method == Scheduler::Request) {
223 icalcomponent_add_property(vfreebusy,icalproperty_new_uid(
224 freebusy->uid().utf8()));
225 }
226
227 //Loops through all the periods in the freebusy object
228 QValueList<Period> list = freebusy->busyPeriods();
229 QValueList<Period>::Iterator it;
230 icalperiodtype period;
231 for (it = list.begin(); it!= list.end(); ++it) {
232 period.start = writeICalDateTime((*it).start());
233 period.end = writeICalDateTime((*it).end());
234 icalcomponent_add_property(vfreebusy, icalproperty_new_freebusy(period) );
235 }
236
237 return vfreebusy;
238}
239
240icalcomponent *ICalFormatImpl::writeJournal(Journal *journal)
241{
242 icalcomponent *vjournal = icalcomponent_new(ICAL_VJOURNAL_COMPONENT);
243
244 writeIncidence(vjournal,journal);
245
246 // start time
247 if (journal->dtStart().isValid()) {
248 icaltimetype start;
249 if (journal->doesFloat()) {
250// kdDebug(5800) << "§§ Incidence " << event->summary() << " floats." << endl;
251 start = writeICalDate(journal->dtStart().date());
252 } else {
253// kdDebug(5800) << "§§ incidence " << event->summary() << " has time." << endl;
254 start = writeICalDateTime(journal->dtStart());
255 }
256 icalcomponent_add_property(vjournal,icalproperty_new_dtstart(start));
257 }
258
259 return vjournal;
260}
261
262void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence)
263{
264 // pilot sync stuff
265// TODO: move this application-specific code to kpilot
266 if (incidence->pilotId()) {
267 incidence->setNonKDECustomProperty("X-PILOTID", QString::number(incidence->pilotId()));
268 incidence->setNonKDECustomProperty("X-PILOTSTAT", QString::number(incidence->syncStatus()));
269 }
270 if (incidence->zaurusId() >= 0) {
271 incidence->setNonKDECustomProperty("X-ZAURUSID", QString::number(incidence->zaurusId()));
272 }
273
274 if (incidence->zaurusUid() > 0) {
275 incidence->setNonKDECustomProperty("X-ZAURUSUID", QString::number(incidence->zaurusUid()));
276 }
277 if (incidence->zaurusStat() > 0) {
278 incidence->setNonKDECustomProperty("X-ZAURUSSTAT", QString::number(incidence->zaurusStat()));
279 }
280
281 writeIncidenceBase(parent,incidence);
282 if (incidence->cancelled()) {
283 icalcomponent_add_property(parent,icalproperty_new_status(ICAL_STATUS_CANCELLED));
284 }
285
286 // creation date
287 icalcomponent_add_property(parent,icalproperty_new_created(
288 writeICalDateTime(incidence->created())));
289
290 // unique id
291 icalcomponent_add_property(parent,icalproperty_new_uid(
292 incidence->uid().utf8()));
293
294 // revision
295 icalcomponent_add_property(parent,icalproperty_new_sequence(
296 incidence->revision()));
297
298 // last modification date
299 icalcomponent_add_property(parent,icalproperty_new_lastmodified(
300 writeICalDateTime(incidence->lastModified())));
301
302 // description
303 if (!incidence->description().isEmpty()) {
304 icalcomponent_add_property(parent,icalproperty_new_description(
305 incidence->description().utf8()));
306 }
307
308 // summary
309 if (!incidence->summary().isEmpty()) {
310 icalcomponent_add_property(parent,icalproperty_new_summary(
311 incidence->summary().utf8()));
312 }
313
314 // location
315 if (!incidence->location().isEmpty()) {
316 icalcomponent_add_property(parent,icalproperty_new_location(
317 incidence->location().utf8()));
318 }
319
320// TODO:
321 // status
322// addPropValue(parent, VCStatusProp, incidence->getStatusStr().utf8());
323
324 // secrecy
325 const char *classStr;
326 switch (incidence->secrecy()) {
327 case Incidence::SecrecyPublic:
328 classStr = "PUBLIC";
329 break;
330 case Incidence::SecrecyConfidential:
331 classStr = "CONFIDENTIAL";
332 break;
333 case Incidence::SecrecyPrivate:
334 default:
335 classStr = "PRIVATE";
336 break;
337 }
338 icalcomponent_add_property(parent,icalproperty_new_class(classStr));
339
340 // priority
341 icalcomponent_add_property(parent,icalproperty_new_priority(
342 incidence->priority()));
343
344 // categories
345 QStringList categories = incidence->categories();
346 QStringList::Iterator it;
347 for(it = categories.begin(); it != categories.end(); ++it ) {
348 icalcomponent_add_property(parent,icalproperty_new_categories((*it).utf8()));
349 }
350// TODO: Ensure correct concatenation of categories properties.
351
352/*
353 // categories
354 tmpStrList = incidence->getCategories();
355 tmpStr = "";
356 QString catStr;
357 for ( QStringList::Iterator it = tmpStrList.begin();
358 it != tmpStrList.end();
359 ++it ) {
360 catStr = *it;
361 if (catStr[0] == ' ')
362 tmpStr += catStr.mid(1);
363 else
364 tmpStr += catStr;
365 // this must be a ';' character as the vCalendar specification requires!
366 // vcc.y has been hacked to translate the ';' to a ',' when the vcal is
367 // read in.
368 tmpStr += ";";
369 }
370 if (!tmpStr.isEmpty()) {
371 tmpStr.truncate(tmpStr.length()-1);
372 icalcomponent_add_property(parent,icalproperty_new_categories(
373 writeText(incidence->getCategories().join(";"))));
374 }
375*/
376
377 // related event
378 if (incidence->relatedTo()) {
379 icalcomponent_add_property(parent,icalproperty_new_relatedto(
380 incidence->relatedTo()->uid().utf8()));
381 }
382
383 // recurrence rule stuff
384 Recurrence *recur = incidence->recurrence();
385 if (recur->doesRecur()) {
386
387 icalcomponent_add_property(parent,writeRecurrenceRule(recur));
388 }
389
390 // recurrence excpetion dates
391 DateList dateList = incidence->exDates();
392 DateList::ConstIterator exIt;
393 for(exIt = dateList.begin(); exIt != dateList.end(); ++exIt) {
394 icalcomponent_add_property(parent,icalproperty_new_exdate(
395 writeICalDate(*exIt)));
396 }
397
398 // attachments
399 QPtrList<Attachment> attachments = incidence->attachments();
400 for (Attachment *at = attachments.first(); at; at = attachments.next())
401 icalcomponent_add_property(parent,writeAttachment(at));
402
403 // alarms
404 QPtrList<Alarm> alarms = incidence->alarms();
405 Alarm* alarm;
406 for (alarm = alarms.first(); alarm; alarm = alarms.next()) {
407 if (alarm->enabled()) {
408 kdDebug(5800) << "Write alarm for " << incidence->summary() << endl;
409 icalcomponent_add_component(parent,writeAlarm(alarm));
410 }
411 }
412
413 // duration
414
415// turned off as it always is set to PTS0 (and must not occur together with DTEND
416
417// if (incidence->hasDuration()) {
418// icaldurationtype duration;
419// duration = writeICalDuration(incidence->duration());
420// icalcomponent_add_property(parent,icalproperty_new_duration(duration));
421// }
422}
423
424void ICalFormatImpl::writeIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase)
425{
426 icalcomponent_add_property(parent,icalproperty_new_dtstamp(
427 writeICalDateTime(QDateTime::currentDateTime())));
428
429 // organizer stuff
430 icalcomponent_add_property(parent,icalproperty_new_organizer(
431 ("MAILTO:" + incidenceBase->organizer()).utf8()));
432
433 // attendees
434 if (incidenceBase->attendeeCount() != 0) {
435 QPtrList<Attendee> al = incidenceBase->attendees();
436 QPtrListIterator<Attendee> ai(al);
437 for (; ai.current(); ++ai) {
438 icalcomponent_add_property(parent,writeAttendee(ai.current()));
439 }
440 }
441
442 // custom properties
443 writeCustomProperties(parent, incidenceBase);
444}
445
446void ICalFormatImpl::writeCustomProperties(icalcomponent *parent,CustomProperties *properties)
447{
448 QMap<QCString, QString> custom = properties->customProperties();
449 for (QMap<QCString, QString>::Iterator c = custom.begin(); c != custom.end(); ++c) {
450 icalproperty *p = icalproperty_new_x(c.data().utf8());
451 icalproperty_set_x_name(p,c.key());
452 icalcomponent_add_property(parent,p);
453 }
454}
455
456icalproperty *ICalFormatImpl::writeAttendee(Attendee *attendee)
457{
458 icalproperty *p = icalproperty_new_attendee("mailto:" + attendee->email().utf8());
459
460 if (!attendee->name().isEmpty()) {
461 icalproperty_add_parameter(p,icalparameter_new_cn(attendee->name().utf8()));
462 }
463
464
465 icalproperty_add_parameter(p,icalparameter_new_rsvp(
466 attendee->RSVP() ? ICAL_RSVP_TRUE : ICAL_RSVP_FALSE ));
467
468 icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION;
469 switch (attendee->status()) {
470 default:
471 case Attendee::NeedsAction:
472 status = ICAL_PARTSTAT_NEEDSACTION;
473 break;
474 case Attendee::Accepted:
475 status = ICAL_PARTSTAT_ACCEPTED;
476 break;
477 case Attendee::Declined:
478 status = ICAL_PARTSTAT_DECLINED;
479 break;
480 case Attendee::Tentative:
481 status = ICAL_PARTSTAT_TENTATIVE;
482 break;
483 case Attendee::Delegated:
484 status = ICAL_PARTSTAT_DELEGATED;
485 break;
486 case Attendee::Completed:
487 status = ICAL_PARTSTAT_COMPLETED;
488 break;
489 case Attendee::InProcess:
490 status = ICAL_PARTSTAT_INPROCESS;
491 break;
492 }
493 icalproperty_add_parameter(p,icalparameter_new_partstat(status));
494
495 icalparameter_role role = ICAL_ROLE_REQPARTICIPANT;
496 switch (attendee->role()) {
497 case Attendee::Chair:
498 role = ICAL_ROLE_CHAIR;
499 break;
500 default:
501 case Attendee::ReqParticipant:
502 role = ICAL_ROLE_REQPARTICIPANT;
503 break;
504 case Attendee::OptParticipant:
505 role = ICAL_ROLE_OPTPARTICIPANT;
506 break;
507 case Attendee::NonParticipant:
508 role = ICAL_ROLE_NONPARTICIPANT;
509 break;
510 }
511 icalproperty_add_parameter(p,icalparameter_new_role(role));
512
513 if (!attendee->uid().isEmpty()) {
514 icalparameter* icalparameter_uid = icalparameter_new_x(attendee->uid().utf8());
515 icalparameter_set_xname(icalparameter_uid,"X-UID");
516 icalproperty_add_parameter(p,icalparameter_uid);
517 }
518
519 return p;
520}
521
522icalproperty *ICalFormatImpl::writeAttachment(Attachment *att)
523{
524 icalattachtype* attach = icalattachtype_new();
525 if (att->isURI())
526 icalattachtype_set_url(attach, att->uri().utf8().data());
527 else
528 icalattachtype_set_base64(attach, att->data(), 0);
529
530 icalproperty *p = icalproperty_new_attach(attach);
531
532 if (!att->mimeType().isEmpty())
533 icalproperty_add_parameter(p,icalparameter_new_fmttype(att->mimeType().utf8().data()));
534
535 if (att->isBinary()) {
536 icalproperty_add_parameter(p,icalparameter_new_value(ICAL_VALUE_BINARY));
537 icalproperty_add_parameter(p,icalparameter_new_encoding(ICAL_ENCODING_BASE64));
538 }
539 return p;
540}
541
542icalproperty *ICalFormatImpl::writeRecurrenceRule(Recurrence *recur)
543{
544// kdDebug(5800) << "ICalFormatImpl::writeRecurrenceRule()" << endl;
545
546 icalrecurrencetype r;
547
548 icalrecurrencetype_clear(&r);
549
550 int index = 0;
551 int index2 = 0;
552
553 QPtrList<Recurrence::rMonthPos> tmpPositions;
554 QPtrList<int> tmpDays;
555 int *tmpDay;
556 Recurrence::rMonthPos *tmpPos;
557 bool datetime = false;
558 int day;
559 int i;
560
561 switch(recur->doesRecur()) {
562 case Recurrence::rMinutely:
563 r.freq = ICAL_MINUTELY_RECURRENCE;
564 datetime = true;
565 break;
566 case Recurrence::rHourly:
567 r.freq = ICAL_HOURLY_RECURRENCE;
568 datetime = true;
569 break;
570 case Recurrence::rDaily:
571 r.freq = ICAL_DAILY_RECURRENCE;
572 break;
573 case Recurrence::rWeekly:
574 r.freq = ICAL_WEEKLY_RECURRENCE;
575 r.week_start = static_cast<icalrecurrencetype_weekday>(recur->weekStart()%7 + 1);
576 for (i = 0; i < 7; i++) {
577 if (recur->days().testBit(i)) {
578 day = (i + 1)%7 + 1; // convert from Monday=0 to Sunday=1
579 r.by_day[index++] = icalrecurrencetype_day_day_of_week(day);
580 }
581 }
582// r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
583 break;
584 case Recurrence::rMonthlyPos:
585 r.freq = ICAL_MONTHLY_RECURRENCE;
586
587 tmpPositions = recur->monthPositions();
588 for (tmpPos = tmpPositions.first();
589 tmpPos;
590 tmpPos = tmpPositions.next()) {
591 for (i = 0; i < 7; i++) {
592 if (tmpPos->rDays.testBit(i)) {
593 day = (i + 1)%7 + 1; // convert from Monday=0 to Sunday=1
594 day += tmpPos->rPos*8;
595 if (tmpPos->negative) day = -day;
596 r.by_day[index++] = day;
597 }
598 }
599 }
600// r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
601 break;
602 case Recurrence::rMonthlyDay:
603 r.freq = ICAL_MONTHLY_RECURRENCE;
604
605 tmpDays = recur->monthDays();
606 for (tmpDay = tmpDays.first();
607 tmpDay;
608 tmpDay = tmpDays.next()) {
609 r.by_month_day[index++] = icalrecurrencetype_day_position(*tmpDay*8);//*tmpDay);
610 }
611// r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
612 break;
613 case Recurrence::rYearlyMonth:
614 case Recurrence::rYearlyPos:
615 r.freq = ICAL_YEARLY_RECURRENCE;
616
617 tmpDays = recur->yearNums();
618 for (tmpDay = tmpDays.first();
619 tmpDay;
620 tmpDay = tmpDays.next()) {
621 r.by_month[index++] = *tmpDay;
622 }
623// r.by_set_pos[index] = ICAL_RECURRENCE_ARRAY_MAX;
624 if (recur->doesRecur() == Recurrence::rYearlyPos) {
625 tmpPositions = recur->monthPositions();
626 for (tmpPos = tmpPositions.first();
627 tmpPos;
628 tmpPos = tmpPositions.next()) {
629 for (i = 0; i < 7; i++) {
630 if (tmpPos->rDays.testBit(i)) {
631 day = (i + 1)%7 + 1; // convert from Monday=0 to Sunday=1
632 day += tmpPos->rPos*8;
633 if (tmpPos->negative) day = -day;
634 r.by_day[index2++] = day;
635 }
636 }
637 }
638// r.by_day[index2] = ICAL_RECURRENCE_ARRAY_MAX;
639 }
640 break;
641 case Recurrence::rYearlyDay:
642 r.freq = ICAL_YEARLY_RECURRENCE;
643
644 tmpDays = recur->yearNums();
645 for (tmpDay = tmpDays.first();
646 tmpDay;
647 tmpDay = tmpDays.next()) {
648 r.by_year_day[index++] = *tmpDay;
649 }
650// r.by_year_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
651 break;
652 default:
653 r.freq = ICAL_NO_RECURRENCE;
654 kdDebug(5800) << "ICalFormatImpl::writeRecurrence(): no recurrence" << endl;
655 break;
656 }
657
658 r.interval = recur->frequency();
659
660 if (recur->duration() > 0) {
661 r.count = recur->duration();
662 } else if (recur->duration() == -1) {
663 r.count = 0;
664 } else {
665 if (datetime)
666 r.until = writeICalDateTime(recur->endDateTime());
667 else
668 r.until = writeICalDate(recur->endDate());
669 }
670
671// Debug output
672#if 0
673 const char *str = icalrecurrencetype_as_string(&r);
674 if (str) {
675 kdDebug(5800) << " String: " << str << endl;
676 } else {
677 kdDebug(5800) << " No String" << endl;
678 }
679#endif
680
681 return icalproperty_new_rrule(r);
682}
683
684icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm)
685{
686 icalcomponent *a = icalcomponent_new(ICAL_VALARM_COMPONENT);
687
688 icalproperty_action action;
689 icalattachtype *attach = 0;
690
691 switch (alarm->type()) {
692 case Alarm::Procedure:
693 action = ICAL_ACTION_PROCEDURE;
694 attach = icalattachtype_new();
695 icalattachtype_set_url(attach,QFile::encodeName(alarm->programFile()).data());
696 icalcomponent_add_property(a,icalproperty_new_attach(attach));
697 icalattachtype_free(attach);
698 if (!alarm->programArguments().isEmpty()) {
699 icalcomponent_add_property(a,icalproperty_new_description(alarm->programArguments().utf8()));
700 }
701 break;
702 case Alarm::Audio:
703 action = ICAL_ACTION_AUDIO;
704 if (!alarm->audioFile().isEmpty()) {
705 attach = icalattachtype_new();
706 icalattachtype_set_url(attach,QFile::encodeName( alarm->audioFile() ).data());
707 icalcomponent_add_property(a,icalproperty_new_attach(attach));
708 icalattachtype_free(attach);
709 }
710 break;
711 case Alarm::Email: {
712 action = ICAL_ACTION_EMAIL;
713 QValueList<Person> addresses = alarm->mailAddresses();
714 for (QValueList<Person>::Iterator ad = addresses.begin(); ad != addresses.end(); ++ad) {
715 icalproperty *p = icalproperty_new_attendee("MAILTO:" + (*ad).email().utf8());
716 if (!(*ad).name().isEmpty()) {
717 icalproperty_add_parameter(p,icalparameter_new_cn((*ad).name().utf8()));
718 }
719 icalcomponent_add_property(a,p);
720 }
721 icalcomponent_add_property(a,icalproperty_new_summary(alarm->mailSubject().utf8()));
722 icalcomponent_add_property(a,icalproperty_new_description(alarm->text().utf8()));
723 QStringList attachments = alarm->mailAttachments();
724 if (attachments.count() > 0) {
725 for (QStringList::Iterator at = attachments.begin(); at != attachments.end(); ++at) {
726 attach = icalattachtype_new();
727 icalattachtype_set_url(attach,QFile::encodeName( *at ).data());
728 icalcomponent_add_property(a,icalproperty_new_attach(attach));
729 icalattachtype_free(attach);
730 }
731 }
732 break;
733 }
734 case Alarm::Display:
735 action = ICAL_ACTION_DISPLAY;
736 icalcomponent_add_property(a,icalproperty_new_description(alarm->text().utf8()));
737 break;
738 case Alarm::Invalid:
739 default:
740 kdDebug(5800) << "Unknown type of alarm" << endl;
741 action = ICAL_ACTION_NONE;
742 break;
743 }
744 icalcomponent_add_property(a,icalproperty_new_action(action));
745
746 // Trigger time
747 icaltriggertype trigger;
748 if ( alarm->hasTime() ) {
749 trigger.time = writeICalDateTime(alarm->time());
750 trigger.duration = icaldurationtype_null_duration();
751 } else {
752 trigger.time = icaltime_null_time();
753 Duration offset;
754 if ( alarm->hasStartOffset() )
755 offset = alarm->startOffset();
756 else
757 offset = alarm->endOffset();
758 trigger.duration = icaldurationtype_from_int( offset.asSeconds() );
759 }
760 icalproperty *p = icalproperty_new_trigger(trigger);
761 if ( alarm->hasEndOffset() )
762 icalproperty_add_parameter(p,icalparameter_new_related(ICAL_RELATED_END));
763 icalcomponent_add_property(a,p);
764
765 // Repeat count and duration
766 if (alarm->repeatCount()) {
767 icalcomponent_add_property(a,icalproperty_new_repeat(alarm->repeatCount()));
768 icalcomponent_add_property(a,icalproperty_new_duration(
769 icaldurationtype_from_int(alarm->snoozeTime()*60)));
770 }
771
772 // Custom properties
773 QMap<QCString, QString> custom = alarm->customProperties();
774 for (QMap<QCString, QString>::Iterator c = custom.begin(); c != custom.end(); ++c) {
775 icalproperty *p = icalproperty_new_x(c.data().utf8());
776 icalproperty_set_x_name(p,c.key());
777 icalcomponent_add_property(a,p);
778 }
779
780 return a;
781}
782
783Todo *ICalFormatImpl::readTodo(icalcomponent *vtodo)
784{
785 Todo *todo = new Todo;
786
787 readIncidence(vtodo,todo);
788
789 icalproperty *p = icalcomponent_get_first_property(vtodo,ICAL_ANY_PROPERTY);
790
791// int intvalue;
792 icaltimetype icaltime;
793
794 QStringList categories;
795
796 while (p) {
797 icalproperty_kind kind = icalproperty_isa(p);
798 switch (kind) {
799
800 case ICAL_DUE_PROPERTY: // due date
801 icaltime = icalproperty_get_due(p);
802 if (icaltime.is_date) {
803 todo->setDtDue(QDateTime(readICalDate(icaltime),QTime(0,0,0)));
804 todo->setFloats(true);
805
806 } else {
807 todo->setDtDue(readICalDateTime(icaltime));
808 todo->setFloats(false);
809 }
810 todo->setHasDueDate(true);
811 break;
812
813 case ICAL_COMPLETED_PROPERTY: // completion date
814 icaltime = icalproperty_get_completed(p);
815 todo->setCompleted(readICalDateTime(icaltime));
816 break;
817
818 case ICAL_PERCENTCOMPLETE_PROPERTY: // Percent completed
819 todo->setPercentComplete(icalproperty_get_percentcomplete(p));
820 break;
821
822 case ICAL_RELATEDTO_PROPERTY: // related todo (parent)
823 todo->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p)));
824 mTodosRelate.append(todo);
825 break;
826
827 case ICAL_DTSTART_PROPERTY:
828 // Flag that todo has start date. Value is read in by readIncidence().
829 todo->setHasStartDate(true);
830 break;
831
832 default:
833// kdDebug(5800) << "ICALFormat::readTodo(): Unknown property: " << kind
834// << endl;
835 break;
836 }
837
838 p = icalcomponent_get_next_property(vtodo,ICAL_ANY_PROPERTY);
839 }
840
841 return todo;
842}
843
844Event *ICalFormatImpl::readEvent(icalcomponent *vevent)
845{
846 Event *event = new Event;
847 event->setFloats(false);
848
849 readIncidence(vevent,event);
850
851 icalproperty *p = icalcomponent_get_first_property(vevent,ICAL_ANY_PROPERTY);
852
853// int intvalue;
854 icaltimetype icaltime;
855
856 QStringList categories;
857 QString transparency;
858
859 while (p) {
860 icalproperty_kind kind = icalproperty_isa(p);
861 switch (kind) {
862
863 case ICAL_DTEND_PROPERTY: // start date and time
864 icaltime = icalproperty_get_dtend(p);
865 if (icaltime.is_date) {
866 event->setFloats( true );
867 // End date is non-inclusive
868 QDate endDate = readICalDate( icaltime ).addDays( -1 );
869 mCompat->fixFloatingEnd( endDate );
870 if ( endDate < event->dtStart().date() ) {
871 endDate = event->dtStart().date();
872 }
873 event->setDtEnd( QDateTime( endDate, QTime( 0, 0, 0 ) ) );
874 } else {
875 event->setDtEnd(readICalDateTime(icaltime));
876 }
877 break;
878
879// TODO:
880 // at this point, there should be at least a start or end time.
881 // fix up for events that take up no time but have a time associated
882#if 0
883 if (!(vo = isAPropertyOf(vevent, VCDTstartProp)))
884 anEvent->setDtStart(anEvent->dtEnd());
885 if (!(vo = isAPropertyOf(vevent, VCDTendProp)))
886 anEvent->setDtEnd(anEvent->dtStart());
887#endif
888
889// TODO: exdates
890#if 0
891 // recurrence exceptions
892 if ((vo = isAPropertyOf(vevent, VCExDateProp)) != 0) {
893 anEvent->setExDates(s = fakeCString(vObjectUStringZValue(vo)));
894 deleteStr(s);
895 }
896#endif
897
898#if 0
899 // secrecy
900 if ((vo = isAPropertyOf(vevent, VCClassProp)) != 0) {
901 anEvent->setSecrecy(s = fakeCString(vObjectUStringZValue(vo)));
902 deleteStr(s);
903 }
904 else
905 anEvent->setSecrecy("PUBLIC");
906
907 // attachments
908 tmpStrList.clear();
909 initPropIterator(&voi, vevent);
910 while (moreIteration(&voi)) {
911 vo = nextVObject(&voi);
912 if (strcmp(vObjectName(vo), VCAttachProp) == 0) {
913 tmpStrList.append(s = fakeCString(vObjectUStringZValue(vo)));
914 deleteStr(s);
915 }
916 }
917 anEvent->setAttachments(tmpStrList);
918
919 // resources
920 if ((vo = isAPropertyOf(vevent, VCResourcesProp)) != 0) {
921 QString resources = (s = fakeCString(vObjectUStringZValue(vo)));
922 deleteStr(s);
923 tmpStrList.clear();
924 index1 = 0;
925 index2 = 0;
926 QString resource;
927 while ((index2 = resources.find(';', index1)) != -1) {
928 resource = resources.mid(index1, (index2 - index1));
929 tmpStrList.append(resource);
930 index1 = index2;
931 }
932 anEvent->setResources(tmpStrList);
933 }
934#endif
935
936 case ICAL_RELATEDTO_PROPERTY: // releated event (parent)
937 event->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p)));
938 mEventsRelate.append(event);
939 break;
940
941
942 case ICAL_TRANSP_PROPERTY: // Transparency
943 transparency = QString::fromUtf8(icalproperty_get_transp(p));
944 if( transparency == "TRANSPARENT" )
945 event->setTransparency( Event::Transparent );
946 else
947 event->setTransparency( Event::Opaque );
948 break;
949
950 default:
951// kdDebug(5800) << "ICALFormat::readEvent(): Unknown property: " << kind
952// << endl;
953 break;
954 }
955
956 p = icalcomponent_get_next_property(vevent,ICAL_ANY_PROPERTY);
957 }
958
959 QString msade = event->nonKDECustomProperty("X-MICROSOFT-CDO-ALLDAYEVENT");
960 if (!msade.isNull()) {
961 bool floats = (msade == QString::fromLatin1("TRUE"));
962 kdDebug(5800) << "ICALFormat::readEvent(): all day event: " << floats << endl;
963 event->setFloats(floats);
964 if (floats) {
965 QDateTime endDate = event->dtEnd();
966 event->setDtEnd(endDate.addDays(-1));
967 }
968 }
969
970 // some stupid vCal exporters ignore the standard and use Description
971 // instead of Summary for the default field. Correct for this.
972 if (event->summary().isEmpty() &&
973 !(event->description().isEmpty())) {
974 QString tmpStr = event->description().simplifyWhiteSpace();
975 event->setDescription("");
976 event->setSummary(tmpStr);
977 }
978
979 return event;
980}
981
982FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy)
983{
984 FreeBusy *freebusy = new FreeBusy;
985
986 readIncidenceBase(vfreebusy,freebusy);
987
988 icalproperty *p = icalcomponent_get_first_property(vfreebusy,ICAL_ANY_PROPERTY);
989
990 icaltimetype icaltime;
991 icalperiodtype icalperiod;
992 QDateTime period_start, period_end;
993
994 while (p) {
995 icalproperty_kind kind = icalproperty_isa(p);
996 switch (kind) {
997
998 case ICAL_DTSTART_PROPERTY: // start date and time
999 icaltime = icalproperty_get_dtstart(p);
1000 freebusy->setDtStart(readICalDateTime(icaltime));
1001 break;
1002
1003 case ICAL_DTEND_PROPERTY: // start End Date and Time
1004 icaltime = icalproperty_get_dtend(p);
1005 freebusy->setDtEnd(readICalDateTime(icaltime));
1006 break;
1007
1008 case ICAL_FREEBUSY_PROPERTY: //Any FreeBusy Times
1009 icalperiod = icalproperty_get_freebusy(p);
1010 period_start = readICalDateTime(icalperiod.start);
1011 period_end = readICalDateTime(icalperiod.end);
1012 freebusy->addPeriod(period_start, period_end);
1013 break;
1014
1015 default:
1016 kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind
1017 << endl;
1018 break;
1019 }
1020 p = icalcomponent_get_next_property(vfreebusy,ICAL_ANY_PROPERTY);
1021 }
1022
1023 return freebusy;
1024}
1025
1026Journal *ICalFormatImpl::readJournal(icalcomponent *vjournal)
1027{
1028 Journal *journal = new Journal;
1029
1030 readIncidence(vjournal,journal);
1031
1032 return journal;
1033}
1034
1035Attendee *ICalFormatImpl::readAttendee(icalproperty *attendee)
1036{
1037 icalparameter *p = 0;
1038
1039 QString email = QString::fromUtf8(icalproperty_get_attendee(attendee));
1040
1041 QString name;
1042 QString uid = QString::null;
1043 p = icalproperty_get_first_parameter(attendee,ICAL_CN_PARAMETER);
1044 if (p) {
1045 name = QString::fromUtf8(icalparameter_get_cn(p));
1046 } else {
1047 }
1048
1049 bool rsvp=false;
1050 p = icalproperty_get_first_parameter(attendee,ICAL_RSVP_PARAMETER);
1051 if (p) {
1052 icalparameter_rsvp rsvpParameter = icalparameter_get_rsvp(p);
1053 if (rsvpParameter == ICAL_RSVP_TRUE) rsvp = true;
1054 }
1055
1056 Attendee::PartStat status = Attendee::NeedsAction;
1057 p = icalproperty_get_first_parameter(attendee,ICAL_PARTSTAT_PARAMETER);
1058 if (p) {
1059 icalparameter_partstat partStatParameter = icalparameter_get_partstat(p);
1060 switch(partStatParameter) {
1061 default:
1062 case ICAL_PARTSTAT_NEEDSACTION:
1063 status = Attendee::NeedsAction;
1064 break;
1065 case ICAL_PARTSTAT_ACCEPTED:
1066 status = Attendee::Accepted;
1067 break;
1068 case ICAL_PARTSTAT_DECLINED:
1069 status = Attendee::Declined;
1070 break;
1071 case ICAL_PARTSTAT_TENTATIVE:
1072 status = Attendee::Tentative;
1073 break;
1074 case ICAL_PARTSTAT_DELEGATED:
1075 status = Attendee::Delegated;
1076 break;
1077 case ICAL_PARTSTAT_COMPLETED:
1078 status = Attendee::Completed;
1079 break;
1080 case ICAL_PARTSTAT_INPROCESS:
1081 status = Attendee::InProcess;
1082 break;
1083 }
1084 }
1085
1086 Attendee::Role role = Attendee::ReqParticipant;
1087 p = icalproperty_get_first_parameter(attendee,ICAL_ROLE_PARAMETER);
1088 if (p) {
1089 icalparameter_role roleParameter = icalparameter_get_role(p);
1090 switch(roleParameter) {
1091 case ICAL_ROLE_CHAIR:
1092 role = Attendee::Chair;
1093 break;
1094 default:
1095 case ICAL_ROLE_REQPARTICIPANT:
1096 role = Attendee::ReqParticipant;
1097 break;
1098 case ICAL_ROLE_OPTPARTICIPANT:
1099 role = Attendee::OptParticipant;
1100 break;
1101 case ICAL_ROLE_NONPARTICIPANT:
1102 role = Attendee::NonParticipant;
1103 break;
1104 }
1105 }
1106
1107 p = icalproperty_get_first_parameter(attendee,ICAL_X_PARAMETER);
1108 uid = icalparameter_get_xvalue(p);
1109 // This should be added, but there seems to be a libical bug here.
1110 /*while (p) {
1111 // if (icalparameter_get_xname(p) == "X-UID") {
1112 uid = icalparameter_get_xvalue(p);
1113 p = icalproperty_get_next_parameter(attendee,ICAL_X_PARAMETER);
1114 } */
1115
1116 return new Attendee( name, email, rsvp, status, role, uid );
1117}
1118
1119Attachment *ICalFormatImpl::readAttachment(icalproperty *attach)
1120{
1121 icalattachtype *a = icalproperty_get_attach(attach);
1122 icalparameter_value v = ICAL_VALUE_NONE;
1123 icalparameter_encoding e = ICAL_ENCODING_NONE;
1124
1125 Attachment *attachment = 0;
1126
1127 icalparameter *vp = icalproperty_get_first_parameter(attach, ICAL_VALUE_PARAMETER);
1128 if (vp)
1129 v = icalparameter_get_value(vp);
1130
1131 icalparameter *ep = icalproperty_get_first_parameter(attach, ICAL_ENCODING_PARAMETER);
1132 if (ep)
1133 e = icalparameter_get_encoding(ep);
1134
1135 if (v == ICAL_VALUE_BINARY && e == ICAL_ENCODING_BASE64)
1136 attachment = new Attachment(icalattachtype_get_base64(a));
1137 else if ((v == ICAL_VALUE_NONE || v == ICAL_VALUE_URI) && (e == ICAL_ENCODING_NONE || e == ICAL_ENCODING_8BIT)) {
1138 attachment = new Attachment(QString(icalattachtype_get_url(a)));
1139 } else {
1140 kdWarning(5800) << "Unsupported attachment format, discarding it!" << endl;
1141 return 0;
1142 }
1143
1144 icalparameter *p = icalproperty_get_first_parameter(attach, ICAL_FMTTYPE_PARAMETER);
1145 if (p)
1146 attachment->setMimeType(QString(icalparameter_get_fmttype(p)));
1147
1148 return attachment;
1149}
1150#include <qtextcodec.h>
1151void ICalFormatImpl::readIncidence(icalcomponent *parent,Incidence *incidence)
1152{
1153 readIncidenceBase(parent,incidence);
1154
1155 icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
1156 bool readrec = false;
1157 const char *text;
1158 int intvalue;
1159 icaltimetype icaltime;
1160 icaldurationtype icalduration;
1161 struct icalrecurrencetype rectype;
1162 QStringList categories;
1163
1164 while (p) {
1165 icalproperty_kind kind = icalproperty_isa(p);
1166 switch (kind) {
1167
1168 case ICAL_CREATED_PROPERTY:
1169 icaltime = icalproperty_get_created(p);
1170 incidence->setCreated(readICalDateTime(icaltime));
1171 break;
1172
1173 case ICAL_SEQUENCE_PROPERTY: // sequence
1174 intvalue = icalproperty_get_sequence(p);
1175 incidence->setRevision(intvalue);
1176 break;
1177
1178 case ICAL_LASTMODIFIED_PROPERTY: // last modification date
1179 icaltime = icalproperty_get_lastmodified(p);
1180 incidence->setLastModified(readICalDateTime(icaltime));
1181 break;
1182
1183 case ICAL_DTSTART_PROPERTY: // start date and time
1184 icaltime = icalproperty_get_dtstart(p);
1185 if (icaltime.is_date) {
1186 incidence->setDtStart(QDateTime(readICalDate(icaltime),QTime(0,0,0)));
1187 incidence->setFloats(true);
1188 } else {
1189 incidence->setDtStart(readICalDateTime(icaltime));
1190 }
1191 break;
1192
1193 case ICAL_DURATION_PROPERTY: // start date and time
1194 icalduration = icalproperty_get_duration(p);
1195 incidence->setDuration(readICalDuration(icalduration));
1196 break;
1197
1198 case ICAL_DESCRIPTION_PROPERTY: // description
1199 text = icalproperty_get_description(p);
1200 incidence->setDescription(QString::fromUtf8(text));
1201 break;
1202
1203 case ICAL_SUMMARY_PROPERTY: // summary
1204 {
1205 text = icalproperty_get_summary(p);
1206 incidence->setSummary(QString::fromUtf8(text));
1207 }
1208 break;
1209 case ICAL_STATUS_PROPERTY: // summary
1210 {
1211 if ( ICAL_STATUS_CANCELLED == icalproperty_get_status(p) )
1212 incidence->setCancelled( true );
1213 }
1214 break;
1215
1216 case ICAL_LOCATION_PROPERTY: // location
1217 text = icalproperty_get_location(p);
1218 incidence->setLocation(QString::fromUtf8(text));
1219 break;
1220
1221#if 0
1222 // status
1223 if ((vo = isAPropertyOf(vincidence, VCStatusProp)) != 0) {
1224 incidence->setStatus(s = fakeCString(vObjectUStringZValue(vo)));
1225 deleteStr(s);
1226 }
1227 else
1228 incidence->setStatus("NEEDS ACTION");
1229#endif
1230
1231 case ICAL_PRIORITY_PROPERTY: // priority
1232 intvalue = icalproperty_get_priority(p);
1233 incidence->setPriority(intvalue);
1234 break;
1235
1236 case ICAL_CATEGORIES_PROPERTY: // categories
1237 text = icalproperty_get_categories(p);
1238 categories.append(QString::fromUtf8(text));
1239 break;
1240 //*******************************************
1241 case ICAL_RRULE_PROPERTY:
1242 // we do need (maybe )start datetime of incidence for recurrence
1243 // such that we can read recurrence only after we read incidence completely
1244 readrec = true;
1245 rectype = icalproperty_get_rrule(p);
1246 break;
1247
1248 case ICAL_EXDATE_PROPERTY:
1249 icaltime = icalproperty_get_exdate(p);
1250 incidence->addExDate(readICalDate(icaltime));
1251 break;
1252
1253 case ICAL_CLASS_PROPERTY:
1254 text = icalproperty_get_class(p);
1255 if (strcmp(text,"PUBLIC") == 0) {
1256 incidence->setSecrecy(Incidence::SecrecyPublic);
1257 } else if (strcmp(text,"CONFIDENTIAL") == 0) {
1258 incidence->setSecrecy(Incidence::SecrecyConfidential);
1259 } else {
1260 incidence->setSecrecy(Incidence::SecrecyPrivate);
1261 }
1262 break;
1263
1264 case ICAL_ATTACH_PROPERTY: // attachments
1265 incidence->addAttachment(readAttachment(p));
1266 break;
1267
1268 default:
1269// kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind
1270// << endl;
1271 break;
1272 }
1273
1274 p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
1275 }
1276 if ( readrec ) {
1277 readRecurrenceRule(rectype,incidence);
1278 }
1279 // kpilot stuff
1280// TODO: move this application-specific code to kpilot
1281 QString kp = incidence->nonKDECustomProperty("X-PILOTID");
1282 if (!kp.isNull()) {
1283 incidence->setPilotId(kp.toInt());
1284 }
1285 kp = incidence->nonKDECustomProperty("X-PILOTSTAT");
1286 if (!kp.isNull()) {
1287 incidence->setSyncStatus(kp.toInt());
1288 }
1289 kp = incidence->nonKDECustomProperty("X-ZAURUSID");
1290 if (!kp.isNull()) {
1291 incidence->setZaurusId(kp.toInt());
1292 }
1293
1294 kp = incidence->nonKDECustomProperty("X-ZAURUSUID");
1295 if (!kp.isNull()) {
1296 incidence->setZaurusUid(kp.toInt());
1297 }
1298
1299 kp = incidence->nonKDECustomProperty("X-ZAURUSSTAT");
1300 if (!kp.isNull()) {
1301 incidence->setZaurusStat(kp.toInt());
1302 }
1303
1304 // Cancel backwards compatibility mode for subsequent changes by the application
1305 incidence->recurrence()->setCompatVersion();
1306
1307 // add categories
1308 incidence->setCategories(categories);
1309
1310 // iterate through all alarms
1311 for (icalcomponent *alarm = icalcomponent_get_first_component(parent,ICAL_VALARM_COMPONENT);
1312 alarm;
1313 alarm = icalcomponent_get_next_component(parent,ICAL_VALARM_COMPONENT)) {
1314 readAlarm(alarm,incidence);
1315 }
1316}
1317
1318void ICalFormatImpl::readIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase)
1319{
1320 icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
1321
1322 while (p) {
1323 icalproperty_kind kind = icalproperty_isa(p);
1324 switch (kind) {
1325
1326 case ICAL_UID_PROPERTY: // unique id
1327 incidenceBase->setUid(QString::fromUtf8(icalproperty_get_uid(p)));
1328 break;
1329
1330 case ICAL_ORGANIZER_PROPERTY: // organizer
1331 incidenceBase->setOrganizer(QString::fromUtf8(icalproperty_get_organizer(p)));
1332 break;
1333
1334 case ICAL_ATTENDEE_PROPERTY: // attendee
1335 incidenceBase->addAttendee(readAttendee(p));
1336 break;
1337
1338 default:
1339 break;
1340 }
1341
1342 p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
1343 }
1344
1345 // custom properties
1346 readCustomProperties(parent, incidenceBase);
1347}
1348
1349void ICalFormatImpl::readCustomProperties(icalcomponent *parent,CustomProperties *properties)
1350{
1351 QMap<QCString, QString> customProperties;
1352
1353 icalproperty *p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY);
1354
1355 while (p) {
1356
1357 QString value = QString::fromUtf8(icalproperty_get_x(p));
1358 customProperties[icalproperty_get_name(p)] = value;
1359
1360 p = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY);
1361 }
1362
1363 properties->setCustomProperties(customProperties);
1364}
1365
1366void ICalFormatImpl::readRecurrenceRule(struct icalrecurrencetype rrule,Incidence *incidence)
1367{
1368// kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
1369
1370 Recurrence *recur = incidence->recurrence();
1371 recur->setCompatVersion(mCalendarVersion);
1372 recur->unsetRecurs();
1373
1374 struct icalrecurrencetype r = rrule;
1375
1376 dumpIcalRecurrence(r);
1377 readRecurrence( r, recur, incidence);
1378}
1379
1380void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r, Recurrence* recur, Incidence *incidence)
1381{
1382 int wkst;
1383 int index = 0;
1384 short day = 0;
1385 QBitArray qba(7);
1386 int frequ = r.freq;
1387 int interv = r.interval;
1388 // preprocessing for odd recurrence definitions
1389
1390 if ( r.freq == ICAL_MONTHLY_RECURRENCE ) {
1391 if ( r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) {
1392 interv = 12;
1393 }
1394 }
1395 if ( r.freq == ICAL_YEARLY_RECURRENCE ) {
1396 if ( r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX && r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
1397 frequ = ICAL_MONTHLY_RECURRENCE;
1398 interv = 12;
1399 }
1400 }
1401
1402 switch (frequ) {
1403 case ICAL_MINUTELY_RECURRENCE:
1404 if (!icaltime_is_null_time(r.until)) {
1405 recur->setMinutely(interv,readICalDateTime(r.until));
1406 } else {
1407 if (r.count == 0)
1408 recur->setMinutely(interv,-1);
1409 else
1410 recur->setMinutely(interv,r.count);
1411 }
1412 break;
1413 case ICAL_HOURLY_RECURRENCE:
1414 if (!icaltime_is_null_time(r.until)) {
1415 recur->setHourly(interv,readICalDateTime(r.until));
1416 } else {
1417 if (r.count == 0)
1418 recur->setHourly(interv,-1);
1419 else
1420 recur->setHourly(interv,r.count);
1421 }
1422 break;
1423 case ICAL_DAILY_RECURRENCE:
1424 if (!icaltime_is_null_time(r.until)) {
1425 recur->setDaily(interv,readICalDate(r.until));
1426 } else {
1427 if (r.count == 0)
1428 recur->setDaily(interv,-1);
1429 else
1430 recur->setDaily(interv,r.count);
1431 }
1432 break;
1433 case ICAL_WEEKLY_RECURRENCE:
1434 // kdDebug(5800) << "WEEKLY_RECURRENCE" << endl;
1435 wkst = (r.week_start + 5)%7 + 1;
1436 if (!icaltime_is_null_time(r.until)) {
1437 recur->setWeekly(interv,qba,readICalDate(r.until),wkst);
1438 } else {
1439 if (r.count == 0)
1440 recur->setWeekly(interv,qba,-1,wkst);
1441 else
1442 recur->setWeekly(interv,qba,r.count,wkst);
1443 }
1444 if ( r.by_day[0] == ICAL_RECURRENCE_ARRAY_MAX) {
1445 int wday = incidence->dtStart().date().dayOfWeek ()-1;
1446 //qDebug("weekly error found ");
1447 qba.setBit(wday);
1448 } else {
1449 while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
1450 // kdDebug(5800) << " " << day << endl;
1451 qba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
1452 }
1453 }
1454 break;
1455 case ICAL_MONTHLY_RECURRENCE:
1456
1457 if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
1458 if (!icaltime_is_null_time(r.until)) {
1459 recur->setMonthly(Recurrence::rMonthlyPos,interv,
1460 readICalDate(r.until));
1461 } else {
1462 if (r.count == 0)
1463 recur->setMonthly(Recurrence::rMonthlyPos,interv,-1);
1464 else
1465 recur->setMonthly(Recurrence::rMonthlyPos,interv,r.count);
1466 }
1467 bool useSetPos = false;
1468 short pos = 0;
1469 while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
1470 // kdDebug(5800) << "----a " << index << ": " << day << endl;
1471 pos = icalrecurrencetype_day_position(day);
1472 if (pos) {
1473 day = icalrecurrencetype_day_day_of_week(day);
1474 QBitArray ba(7); // don't wipe qba
1475 ba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
1476 recur->addMonthlyPos(pos,ba);
1477 } else {
1478 qba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
1479 useSetPos = true;
1480 }
1481 }
1482 if (useSetPos) {
1483 if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
1484 recur->addMonthlyPos(r.by_set_pos[0],qba);
1485 }
1486 }
1487 } else if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
1488 if (!icaltime_is_null_time(r.until)) {
1489 recur->setMonthly(Recurrence::rMonthlyDay,interv,
1490 readICalDate(r.until));
1491 } else {
1492 if (r.count == 0)
1493 recur->setMonthly(Recurrence::rMonthlyDay,interv,-1);
1494 else
1495 recur->setMonthly(Recurrence::rMonthlyDay,interv,r.count);
1496 }
1497 while((day = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
1498 // kdDebug(5800) << "----b " << day << endl;
1499 recur->addMonthlyDay(day);
1500 }
1501 }
1502 break;
1503 case ICAL_YEARLY_RECURRENCE:
1504 if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
1505 if (!icaltime_is_null_time(r.until)) {
1506 recur->setYearly(Recurrence::rYearlyDay,interv,
1507 readICalDate(r.until));
1508 } else {
1509 if (r.count == 0)
1510 recur->setYearly(Recurrence::rYearlyDay,interv,-1);
1511 else
1512 recur->setYearly(Recurrence::rYearlyDay,interv,r.count);
1513 }
1514 while((day = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
1515 recur->addYearlyNum(day);
1516 }
1517 } else if ( true /*r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX*/) {
1518 if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
1519 if (!icaltime_is_null_time(r.until)) {
1520 recur->setYearly(Recurrence::rYearlyPos,interv,
1521 readICalDate(r.until));
1522 } else {
1523 if (r.count == 0)
1524 recur->setYearly(Recurrence::rYearlyPos,interv,-1);
1525 else
1526 recur->setYearly(Recurrence::rYearlyPos,interv,r.count);
1527 }
1528 bool useSetPos = false;
1529 short pos = 0;
1530 while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
1531 // kdDebug(5800) << "----a " << index << ": " << day << endl;
1532 pos = icalrecurrencetype_day_position(day);
1533 if (pos) {
1534 day = icalrecurrencetype_day_day_of_week(day);
1535 QBitArray ba(7); // don't wipe qba
1536 ba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
1537 recur->addYearlyMonthPos(pos,ba);
1538 } else {
1539 qba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
1540 useSetPos = true;
1541 }
1542 }
1543 if (useSetPos) {
1544 if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
1545 recur->addYearlyMonthPos(r.by_set_pos[0],qba);
1546 }
1547 }
1548 } else {
1549 if (!icaltime_is_null_time(r.until)) {
1550 recur->setYearly(Recurrence::rYearlyMonth,interv,
1551 readICalDate(r.until));
1552 } else {
1553 if (r.count == 0)
1554 recur->setYearly(Recurrence::rYearlyMonth,interv,-1);
1555 else
1556 recur->setYearly(Recurrence::rYearlyMonth,interv,r.count);
1557 }
1558 }
1559 if ( r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
1560 index = 0;
1561 while((day = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
1562 recur->addYearlyNum(day);
1563 }
1564 } else {
1565 recur->addYearlyNum(incidence->dtStart().date().month());
1566 }
1567 }
1568 break;
1569 default:
1570 ;
1571 break;
1572 }
1573}
1574
1575void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
1576{
1577 //kdDebug(5800) << "Read alarm for " << incidence->summary() << endl;
1578
1579 Alarm* ialarm = incidence->newAlarm();
1580 ialarm->setRepeatCount(0);
1581 ialarm->setEnabled(true);
1582
1583 // Determine the alarm's action type
1584 icalproperty *p = icalcomponent_get_first_property(alarm,ICAL_ACTION_PROPERTY);
1585 if ( !p ) {
1586 return;
1587 }
1588
1589 icalproperty_action action = icalproperty_get_action(p);
1590 Alarm::Type type = Alarm::Display;
1591 switch ( action ) {
1592 case ICAL_ACTION_DISPLAY: type = Alarm::Display; break;
1593 case ICAL_ACTION_AUDIO: type = Alarm::Audio; break;
1594 case ICAL_ACTION_PROCEDURE: type = Alarm::Procedure; break;
1595 case ICAL_ACTION_EMAIL: type = Alarm::Email; break;
1596 default:
1597 ;
1598 return;
1599 }
1600 ialarm->setType(type);
1601
1602 p = icalcomponent_get_first_property(alarm,ICAL_ANY_PROPERTY);
1603 while (p) {
1604 icalproperty_kind kind = icalproperty_isa(p);
1605
1606 switch (kind) {
1607 case ICAL_TRIGGER_PROPERTY: {
1608 icaltriggertype trigger = icalproperty_get_trigger(p);
1609 if (icaltime_is_null_time(trigger.time)) {
1610 if (icaldurationtype_is_null_duration(trigger.duration)) {
1611 kdDebug(5800) << "ICalFormatImpl::readAlarm(): Trigger has no time and no duration." << endl;
1612 } else {
1613 Duration duration = icaldurationtype_as_int( trigger.duration );
1614 icalparameter *param = icalproperty_get_first_parameter(p,ICAL_RELATED_PARAMETER);
1615 if (param && icalparameter_get_related(param) == ICAL_RELATED_END)
1616 ialarm->setEndOffset(duration);
1617 else
1618 ialarm->setStartOffset(duration);
1619 }
1620 } else {
1621 ialarm->setTime(readICalDateTime(trigger.time));
1622 }
1623 break;
1624 }
1625 case ICAL_DURATION_PROPERTY: {
1626 icaldurationtype duration = icalproperty_get_duration(p);
1627 ialarm->setSnoozeTime(icaldurationtype_as_int(duration)/60);
1628 break;
1629 }
1630 case ICAL_REPEAT_PROPERTY:
1631 ialarm->setRepeatCount(icalproperty_get_repeat(p));
1632 break;
1633
1634 // Only in DISPLAY and EMAIL and PROCEDURE alarms
1635 case ICAL_DESCRIPTION_PROPERTY: {
1636 QString description = QString::fromUtf8(icalproperty_get_description(p));
1637 switch ( action ) {
1638 case ICAL_ACTION_DISPLAY:
1639 ialarm->setText( description );
1640 break;
1641 case ICAL_ACTION_PROCEDURE:
1642 ialarm->setProgramArguments( description );
1643 break;
1644 case ICAL_ACTION_EMAIL:
1645 ialarm->setMailText( description );
1646 break;
1647 default:
1648 break;
1649 }
1650 break;
1651 }
1652 // Only in EMAIL alarm
1653 case ICAL_SUMMARY_PROPERTY:
1654 ialarm->setMailSubject(QString::fromUtf8(icalproperty_get_summary(p)));
1655 break;
1656
1657 // Only in EMAIL alarm
1658 case ICAL_ATTENDEE_PROPERTY: {
1659 QString email = QString::fromUtf8(icalproperty_get_attendee(p));
1660 QString name;
1661 icalparameter *param = icalproperty_get_first_parameter(p,ICAL_CN_PARAMETER);
1662 if (param) {
1663 name = QString::fromUtf8(icalparameter_get_cn(param));
1664 }
1665 ialarm->addMailAddress(Person(name, email));
1666 break;
1667 }
1668 // Only in AUDIO and EMAIL and PROCEDURE alarms
1669 case ICAL_ATTACH_PROPERTY: {
1670 icalattachtype *attach = icalproperty_get_attach(p);
1671 QString url = QFile::decodeName(icalattachtype_get_url(attach));
1672 switch ( action ) {
1673 case ICAL_ACTION_AUDIO:
1674 ialarm->setAudioFile( url );
1675 break;
1676 case ICAL_ACTION_PROCEDURE:
1677 ialarm->setProgramFile( url );
1678 break;
1679 case ICAL_ACTION_EMAIL:
1680 ialarm->addMailAttachment( url );
1681 break;
1682 default:
1683 break;
1684 }
1685 break;
1686 }
1687 default:
1688 break;
1689 }
1690
1691 p = icalcomponent_get_next_property(alarm,ICAL_ANY_PROPERTY);
1692 }
1693
1694 // custom properties
1695 readCustomProperties(alarm, ialarm);
1696
1697 // TODO: check for consistency of alarm properties
1698}
1699
1700icaltimetype ICalFormatImpl::writeICalDate(const QDate &date)
1701{
1702 icaltimetype t;
1703
1704 t.year = date.year();
1705 t.month = date.month();
1706 t.day = date.day();
1707
1708 t.hour = 0;
1709 t.minute = 0;
1710 t.second = 0;
1711
1712 t.is_date = 1;
1713
1714 t.is_utc = 0;
1715
1716 t.zone = 0;
1717
1718 return t;
1719}
1720
1721icaltimetype ICalFormatImpl::writeICalDateTime(const QDateTime &dt )
1722{
1723 icaltimetype t;
1724 t.is_date = 0;
1725 t.zone = 0;
1726 QDateTime datetime;
1727 if ( mParent->utc() ) {
1728 int offset = KGlobal::locale()->localTimeOffset( dt );
1729 datetime = dt.addSecs ( -offset*60);
1730 t.is_utc = 1;
1731 }
1732 else {
1733 datetime = dt;
1734 t.is_utc = 0;
1735
1736 }
1737 t.year = datetime.date().year();
1738 t.month = datetime.date().month();
1739 t.day = datetime.date().day();
1740
1741 t.hour = datetime.time().hour();
1742 t.minute = datetime.time().minute();
1743 t.second = datetime.time().second();
1744
1745 //qDebug("*** time %s localtime %s ",dt .toString().latin1() ,datetime .toString().latin1() );
1746
1747// if ( mParent->utc() ) {
1748// datetime = KGlobal::locale()->localTime( dt );
1749// qDebug("*** time %s localtime %s ",dt .toString().latin1() ,datetime .toString().latin1() );
1750// if (mParent->timeZoneId().isEmpty())
1751// t = icaltime_as_utc(t, 0);
1752// else
1753// t = icaltime_as_utc(t,mParent->timeZoneId().local8Bit());
1754// }
1755
1756 return t;
1757}
1758
1759QDateTime ICalFormatImpl::readICalDateTime(icaltimetype t)
1760{
1761 QDateTime dt (QDate(t.year,t.month,t.day),
1762 QTime(t.hour,t.minute,t.second) );
1763
1764 if (t.is_utc) {
1765 int offset = KGlobal::locale()->localTimeOffset( dt );
1766 dt = dt.addSecs ( offset*60);
1767 }
1768
1769 return dt;
1770}
1771
1772QDate ICalFormatImpl::readICalDate(icaltimetype t)
1773{
1774 return QDate(t.year,t.month,t.day);
1775}
1776
1777icaldurationtype ICalFormatImpl::writeICalDuration(int seconds)
1778{
1779 icaldurationtype d;
1780
1781 d.weeks = seconds % gSecondsPerWeek;
1782 seconds -= d.weeks * gSecondsPerWeek;
1783 d.days = seconds % gSecondsPerDay;
1784 seconds -= d.days * gSecondsPerDay;
1785 d.hours = seconds % gSecondsPerHour;
1786 seconds -= d.hours * gSecondsPerHour;
1787 d.minutes = seconds % gSecondsPerMinute;
1788 seconds -= d.minutes * gSecondsPerMinute;
1789 d.seconds = seconds;
1790 d.is_neg = 0;
1791
1792 return d;
1793}
1794
1795int ICalFormatImpl::readICalDuration(icaldurationtype d)
1796{
1797 int result = 0;
1798
1799 result += d.weeks * gSecondsPerWeek;
1800 result += d.days * gSecondsPerDay;
1801 result += d.hours * gSecondsPerHour;
1802 result += d.minutes * gSecondsPerMinute;
1803 result += d.seconds;
1804
1805 if (d.is_neg) result *= -1;
1806
1807 return result;
1808}
1809
1810icalcomponent *ICalFormatImpl::createCalendarComponent(Calendar *cal)
1811{
1812 icalcomponent *calendar;
1813
1814 // Root component
1815 calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
1816
1817 icalproperty *p;
1818
1819 // Product Identifier
1820 p = icalproperty_new_prodid(CalFormat::productId().utf8());
1821 icalcomponent_add_property(calendar,p);
1822
1823 // TODO: Add time zone
1824
1825 // iCalendar version (2.0)
1826 p = icalproperty_new_version(const_cast<char *>(_ICAL_VERSION));
1827 icalcomponent_add_property(calendar,p);
1828
1829 // Custom properties
1830 if( cal != 0 )
1831 writeCustomProperties(calendar, cal);
1832
1833 return calendar;
1834}
1835
1836
1837
1838// take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
1839// and break it down from its tree-like format into the dictionary format
1840// that is used internally in the ICalFormatImpl.
1841bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
1842{
1843 // this function will populate the caldict dictionary and other event
1844 // lists. It turns vevents into Events and then inserts them.
1845
1846 if (!calendar) return false;
1847
1848// TODO: check for METHOD
1849#if 0
1850 if ((curVO = isAPropertyOf(vcal, ICMethodProp)) != 0) {
1851 char *methodType = 0;
1852 methodType = fakeCString(vObjectUStringZValue(curVO));
1853 if (mEnableDialogs)
1854 KMessageBox::information(mTopWidget,
1855 i18n("This calendar is an iTIP transaction of type \"%1\".")
1856 .arg(methodType),
1857 i18n("%1: iTIP Transaction").arg(CalFormat::application()));
1858 delete methodType;
1859 }
1860#endif
1861
1862 icalproperty *p;
1863
1864 p = icalcomponent_get_first_property(calendar,ICAL_PRODID_PROPERTY);
1865 if (!p) {
1866// TODO: does no PRODID really matter?
1867// mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
1868// return false;
1869 mLoadedProductId = "";
1870 mCalendarVersion = 0;
1871 } else {
1872 mLoadedProductId = QString::fromUtf8(icalproperty_get_prodid(p));
1873 mCalendarVersion = CalFormat::calendarVersion(mLoadedProductId);
1874
1875 delete mCompat;
1876 mCompat = CompatFactory::createCompat( mLoadedProductId );
1877 }
1878
1879// TODO: check for unknown PRODID
1880#if 0
1881 if (!mCalendarVersion
1882 && CalFormat::productId() != mLoadedProductId) {
1883 // warn the user that we might have trouble reading non-known calendar.
1884 if (mEnableDialogs)
1885 KMessageBox::information(mTopWidget,
1886 i18n("This vCalendar file was not created by KOrganizer "
1887 "or any other product we support. Loading anyway..."),
1888 i18n("%1: Unknown vCalendar Vendor").arg(CalFormat::application()));
1889 }
1890#endif
1891
1892 p = icalcomponent_get_first_property(calendar,ICAL_VERSION_PROPERTY);
1893 if (!p) {
1894 mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
1895 return false;
1896 } else {
1897 const char *version = icalproperty_get_version(p);
1898
1899 if (strcmp(version,"1.0") == 0) {
1900 mParent->setException(new ErrorFormat(ErrorFormat::CalVersion1,
1901 i18n("Expected iCalendar format")));
1902 return false;
1903 } else if (strcmp(version,"2.0") != 0) {
1904 mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
1905 return false;
1906 }
1907 }
1908
1909
1910// TODO: check for calendar format version
1911#if 0
1912 // warn the user we might have trouble reading this unknown version.
1913 if ((curVO = isAPropertyOf(vcal, VCVersionProp)) != 0) {
1914 char *s = fakeCString(vObjectUStringZValue(curVO));
1915 if (strcmp(_VCAL_VERSION, s) != 0)
1916 if (mEnableDialogs)
1917 KMessageBox::sorry(mTopWidget,
1918 i18n("This vCalendar file has version %1.\n"
1919 "We only support %2.")
1920 .arg(s).arg(_VCAL_VERSION),
1921 i18n("%1: Unknown vCalendar Version").arg(CalFormat::application()));
1922 deleteStr(s);
1923 }
1924#endif
1925
1926 // custom properties
1927 readCustomProperties(calendar, cal);
1928
1929// TODO: set time zone
1930#if 0
1931 // set the time zone
1932 if ((curVO = isAPropertyOf(vcal, VCTimeZoneProp)) != 0) {
1933 char *s = fakeCString(vObjectUStringZValue(curVO));
1934 cal->setTimeZone(s);
1935 deleteStr(s);
1936 }
1937#endif
1938
1939 // Store all events with a relatedTo property in a list for post-processing
1940 mEventsRelate.clear();
1941 mTodosRelate.clear();
1942 // TODO: make sure that only actually added ecvens go to this lists.
1943
1944 icalcomponent *c;
1945
1946 // Iterate through all todos
1947 c = icalcomponent_get_first_component(calendar,ICAL_VTODO_COMPONENT);
1948 while (c) {
1949// kdDebug(5800) << "----Todo found" << endl;
1950 Todo *todo = readTodo(c);
1951 if (!cal->todo(todo->uid())) cal->addTodo(todo);
1952 c = icalcomponent_get_next_component(calendar,ICAL_VTODO_COMPONENT);
1953 }
1954
1955 // Iterate through all events
1956 c = icalcomponent_get_first_component(calendar,ICAL_VEVENT_COMPONENT);
1957 while (c) {
1958// kdDebug(5800) << "----Event found" << endl;
1959 Event *event = readEvent(c);
1960 if (!cal->event(event->uid())) cal->addEvent(event);
1961 c = icalcomponent_get_next_component(calendar,ICAL_VEVENT_COMPONENT);
1962 }
1963
1964 // Iterate through all journals
1965 c = icalcomponent_get_first_component(calendar,ICAL_VJOURNAL_COMPONENT);
1966 while (c) {
1967// kdDebug(5800) << "----Journal found" << endl;
1968 Journal *journal = readJournal(c);
1969 if (!cal->journal(journal->uid())) cal->addJournal(journal);
1970 c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT);
1971 }
1972
1973#if 0
1974 initPropIterator(&i, vcal);
1975
1976 // go through all the vobjects in the vcal
1977 while (moreIteration(&i)) {
1978 curVO = nextVObject(&i);
1979
1980 /************************************************************************/
1981
1982 // now, check to see that the object is an event or todo.
1983 if (strcmp(vObjectName(curVO), VCEventProp) == 0) {
1984
1985 if ((curVOProp = isAPropertyOf(curVO, KPilotStatusProp)) != 0) {
1986 char *s;
1987 s = fakeCString(vObjectUStringZValue(curVOProp));
1988 // check to see if event was deleted by the kpilot conduit
1989 if (atoi(s) == Event::SYNCDEL) {
1990 deleteStr(s);
1991 goto SKIP;
1992 }
1993 deleteStr(s);
1994 }
1995
1996 // this code checks to see if we are trying to read in an event
1997 // that we already find to be in the calendar. If we find this
1998 // to be the case, we skip the event.
1999 if ((curVOProp = isAPropertyOf(curVO, VCUniqueStringProp)) != 0) {
2000 char *s = fakeCString(vObjectUStringZValue(curVOProp));
2001 QString tmpStr(s);
2002 deleteStr(s);
2003
2004 if (cal->event(tmpStr)) {
2005 goto SKIP;
2006 }
2007 if (cal->todo(tmpStr)) {
2008 goto SKIP;
2009 }
2010 }
2011
2012 if ((!(curVOProp = isAPropertyOf(curVO, VCDTstartProp))) &&
2013 (!(curVOProp = isAPropertyOf(curVO, VCDTendProp)))) {
2014 kdDebug(5800) << "found a VEvent with no DTSTART and no DTEND! Skipping..." << endl;
2015 goto SKIP;
2016 }
2017
2018 anEvent = VEventToEvent(curVO);
2019 // we now use addEvent instead of insertEvent so that the
2020 // signal/slot get connected.
2021 if (anEvent)
2022 cal->addEvent(anEvent);
2023 else {
2024 // some sort of error must have occurred while in translation.
2025 goto SKIP;
2026 }
2027 } else if (strcmp(vObjectName(curVO), VCTodoProp) == 0) {
2028 anEvent = VTodoToEvent(curVO);
2029 cal->addTodo(anEvent);
2030 } else if ((strcmp(vObjectName(curVO), VCVersionProp) == 0) ||
2031 (strcmp(vObjectName(curVO), VCProdIdProp) == 0) ||
2032 (strcmp(vObjectName(curVO), VCTimeZoneProp) == 0)) {
2033 // do nothing, we know these properties and we want to skip them.
2034 // we have either already processed them or are ignoring them.
2035 ;
2036 } else {
2037 ;
2038 }
2039 SKIP:
2040 ;
2041 } // while
2042#endif
2043
2044 // Post-Process list of events with relations, put Event objects in relation
2045 Event *ev;
2046 for ( ev=mEventsRelate.first(); ev != 0; ev=mEventsRelate.next() ) {
2047 ev->setRelatedTo(cal->event(ev->relatedToUid()));
2048 }
2049 Todo *todo;
2050 for ( todo=mTodosRelate.first(); todo != 0; todo=mTodosRelate.next() ) {
2051 todo->setRelatedTo(cal->todo(todo->relatedToUid()));
2052 }
2053
2054 return true;
2055}
2056
2057QString ICalFormatImpl::extractErrorProperty(icalcomponent *c)
2058{
2059// kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: "
2060// << icalcomponent_as_ical_string(c) << endl;
2061
2062 QString errorMessage;
2063
2064 icalproperty *error;
2065 error = icalcomponent_get_first_property(c,ICAL_XLICERROR_PROPERTY);
2066 while(error) {
2067 errorMessage += icalproperty_get_xlicerror(error);
2068 errorMessage += "\n";
2069 error = icalcomponent_get_next_property(c,ICAL_XLICERROR_PROPERTY);
2070 }
2071
2072// kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: " << errorMessage << endl;
2073
2074 return errorMessage;
2075}
2076
2077void ICalFormatImpl::dumpIcalRecurrence(icalrecurrencetype r)
2078{
2079 int i;
2080
2081
2082 if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
2083 int index = 0;
2084 QString out = " By Day: ";
2085 while((i = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
2086 out.append(QString::number(i) + " ");
2087 }
2088 }
2089 if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
2090 int index = 0;
2091 QString out = " By Month Day: ";
2092 while((i = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
2093 out.append(QString::number(i) + " ");
2094 }
2095 }
2096 if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
2097 int index = 0;
2098 QString out = " By Year Day: ";
2099 while((i = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
2100 out.append(QString::number(i) + " ");
2101 }
2102 }
2103 if (r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) {
2104 int index = 0;
2105 QString out = " By Month: ";
2106 while((i = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
2107 out.append(QString::number(i) + " ");
2108 }
2109 }
2110 if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
2111 int index = 0;
2112 QString out = " By Set Pos: ";
2113 while((i = r.by_set_pos[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
2114 out.append(QString::number(i) + " ");
2115 }
2116 }
2117}
2118
2119icalcomponent *ICalFormatImpl::createScheduleComponent(IncidenceBase *incidence,
2120 Scheduler::Method method)
2121{
2122 icalcomponent *message = createCalendarComponent();
2123
2124 icalproperty_method icalmethod = ICAL_METHOD_NONE;
2125
2126 switch (method) {
2127 case Scheduler::Publish:
2128 icalmethod = ICAL_METHOD_PUBLISH;
2129 break;
2130 case Scheduler::Request:
2131 icalmethod = ICAL_METHOD_REQUEST;
2132 break;
2133 case Scheduler::Refresh:
2134 icalmethod = ICAL_METHOD_REFRESH;
2135 break;
2136 case Scheduler::Cancel:
2137 icalmethod = ICAL_METHOD_CANCEL;
2138 break;
2139 case Scheduler::Add:
2140 icalmethod = ICAL_METHOD_ADD;
2141 break;
2142 case Scheduler::Reply:
2143 icalmethod = ICAL_METHOD_REPLY;
2144 break;
2145 case Scheduler::Counter:
2146 icalmethod = ICAL_METHOD_COUNTER;
2147 break;
2148 case Scheduler::Declinecounter:
2149 icalmethod = ICAL_METHOD_DECLINECOUNTER;
2150 break;
2151 default:
2152
2153 return message;
2154 }
2155
2156 icalcomponent_add_property(message,icalproperty_new_method(icalmethod));
2157
2158 // TODO: check, if dynamic cast is required
2159 if(incidence->type() == "Todo") {
2160 Todo *todo = static_cast<Todo *>(incidence);
2161 icalcomponent_add_component(message,writeTodo(todo));
2162 }
2163 if(incidence->type() == "Event") {
2164 Event *event = static_cast<Event *>(incidence);
2165 icalcomponent_add_component(message,writeEvent(event));
2166 }
2167 if(incidence->type() == "FreeBusy") {
2168 FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);
2169 icalcomponent_add_component(message,writeFreeBusy(freebusy, method));
2170 }
2171
2172 return message;
2173}
diff --git a/libkcal/icalformatimpl.h b/libkcal/icalformatimpl.h
new file mode 100644
index 0000000..2f32365
--- a/dev/null
+++ b/libkcal/icalformatimpl.h
@@ -0,0 +1,109 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef ICALFORMATIMPL_H
21#define ICALFORMATIMPL_H
22
23#include <qstring.h>
24
25#include "scheduler.h"
26#include "freebusy.h"
27
28extern "C" {
29 #include <ical.h>
30 #include <icalss.h>
31}
32
33namespace KCal {
34
35class Compat;
36
37/**
38 This class provides the libical dependent functions for ICalFormat.
39*/
40class ICalFormatImpl {
41 public:
42 /** Create new iCal format for calendar object */
43 ICalFormatImpl( ICalFormat *parent );
44 virtual ~ICalFormatImpl();
45
46 bool populate( Calendar *, icalcomponent *fs);
47
48 icalcomponent *writeIncidence(Incidence *incidence);
49 icalcomponent *writeTodo(Todo *todo);
50 icalcomponent *writeEvent(Event *event);
51 icalcomponent *writeFreeBusy(FreeBusy *freebusy,
52 Scheduler::Method method);
53 icalcomponent *writeJournal(Journal *journal);
54 void writeIncidence(icalcomponent *parent,Incidence *incidence);
55 icalproperty *writeAttendee(Attendee *attendee);
56 icalproperty *writeAttachment(Attachment *attach);
57 icalproperty *writeRecurrenceRule(Recurrence *);
58 icalproperty *writeAlarm(Alarm *alarm);
59
60 QString extractErrorProperty(icalcomponent *);
61 Todo *readTodo(icalcomponent *vtodo);
62 Event *readEvent(icalcomponent *vevent);
63 FreeBusy *readFreeBusy(icalcomponent *vfreebusy);
64 Journal *readJournal(icalcomponent *vjournal);
65 Attendee *readAttendee(icalproperty *attendee);
66 Attachment *readAttachment(icalproperty *attach);
67 void readIncidence(icalcomponent *parent,Incidence *incidence);
68 void readRecurrenceRule(struct icalrecurrencetype rrule,Incidence *event);
69 void readRecurrence( const struct icalrecurrencetype &r, Recurrence* recur,Incidence *event );
70 void readAlarm(icalcomponent *alarm,Incidence *incidence);
71 /** Return the PRODID string loaded from calendar file */
72 const QString &loadedProductId() { return mLoadedProductId; }
73
74 icaltimetype writeICalDate(const QDate &);
75 QDate readICalDate(icaltimetype);
76 icaltimetype writeICalDateTime(const QDateTime &);
77 QDateTime readICalDateTime(icaltimetype);
78 icaldurationtype writeICalDuration(int seconds);
79 int readICalDuration(icaldurationtype);
80 icalcomponent *createCalendarComponent(Calendar * = 0);
81 icalcomponent *createScheduleComponent(IncidenceBase *,Scheduler::Method);
82
83 private:
84 void writeIncidenceBase(icalcomponent *parent,IncidenceBase *);
85 void readIncidenceBase(icalcomponent *parent,IncidenceBase *);
86 void writeCustomProperties(icalcomponent *parent,CustomProperties *);
87 void readCustomProperties(icalcomponent *parent,CustomProperties *);
88 void dumpIcalRecurrence(icalrecurrencetype);
89
90 ICalFormat *mParent;
91 Calendar *mCalendar;
92
93 QString mLoadedProductId; // PRODID string loaded from calendar file
94 int mCalendarVersion; // determines backward compatibility mode on read
95
96 QPtrList<Event> mEventsRelate; // events with relations
97 QPtrList<Todo> mTodosRelate; // todos with relations
98
99 static const int mSecondsPerWeek;
100 static const int mSecondsPerDay;
101 static const int mSecondsPerHour;
102 static const int mSecondsPerMinute;
103
104 Compat *mCompat;
105};
106
107}
108
109#endif
diff --git a/libkcal/icalformatimpl.h.bup b/libkcal/icalformatimpl.h.bup
new file mode 100644
index 0000000..37cf857
--- a/dev/null
+++ b/libkcal/icalformatimpl.h.bup
@@ -0,0 +1,109 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef ICALFORMATIMPL_H
21#define ICALFORMATIMPL_H
22
23#include <qstring.h>
24
25#include "scheduler.h"
26#include "freebusy.h"
27
28extern "C" {
29 #include <ical.h>
30 #include <icalss.h>
31}
32
33namespace KCal {
34
35class Compat;
36
37/**
38 This class provides the libical dependent functions for ICalFormat.
39*/
40class ICalFormatImpl {
41 public:
42 /** Create new iCal format for calendar object */
43 ICalFormatImpl( ICalFormat *parent );
44 virtual ~ICalFormatImpl();
45
46 bool populate( Calendar *, icalcomponent *fs);
47
48 icalcomponent *writeIncidence(Incidence *incidence);
49 icalcomponent *writeTodo(Todo *todo);
50 icalcomponent *writeEvent(Event *event);
51 icalcomponent *writeFreeBusy(FreeBusy *freebusy,
52 Scheduler::Method method);
53 icalcomponent *writeJournal(Journal *journal);
54 void writeIncidence(icalcomponent *parent,Incidence *incidence);
55 icalproperty *writeAttendee(Attendee *attendee);
56 icalproperty *writeAttachment(Attachment *attach);
57 icalproperty *writeRecurrenceRule(Recurrence *);
58 icalproperty *writeAlarm(Alarm *alarm);
59
60 QString extractErrorProperty(icalcomponent *);
61 Todo *readTodo(icalcomponent *vtodo);
62 Event *readEvent(icalcomponent *vevent);
63 FreeBusy *readFreeBusy(icalcomponent *vfreebusy);
64 Journal *readJournal(icalcomponent *vjournal);
65 Attendee *readAttendee(icalproperty *attendee);
66 Attachment *readAttachment(icalproperty *attach);
67 void readIncidence(icalcomponent *parent,Incidence *incidence);
68 void readRecurrenceRule(icalproperty *rrule,Incidence *event);
69 void readRecurrence( const struct icalrecurrencetype &r, Recurrence* recur );
70 void readAlarm(icalcomponent *alarm,Incidence *incidence);
71 /** Return the PRODID string loaded from calendar file */
72 const QString &loadedProductId() { return mLoadedProductId; }
73
74 icaltimetype writeICalDate(const QDate &);
75 QDate readICalDate(icaltimetype);
76 icaltimetype writeICalDateTime(const QDateTime &);
77 QDateTime readICalDateTime(icaltimetype);
78 icaldurationtype writeICalDuration(int seconds);
79 int readICalDuration(icaldurationtype);
80 icalcomponent *createCalendarComponent(Calendar * = 0);
81 icalcomponent *createScheduleComponent(IncidenceBase *,Scheduler::Method);
82
83 private:
84 void writeIncidenceBase(icalcomponent *parent,IncidenceBase *);
85 void readIncidenceBase(icalcomponent *parent,IncidenceBase *);
86 void writeCustomProperties(icalcomponent *parent,CustomProperties *);
87 void readCustomProperties(icalcomponent *parent,CustomProperties *);
88 void dumpIcalRecurrence(icalrecurrencetype);
89
90 ICalFormat *mParent;
91 Calendar *mCalendar;
92
93 QString mLoadedProductId; // PRODID string loaded from calendar file
94 int mCalendarVersion; // determines backward compatibility mode on read
95
96 QPtrList<Event> mEventsRelate; // events with relations
97 QPtrList<Todo> mTodosRelate; // todos with relations
98
99 static const int mSecondsPerWeek;
100 static const int mSecondsPerDay;
101 static const int mSecondsPerHour;
102 static const int mSecondsPerMinute;
103
104 Compat *mCompat;
105};
106
107}
108
109#endif
diff --git a/libkcal/imipscheduler.cpp b/libkcal/imipscheduler.cpp
new file mode 100644
index 0000000..e186f8e
--- a/dev/null
+++ b/libkcal/imipscheduler.cpp
@@ -0,0 +1,58 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21//
22// IMIPScheduler - iMIP implementation of iTIP methods
23//
24
25#include "event.h"
26#include "icalformat.h"
27
28#include "imipscheduler.h"
29
30using namespace KCal;
31
32IMIPScheduler::IMIPScheduler(Calendar *calendar)
33 : Scheduler(calendar)
34{
35}
36
37IMIPScheduler::~IMIPScheduler()
38{
39}
40
41bool IMIPScheduler::publish (IncidenceBase *incidence,const QString &recipients)
42{
43 return false;
44}
45
46bool IMIPScheduler::performTransaction(IncidenceBase *incidence,Method method)
47{
48 mFormat->createScheduleMessage(incidence,method);
49
50 return false;
51}
52
53QPtrList<ScheduleMessage> IMIPScheduler::retrieveTransactions()
54{
55 QPtrList<ScheduleMessage> messageList;
56
57 return messageList;
58}
diff --git a/libkcal/imipscheduler.h b/libkcal/imipscheduler.h
new file mode 100644
index 0000000..f142060
--- a/dev/null
+++ b/libkcal/imipscheduler.h
@@ -0,0 +1,49 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef IMIPSCHEDULER_H
21#define IMIPSCHEDULER_H
22//
23// iMIP implementation of iTIP methods
24//
25
26#include <qptrlist.h>
27
28#include "scheduler.h"
29
30namespace KCal {
31
32/*
33 This class implements the iTIP interface using the email interface specified
34 as iMIP.
35*/
36class IMIPScheduler : public Scheduler {
37 public:
38 IMIPScheduler(Calendar *);
39 virtual ~IMIPScheduler();
40
41 bool publish (IncidenceBase *incidence,const QString &recipients);
42 bool performTransaction(IncidenceBase *incidence,Method method);
43 QPtrList<ScheduleMessage> retrieveTransactions();
44};
45
46}
47
48#endif // IMIPSCHEDULER_H
49
diff --git a/libkcal/incidence.cpp b/libkcal/incidence.cpp
new file mode 100644
index 0000000..d9bda64
--- a/dev/null
+++ b/libkcal/incidence.cpp
@@ -0,0 +1,594 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <kglobal.h>
22#include <klocale.h>
23#include <kdebug.h>
24
25#include "calformat.h"
26
27#include "incidence.h"
28#include "todo.h"
29
30using namespace KCal;
31
32Incidence::Incidence() :
33 IncidenceBase(),
34 mRelatedTo(0), mSecrecy(SecrecyPublic), mPriority(3)
35{
36 mRecurrence = new Recurrence(this);
37 mCancelled = false;
38 recreate();
39 mHasStartDate = true;
40 mAlarms.setAutoDelete(true);
41 mAttachments.setAutoDelete(true);
42}
43
44Incidence::Incidence( const Incidence &i ) : IncidenceBase( i )
45{
46// TODO: reenable attributes currently commented out.
47 mRevision = i.mRevision;
48 mCreated = i.mCreated;
49 mDescription = i.mDescription;
50 mSummary = i.mSummary;
51 mCategories = i.mCategories;
52// Incidence *mRelatedTo; Incidence *mRelatedTo;
53 mRelatedTo = 0;
54 mRelatedToUid = i.mRelatedToUid;
55// QPtrList<Incidence> mRelations; QPtrList<Incidence> mRelations;
56 mExDates = i.mExDates;
57 mAttachments = i.mAttachments;
58 mResources = i.mResources;
59 mSecrecy = i.mSecrecy;
60 mPriority = i.mPriority;
61 mLocation = i.mLocation;
62 mCancelled = i.mCancelled;
63 mHasStartDate = i.mHasStartDate;
64 QPtrListIterator<Alarm> it( i.mAlarms );
65 const Alarm *a;
66 while( (a = it.current()) ) {
67 Alarm *b = new Alarm( *a );
68 b->setParent( this );
69 mAlarms.append( b );
70
71 ++it;
72 }
73 mAlarms.setAutoDelete(true);
74
75 mRecurrence = new Recurrence( *(i.mRecurrence), this );
76}
77
78Incidence::~Incidence()
79{
80
81 Incidence *ev;
82 QPtrList<Incidence> Relations = relations();
83 for (ev=Relations.first();ev;ev=Relations.next()) {
84 if (ev->relatedTo() == this) ev->setRelatedTo(0);
85 }
86 if (relatedTo()) relatedTo()->removeRelation(this);
87 delete mRecurrence;
88
89}
90
91bool Incidence::cancelled() const
92{
93 return mCancelled;
94}
95void Incidence::setCancelled( bool b )
96{
97 mCancelled = b;
98 updated();
99}
100bool Incidence::hasStartDate() const
101{
102 return mHasStartDate;
103}
104
105void Incidence::setHasStartDate(bool f)
106{
107 if (mReadOnly) return;
108 mHasStartDate = f;
109 updated();
110}
111
112// A string comparison that considers that null and empty are the same
113static bool stringCompare( const QString& s1, const QString& s2 )
114{
115 if ( s1.isEmpty() && s2.isEmpty() )
116 return true;
117 return s1 == s2;
118}
119
120bool KCal::operator==( const Incidence& i1, const Incidence& i2 )
121{
122
123 if( i1.alarms().count() != i2.alarms().count() ) {
124 return false; // no need to check further
125 }
126 if ( i1.alarms().count() > 0 ) {
127 if ( !( *(i1.alarms().first()) == *(i2.alarms().first())) )
128 {
129 qDebug("alarm not equal ");
130 return false;
131 }
132 }
133#if 0
134 QPtrListIterator<Alarm> a1( i1.alarms() );
135 QPtrListIterator<Alarm> a2( i2.alarms() );
136 for( ; a1.current() && a2.current(); ++a1, ++a2 ) {
137 if( *a1.current() == *a2.current() ) {
138 continue;
139 }
140 else {
141 return false;
142 }
143 }
144#endif
145
146 if ( ! operator==( (const IncidenceBase&)i1, (const IncidenceBase&)i2 ) )
147 return false;
148 if ( i1.hasStartDate() == i2.hasStartDate() ) {
149 if ( i1.hasStartDate() ) {
150 if ( i1.dtStart() != i2.dtStart() )
151 return false;
152 }
153 } else {
154 return false;
155 }
156 if (!( *i1.recurrence() == *i2.recurrence()) ) {
157 qDebug("recurrence is NOT equal ");
158 return false;
159 }
160 return
161 // i1.created() == i2.created() &&
162 stringCompare( i1.description(), i2.description() ) &&
163 stringCompare( i1.summary(), i2.summary() ) &&
164 i1.categories() == i2.categories() &&
165 // no need to compare mRelatedTo
166 stringCompare( i1.relatedToUid(), i2.relatedToUid() ) &&
167 // i1.relations() == i2.relations() &&
168 i1.exDates() == i2.exDates() &&
169 i1.attachments() == i2.attachments() &&
170 i1.resources() == i2.resources() &&
171 i1.secrecy() == i2.secrecy() &&
172 i1.priority() == i2.priority() &&
173 stringCompare( i1.location(), i2.location() );
174}
175
176
177void Incidence::recreate()
178{
179 setCreated(QDateTime::currentDateTime());
180
181 setUid(CalFormat::createUniqueId());
182
183 setRevision(0);
184
185 setLastModified(QDateTime::currentDateTime());
186}
187
188void Incidence::setReadOnly( bool readOnly )
189{
190 IncidenceBase::setReadOnly( readOnly );
191 recurrence()->setRecurReadOnly( readOnly);
192}
193
194void Incidence::setCreated(QDateTime created)
195{
196 if (mReadOnly) return;
197 mCreated = getEvenTime(created);
198}
199
200QDateTime Incidence::created() const
201{
202 return mCreated;
203}
204
205void Incidence::setRevision(int rev)
206{
207 if (mReadOnly) return;
208 mRevision = rev;
209
210 updated();
211}
212
213int Incidence::revision() const
214{
215 return mRevision;
216}
217
218void Incidence::setDtStart(const QDateTime &dtStart)
219{
220
221 QDateTime dt = getEvenTime(dtStart);
222 recurrence()->setRecurStart( dt);
223 IncidenceBase::setDtStart( dt );
224}
225
226void Incidence::setDescription(const QString &description)
227{
228 if (mReadOnly) return;
229 mDescription = description;
230 updated();
231}
232
233QString Incidence::description() const
234{
235 return mDescription;
236}
237
238
239void Incidence::setSummary(const QString &summary)
240{
241 if (mReadOnly) return;
242 mSummary = summary;
243 updated();
244}
245
246QString Incidence::summary() const
247{
248 return mSummary;
249}
250
251void Incidence::setCategories(const QStringList &categories)
252{
253 if (mReadOnly) return;
254 mCategories = categories;
255 updated();
256}
257
258// TODO: remove setCategories(QString) function
259void Incidence::setCategories(const QString &catStr)
260{
261 if (mReadOnly) return;
262 mCategories.clear();
263
264 if (catStr.isEmpty()) return;
265
266 mCategories = QStringList::split(",",catStr);
267
268 QStringList::Iterator it;
269 for(it = mCategories.begin();it != mCategories.end(); ++it) {
270 *it = (*it).stripWhiteSpace();
271 }
272
273 updated();
274}
275
276QStringList Incidence::categories() const
277{
278 return mCategories;
279}
280
281QString Incidence::categoriesStr()
282{
283 return mCategories.join(",");
284}
285
286void Incidence::setRelatedToUid(const QString &relatedToUid)
287{
288 if (mReadOnly) return;
289 mRelatedToUid = relatedToUid;
290}
291
292QString Incidence::relatedToUid() const
293{
294 return mRelatedToUid;
295}
296
297void Incidence::setRelatedTo(Incidence *relatedTo)
298{
299 //qDebug("Incidence::setRelatedTo %d ", relatedTo);
300 //qDebug("setRelatedTo(Incidence *relatedTo) %s %s", summary().latin1(), relatedTo->summary().latin1() );
301 if (mReadOnly || mRelatedTo == relatedTo) return;
302 if(mRelatedTo) {
303 // updated();
304 mRelatedTo->removeRelation(this);
305 }
306 mRelatedTo = relatedTo;
307 if (mRelatedTo) mRelatedTo->addRelation(this);
308}
309
310Incidence *Incidence::relatedTo() const
311{
312 return mRelatedTo;
313}
314
315QPtrList<Incidence> Incidence::relations() const
316{
317 return mRelations;
318}
319
320void Incidence::addRelation(Incidence *event)
321{
322 if( mRelations.findRef( event ) == -1 ) {
323 mRelations.append(event);
324 //updated();
325 }
326}
327
328void Incidence::removeRelation(Incidence *event)
329{
330
331 mRelations.removeRef(event);
332
333// if (event->getRelatedTo() == this) event->setRelatedTo(0);
334}
335
336bool Incidence::recursOn(const QDate &qd) const
337{
338 if (recurrence()->recursOnPure(qd) && !isException(qd)) return true;
339 else return false;
340}
341
342void Incidence::setExDates(const DateList &exDates)
343{
344 if (mReadOnly) return;
345 mExDates = exDates;
346
347 recurrence()->setRecurExDatesCount(mExDates.count());
348
349 updated();
350}
351
352void Incidence::addExDate(const QDate &date)
353{
354 if (mReadOnly) return;
355 mExDates.append(date);
356
357 recurrence()->setRecurExDatesCount(mExDates.count());
358
359 updated();
360}
361
362DateList Incidence::exDates() const
363{
364 return mExDates;
365}
366
367bool Incidence::isException(const QDate &date) const
368{
369 DateList::ConstIterator it;
370 for( it = mExDates.begin(); it != mExDates.end(); ++it ) {
371 if ( (*it) == date ) {
372 return true;
373 }
374 }
375
376 return false;
377}
378
379void Incidence::addAttachment(Attachment *attachment)
380{
381 if (mReadOnly || !attachment) return;
382 mAttachments.append(attachment);
383 updated();
384}
385
386void Incidence::deleteAttachment(Attachment *attachment)
387{
388 mAttachments.removeRef(attachment);
389}
390
391void Incidence::deleteAttachments(const QString& mime)
392{
393 Attachment *at = mAttachments.first();
394 while (at) {
395 if (at->mimeType() == mime)
396 mAttachments.remove();
397 else
398 at = mAttachments.next();
399 }
400}
401
402QPtrList<Attachment> Incidence::attachments() const
403{
404 return mAttachments;
405}
406
407QPtrList<Attachment> Incidence::attachments(const QString& mime) const
408{
409 QPtrList<Attachment> attachments;
410 QPtrListIterator<Attachment> it( mAttachments );
411 Attachment *at;
412 while ( (at = it.current()) ) {
413 if (at->mimeType() == mime)
414 attachments.append(at);
415 ++it;
416 }
417
418 return attachments;
419}
420
421void Incidence::setResources(const QStringList &resources)
422{
423 if (mReadOnly) return;
424 mResources = resources;
425 updated();
426}
427
428QStringList Incidence::resources() const
429{
430 return mResources;
431}
432
433
434void Incidence::setPriority(int priority)
435{
436 if (mReadOnly) return;
437 mPriority = priority;
438 updated();
439}
440
441int Incidence::priority() const
442{
443 return mPriority;
444}
445
446void Incidence::setSecrecy(int sec)
447{
448 if (mReadOnly) return;
449 mSecrecy = sec;
450 updated();
451}
452
453int Incidence::secrecy() const
454{
455 return mSecrecy;
456}
457
458QString Incidence::secrecyStr() const
459{
460 return secrecyName(mSecrecy);
461}
462
463QString Incidence::secrecyName(int secrecy)
464{
465 switch (secrecy) {
466 case SecrecyPublic:
467 return i18n("Public");
468 break;
469 case SecrecyPrivate:
470 return i18n("Private");
471 break;
472 case SecrecyConfidential:
473 return i18n("Confidential");
474 break;
475 default:
476 return i18n("Undefined");
477 break;
478 }
479}
480
481QStringList Incidence::secrecyList()
482{
483 QStringList list;
484 list << secrecyName(SecrecyPublic);
485 list << secrecyName(SecrecyPrivate);
486 list << secrecyName(SecrecyConfidential);
487
488 return list;
489}
490
491
492QPtrList<Alarm> Incidence::alarms() const
493{
494 return mAlarms;
495}
496
497Alarm* Incidence::newAlarm()
498{
499 Alarm* alarm = new Alarm(this);
500 mAlarms.append(alarm);
501// updated();
502 return alarm;
503}
504
505void Incidence::addAlarm(Alarm *alarm)
506{
507 mAlarms.append(alarm);
508 updated();
509}
510
511void Incidence::removeAlarm(Alarm *alarm)
512{
513 mAlarms.removeRef(alarm);
514 updated();
515}
516
517void Incidence::clearAlarms()
518{
519 mAlarms.clear();
520 updated();
521}
522
523bool Incidence::isAlarmEnabled() const
524{
525 Alarm* alarm;
526 for (QPtrListIterator<Alarm> it(mAlarms); (alarm = it.current()) != 0; ++it) {
527 if (alarm->enabled())
528 return true;
529 }
530 return false;
531}
532
533Recurrence *Incidence::recurrence() const
534{
535 return mRecurrence;
536}
537
538void Incidence::setLocation(const QString &location)
539{
540 if (mReadOnly) return;
541 mLocation = location;
542 updated();
543}
544
545QString Incidence::location() const
546{
547 return mLocation;
548}
549
550ushort Incidence::doesRecur() const
551{
552 if ( mRecurrence ) return mRecurrence->doesRecur();
553 else return Recurrence::rNone;
554}
555
556QDateTime Incidence::getNextOccurence( const QDateTime& dt, bool* ok ) const
557{
558 QDateTime incidenceStart = dt;
559 *ok = false;
560 if ( doesRecur() ) {
561 bool last;
562 recurrence()->getPreviousDateTime( incidenceStart , &last );
563 int count = 0;
564 if ( !last ) {
565 while ( !last ) {
566 ++count;
567 incidenceStart = recurrence()->getNextDateTime( incidenceStart, &last );
568 if ( recursOn( incidenceStart.date() ) ) {
569 last = true; // exit while llop
570 } else {
571 if ( last ) { // no alarm on last recurrence
572 return QDateTime ();
573 }
574 int year = incidenceStart.date().year();
575 // workaround for bug in recurrence
576 if ( count == 100 || year < 1980 || year > 5000 ) {
577 return QDateTime ();
578 }
579 incidenceStart = incidenceStart.addSecs( 1 );
580 }
581 }
582 } else {
583 return QDateTime ();
584 }
585 } else {
586 if ( hasStartDate () ) {
587 incidenceStart = dtStart();
588
589 }
590 }
591 if ( incidenceStart > dt )
592 *ok = true;
593 return incidenceStart;
594}
diff --git a/libkcal/incidence.h b/libkcal/incidence.h
new file mode 100644
index 0000000..d1972cb
--- a/dev/null
+++ b/libkcal/incidence.h
@@ -0,0 +1,298 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef INCIDENCE_H
21#define INCIDENCE_H
22//
23// Incidence - base class of calendaring components
24//
25
26#include <qdatetime.h>
27#include <qstringlist.h>
28#include <qvaluelist.h>
29
30#include "recurrence.h"
31#include "alarm.h"
32#include "attachment.h"
33#include "listbase.h"
34#include "incidencebase.h"
35
36namespace KCal {
37
38class Event;
39class Todo;
40class Journal;
41
42/**
43 This class provides the base class common to all calendar components.
44*/
45class Incidence : public IncidenceBase
46{
47 public:
48 /**
49 This class provides the interface for a visitor of calendar components. It
50 serves as base class for concrete visitors, which implement certain actions on
51 calendar components. It allows to add functions, which operate on the concrete
52 types of calendar components, without changing the calendar component classes.
53 */
54 class Visitor
55 {
56 public:
57 /** Destruct Incidence::Visitor */
58 virtual ~Visitor() {}
59
60 /**
61 Reimplement this function in your concrete subclass of IncidenceVisitor to perform actions
62 on an Event object.
63 */
64 virtual bool visit(Event *) { return false; }
65 /**
66 Reimplement this function in your concrete subclass of IncidenceVisitor to perform actions
67 on an Todo object.
68 */
69 virtual bool visit(Todo *) { return false; }
70 /**
71 Reimplement this function in your concrete subclass of IncidenceVisitor to perform actions
72 on an Journal object.
73 */
74 virtual bool visit(Journal *) { return false; }
75
76 protected:
77 /** Constructor is protected to prevent direct creation of visitor base class. */
78 Visitor() {}
79 };
80
81 /**
82 This class implements a visitor for adding an Incidence to a resource
83 supporting addEvent(), addTodo() and addJournal() calls.
84 */
85 template<class T>
86 class AddVisitor : public Visitor
87 {
88 public:
89 AddVisitor( T *r ) : mResource( r ) {}
90 bool visit( Event *e ) { return mResource->addEvent( e ); }
91 bool visit( Todo *t ) { return mResource->addTodo( t ); }
92 bool visit( Journal *j ) { return mResource->addJournal( j ); }
93
94 private:
95 T *mResource;
96 };
97
98 /** enumeration for describing an event's secrecy. */
99 enum { SecrecyPublic = 0, SecrecyPrivate = 1, SecrecyConfidential = 2 };
100 typedef ListBase<Incidence> List;
101 Incidence();
102 Incidence(const Incidence &);
103 ~Incidence();
104
105 /**
106 Accept IncidenceVisitor. A class taking part in the visitor mechanism has to
107 provide this implementation:
108 <pre>
109 bool accept(Visitor &v) { return v.visit(this); }
110 </pre>
111 */
112 virtual bool accept(Visitor &) { return false; }
113
114 virtual Incidence *clone() = 0;
115
116 virtual QDateTime getNextAlarmDateTime( bool * ok, int * offset ) const = 0;
117 void setReadOnly( bool );
118
119 /**
120 Recreate event. The event is made a new unique event, but already stored
121 event information is preserved. Sets uniquie id, creation date, last
122 modification date and revision number.
123 */
124 void recreate();
125
126 /** set creation date */
127 void setCreated(QDateTime);
128 /** return time and date of creation. */
129 QDateTime created() const;
130
131 /** set the number of revisions this event has seen */
132 void setRevision(int rev);
133 /** return the number of revisions this event has seen */
134 int revision() const;
135
136 /** Set starting date/time. */
137 virtual void setDtStart(const QDateTime &dtStart);
138 /** Return the incidence's ending date/time as a QDateTime. */
139 virtual QDateTime dtEnd() const { return QDateTime(); }
140
141 /** sets the event's lengthy description. */
142 void setDescription(const QString &description);
143 /** returns a reference to the event's description. */
144 QString description() const;
145
146 /** sets the event's short summary. */
147 void setSummary(const QString &summary);
148 /** returns a reference to the event's summary. */
149 QString summary() const;
150
151 /** set event's applicable categories */
152 void setCategories(const QStringList &categories);
153 /** set event's categories based on a comma delimited string */
154 void setCategories(const QString &catStr);
155 /** return categories in a list */
156 QStringList categories() const;
157 /** return categories as a comma separated string */
158 QString categoriesStr();
159
160 /** point at some other event to which the event relates. This function should
161 * only be used when constructing a calendar before the related Event
162 * exists. */
163 void setRelatedToUid(const QString &);
164 /** what event does this one relate to? This function should
165 * only be used when constructing a calendar before the related Event
166 * exists. */
167 QString relatedToUid() const;
168 /** point at some other event to which the event relates */
169 void setRelatedTo(Incidence *relatedTo);
170 /** what event does this one relate to? */
171 Incidence *relatedTo() const;
172 /** All events that are related to this event */
173 QPtrList<Incidence> relations() const;
174 /** Add an event which is related to this event */
175 void addRelation(Incidence *);
176 /** Remove event that is related to this event */
177 void removeRelation(Incidence *);
178
179 /** returns the list of dates which are exceptions to the recurrence rule */
180 DateList exDates() const;
181 /** sets the list of dates which are exceptions to the recurrence rule */
182 void setExDates(const DateList &_exDates);
183 void setExDates(const char *dates);
184 /** Add a date to the list of exceptions of the recurrence rule. */
185 void addExDate(const QDate &date);
186
187 /** returns true if there is an exception for this date in the recurrence
188 rule set, or false otherwise. */
189 bool isException(const QDate &qd) const;
190
191 /** add attachment to this event */
192 void addAttachment(Attachment *attachment);
193 /** remove and delete a specific attachment */
194 void deleteAttachment(Attachment *attachment);
195 /** remove and delete all attachments with this mime type */
196 void deleteAttachments(const QString& mime);
197 /** return list of all associated attachments */
198 QPtrList<Attachment> attachments() const;
199 /** find a list of attachments with this mime type */
200 QPtrList<Attachment> attachments(const QString& mime) const;
201
202 /** sets the event's status the value specified. See the enumeration
203 * above for possible values. */
204 void setSecrecy(int);
205 /** return the event's secrecy. */
206 int secrecy() const;
207 /** return the event's secrecy in string format. */
208 QString secrecyStr() const;
209 /** return list of all availbale secrecy classes */
210 static QStringList secrecyList();
211 /** return human-readable name of secrecy class */
212 static QString secrecyName(int);
213
214 /** returns TRUE if the date specified is one on which the event will
215 * recur. */
216 bool recursOn(const QDate &qd) const;
217
218 // VEVENT and VTODO, but not VJOURNAL (move to EventBase class?):
219
220 /** set resources used, such as Office, Car, etc. */
221 void setResources(const QStringList &resources);
222 /** return list of current resources */
223 QStringList resources() const;
224
225 /** set the event's priority, 0 is undefined, 1 highest (decreasing order) */
226 void setPriority(int priority);
227 /** get the event's priority */
228 int priority() const;
229
230 /** All alarms that are associated with this incidence */
231 QPtrList<Alarm> alarms() const;
232 /** Create a new alarm which is associated with this incidence */
233 Alarm* newAlarm();
234 /** Add an alarm which is associated with this incidence */
235 void addAlarm(Alarm*);
236 /** Remove an alarm that is associated with this incidence */
237 void removeAlarm(Alarm*);
238 /** Remove all alarms that are associated with this incidence */
239 void clearAlarms();
240 /** return whether any alarm associated with this incidence is enabled */
241 bool isAlarmEnabled() const;
242
243 /**
244 Return the recurrence rule associated with this incidence. If there is
245 none, returns an appropriate (non-0) object.
246 */
247 Recurrence *recurrence() const;
248
249 /**
250 Forward to Recurrence::doesRecur().
251 */
252 ushort doesRecur() const;
253
254 /** set the event's/todo's location. Do _not_ use it with journal */
255 void setLocation(const QString &location);
256 /** return the event's/todo's location. Do _not_ use it with journal */
257 QString location() const;
258 /** returns TRUE or FALSE depending on whether the todo has a start date */
259 bool hasStartDate() const;
260 /** sets the event's hasStartDate value. */
261 void setHasStartDate(bool f);
262 QDateTime getNextOccurence( const QDateTime& dt, bool* yes ) const;
263 bool cancelled() const;
264 void setCancelled( bool b );
265
266protected:
267 QPtrList<Alarm> mAlarms;
268 private:
269 int mRevision;
270 bool mCancelled;
271
272 // base components of jounal, event and todo
273 QDateTime mCreated;
274 QString mDescription;
275 QString mSummary;
276 QStringList mCategories;
277 Incidence *mRelatedTo;
278 QString mRelatedToUid;
279 QPtrList<Incidence> mRelations;
280 DateList mExDates;
281 QPtrList<Attachment> mAttachments;
282 QStringList mResources;
283 bool mHasStartDate; // if todo has associated start date
284
285 int mSecrecy;
286 int mPriority; // 1 = highest, 2 = less, etc.
287
288 //QPtrList<Alarm> mAlarms;
289 Recurrence *mRecurrence;
290
291 QString mLocation;
292};
293
294bool operator==( const Incidence&, const Incidence& );
295
296}
297
298#endif
diff --git a/libkcal/incidencebase.cpp b/libkcal/incidencebase.cpp
new file mode 100644
index 0000000..9479048
--- a/dev/null
+++ b/libkcal/incidencebase.cpp
@@ -0,0 +1,393 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <kglobal.h>
22#include <klocale.h>
23#include <kdebug.h>
24
25#include "calformat.h"
26
27#include "incidencebase.h"
28
29using namespace KCal;
30
31IncidenceBase::IncidenceBase() :
32 mReadOnly(false), mFloats(true), mDuration(0), mHasDuration(false),
33 mPilotId(0), mSyncStatus(SYNCMOD)
34{
35 setUid(CalFormat::createUniqueId());
36 mOrganizer = "";
37 mFloats = false;
38 mDuration = 0;
39 mHasDuration = false;
40 mPilotId = 0;
41 mZaurusId = -1;
42 mZaurusUid = 0;
43 mZaurusStat = 0;
44 mSyncStatus = 0;
45 mAttendees.setAutoDelete( true );
46}
47
48IncidenceBase::IncidenceBase(const IncidenceBase &i) :
49 CustomProperties( i )
50{
51 mReadOnly = i.mReadOnly;
52 mDtStart = i.mDtStart;
53 mDuration = i.mDuration;
54 mHasDuration = i.mHasDuration;
55 mOrganizer = i.mOrganizer;
56 mUid = i.mUid;
57 QPtrList<Attendee> attendees = i.attendees();
58 for( Attendee *a = attendees.first(); a; a = attendees.next() ) {
59 mAttendees.append( new Attendee( *a ) );
60 }
61 mFloats = i.mFloats;
62 mLastModified = i.mLastModified;
63 mPilotId = i.mPilotId;
64 mZaurusId = i.mZaurusId;
65 mZaurusUid = i.mZaurusUid;
66 mZaurusStat = i.mZaurusStat;
67 mSyncStatus = i.mSyncStatus;
68
69 // The copied object is a new one, so it isn't observed by the observer
70 // of the original object.
71 mObservers.clear();
72
73 mAttendees.setAutoDelete( true );
74}
75
76IncidenceBase::~IncidenceBase()
77{
78}
79
80
81bool KCal::operator==( const IncidenceBase& i1, const IncidenceBase& i2 )
82{
83
84 if( i1.attendees().count() != i2.attendees().count() ) {
85 return false; // no need to check further
86 }
87 if ( i1.attendees().count() > 0 ) {
88 Attendee * a1 = i1.attendees().first(), *a2 =i2.attendees().first() ;
89 while ( a1 ) {
90 if ( !( (*a1) == (*a2)) )
91 {
92 //qDebug("Attendee not equal ");
93 return false;
94 }
95 a1 = i1.attendees().next();
96 a2 = i2.attendees().next();
97 }
98 }
99 //if ( i1.dtStart() != i2.dtStart() )
100 // return false;
101#if 0
102 qDebug("1 %d ",i1.doesFloat() == i2.doesFloat() );
103 qDebug("1 %d ",i1.duration() == i2.duration() );
104 qDebug("3 %d ",i1.hasDuration() == i2.hasDuration() );
105 qDebug("1 %d ",i1.pilotId() == i2.pilotId() );
106 qDebug("1 %d %d %d",i1.syncStatus() == i2.syncStatus() , i1.syncStatus(),i2.syncStatus() );
107 qDebug("6 %d ",i1.organizer() == i2.organizer() );
108
109#endif
110 return ( i1.organizer() == i2.organizer() &&
111 // i1.uid() == i2.uid() &&
112 // Don't compare lastModified, otherwise the operator is not
113 // of much use. We are not comparing for identity, after all.
114 i1.doesFloat() == i2.doesFloat() &&
115 i1.duration() == i2.duration() &&
116 i1.hasDuration() == i2.hasDuration() &&
117 i1.pilotId() == i2.pilotId() );// && i1.syncStatus() == i2.syncStatus() );
118 // no need to compare mObserver
119}
120
121
122QDateTime IncidenceBase::getEvenTime( QDateTime dt )
123{
124 QTime t = dt.time();
125 dt.setTime( QTime (t.hour (), t.minute (), t.second () ) );
126 return dt;
127}
128
129
130void IncidenceBase::setUid(const QString &uid)
131{
132 mUid = uid;
133 updated();
134}
135
136QString IncidenceBase::uid() const
137{
138 return mUid;
139}
140
141void IncidenceBase::setLastModified(const QDateTime &lm)
142{
143 // DON'T! updated() because we call this from
144 // Calendar::updateEvent().
145 mLastModified = getEvenTime(lm);
146 //qDebug("IncidenceBase::setLastModified %s ",lm.toString().latin1());
147}
148
149QDateTime IncidenceBase::lastModified() const
150{
151 return mLastModified;
152}
153
154void IncidenceBase::setOrganizer(const QString &o)
155{
156 // we don't check for readonly here, because it is
157 // possible that by setting the organizer we are changing
158 // the event's readonly status...
159 mOrganizer = o;
160 if (mOrganizer.left(7).upper() == "MAILTO:")
161 mOrganizer = mOrganizer.remove(0,7);
162
163 updated();
164}
165
166QString IncidenceBase::organizer() const
167{
168 return mOrganizer;
169}
170
171void IncidenceBase::setReadOnly( bool readOnly )
172{
173 mReadOnly = readOnly;
174}
175
176void IncidenceBase::setDtStart(const QDateTime &dtStart)
177{
178// if (mReadOnly) return;
179 mDtStart = getEvenTime(dtStart);
180 updated();
181}
182
183QDateTime IncidenceBase::dtStart() const
184{
185 return mDtStart;
186}
187
188QString IncidenceBase::dtStartTimeStr() const
189{
190 return KGlobal::locale()->formatTime(dtStart().time());
191}
192
193QString IncidenceBase::dtStartDateStr(bool shortfmt) const
194{
195 return KGlobal::locale()->formatDate(dtStart().date(),shortfmt);
196}
197
198QString IncidenceBase::dtStartStr(bool shortfmt) const
199{
200 return KGlobal::locale()->formatDateTime(dtStart(), shortfmt);
201}
202
203
204bool IncidenceBase::doesFloat() const
205{
206 return mFloats;
207}
208
209void IncidenceBase::setFloats(bool f)
210{
211 if (mReadOnly) return;
212 mFloats = f;
213 updated();
214}
215
216
217void IncidenceBase::addAttendee(Attendee *a, bool doupdate)
218{
219 if (mReadOnly) return;
220 if (a->name().left(7).upper() == "MAILTO:")
221 a->setName(a->name().remove(0,7));
222
223 mAttendees.append(a);
224 if (doupdate) updated();
225}
226
227#if 0
228void IncidenceBase::removeAttendee(Attendee *a)
229{
230 if (mReadOnly) return;
231 mAttendees.removeRef(a);
232 updated();
233}
234
235void IncidenceBase::removeAttendee(const char *n)
236{
237 Attendee *a;
238
239 if (mReadOnly) return;
240 for (a = mAttendees.first(); a; a = mAttendees.next())
241 if (a->getName() == n) {
242 mAttendees.remove();
243 break;
244 }
245}
246#endif
247
248void IncidenceBase::clearAttendees()
249{
250 if (mReadOnly) return;
251 mAttendees.clear();
252}
253
254#if 0
255Attendee *IncidenceBase::getAttendee(const char *n) const
256{
257 QPtrListIterator<Attendee> qli(mAttendees);
258
259 qli.toFirst();
260 while (qli) {
261 if (qli.current()->getName() == n)
262 return qli.current();
263 ++qli;
264 }
265 return 0L;
266}
267#endif
268
269Attendee *IncidenceBase::attendeeByMail(const QString &email)
270{
271 QPtrListIterator<Attendee> qli(mAttendees);
272
273 qli.toFirst();
274 while (qli) {
275 if (qli.current()->email() == email)
276 return qli.current();
277 ++qli;
278 }
279 return 0L;
280}
281
282Attendee *IncidenceBase::attendeeByMails(const QStringList &emails, const QString& email)
283{
284 QPtrListIterator<Attendee> qli(mAttendees);
285
286 QStringList mails = emails;
287 if (!email.isEmpty()) {
288 mails.append(email);
289 }
290 qli.toFirst();
291 while (qli) {
292 for ( QStringList::Iterator it = mails.begin(); it != mails.end(); ++it ) {
293 if (qli.current()->email() == *it)
294 return qli.current();
295 }
296
297 ++qli;
298 }
299 return 0L;
300}
301
302void IncidenceBase::setDuration(int seconds)
303{
304 mDuration = seconds;
305 setHasDuration(true);
306}
307
308int IncidenceBase::duration() const
309{
310 return mDuration;
311}
312
313void IncidenceBase::setHasDuration(bool b)
314{
315 mHasDuration = b;
316}
317
318bool IncidenceBase::hasDuration() const
319{
320 return mHasDuration;
321}
322
323void IncidenceBase::setSyncStatus(int stat)
324{
325 if (mReadOnly) return;
326 mSyncStatus = stat;
327}
328
329int IncidenceBase::syncStatus() const
330{
331 return mSyncStatus;
332}
333
334void IncidenceBase::setPilotId( int id )
335{
336 if (mReadOnly) return;
337 mPilotId = id;
338}
339
340int IncidenceBase::pilotId() const
341{
342 return mPilotId;
343}
344void IncidenceBase::setZaurusId( int id )
345{
346 if (mReadOnly) return;
347 mZaurusId = id;
348}
349
350int IncidenceBase::zaurusId() const
351{
352 return mZaurusId;
353}
354
355int IncidenceBase::zaurusUid() const
356{
357 return mZaurusUid;
358}
359void IncidenceBase::setZaurusUid( int id )
360{
361 if (mReadOnly) return;
362 mZaurusUid = id;
363}
364
365int IncidenceBase::zaurusStat() const
366{
367 return mZaurusStat;
368}
369void IncidenceBase::setZaurusStat( int id )
370{
371 if (mReadOnly) return;
372 mZaurusStat = id;
373}
374
375void IncidenceBase::registerObserver( IncidenceBase::Observer *observer )
376{
377 if( !mObservers.contains(observer) ) mObservers.append( observer );
378}
379
380void IncidenceBase::unRegisterObserver( IncidenceBase::Observer *observer )
381{
382 mObservers.remove( observer );
383}
384
385void IncidenceBase::updated()
386{
387 QPtrListIterator<Observer> it(mObservers);
388 while( it.current() ) {
389 Observer *o = it.current();
390 ++it;
391 o->incidenceUpdated( this );
392 }
393}
diff --git a/libkcal/incidencebase.h b/libkcal/incidencebase.h
new file mode 100644
index 0000000..0ab7eef
--- a/dev/null
+++ b/libkcal/incidencebase.h
@@ -0,0 +1,170 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef KCAL_INCIDENCEBASE_H
21#define KCAL_INCIDENCEBASE_H
22//
23// Incidence - base class of calendaring components
24//
25
26#include <qdatetime.h>
27#include <qstringlist.h>
28#include <qvaluelist.h>
29#include <qptrlist.h>
30
31#include "customproperties.h"
32#include "attendee.h"
33
34namespace KCal {
35
36typedef QValueList<QDate> DateList;
37
38/**
39 This class provides the base class common to all calendar components.
40*/
41class IncidenceBase : public CustomProperties
42{
43 public:
44 class Observer {
45 public:
46 virtual void incidenceUpdated( IncidenceBase * ) = 0;
47 };
48
49 IncidenceBase();
50 IncidenceBase(const IncidenceBase &);
51 virtual ~IncidenceBase();
52
53 virtual QCString type() const = 0;
54
55 /** Set the unique id for the event */
56 void setUid(const QString &);
57 /** Return the unique id for the event */
58 QString uid() const;
59
60 /** Sets the time the incidence was last modified. */
61 void setLastModified(const QDateTime &lm);
62 /** Return the time the incidence was last modified. */
63 QDateTime lastModified() const;
64
65 /** sets the organizer for the event */
66 void setOrganizer(const QString &o);
67 QString organizer() const;
68
69 /** Set readonly status. */
70 virtual void setReadOnly( bool );
71 /** Return if the object is read-only. */
72 bool isReadOnly() const { return mReadOnly; }
73
74 /** for setting the event's starting date/time with a QDateTime. */
75 virtual void setDtStart(const QDateTime &dtStart);
76 /** returns an event's starting date/time as a QDateTime. */
77 QDateTime dtStart() const;
78 /** returns an event's starting time as a string formatted according to the
79 users locale settings */
80 QString dtStartTimeStr() const;
81 /** returns an event's starting date as a string formatted according to the
82 users locale settings */
83 QString dtStartDateStr(bool shortfmt=true) const;
84 /** returns an event's starting date and time as a string formatted according
85 to the users locale settings */
86 QString dtStartStr(bool shortfmt=true) const;
87
88 virtual void setDuration(int seconds);
89 int duration() const;
90 void setHasDuration(bool);
91 bool hasDuration() const;
92
93 /** Return true or false depending on whether the incidence "floats,"
94 * i.e. has a date but no time attached to it. */
95 bool doesFloat() const;
96 /** Set whether the incidence floats, i.e. has a date but no time attached to it. */
97 void setFloats(bool f);
98
99 /**
100 Add Attendee to this incidence. IncidenceBase takes ownership of the
101 Attendee object.
102 */
103 void addAttendee(Attendee *a, bool doupdate=true );
104// void removeAttendee(Attendee *a);
105// void removeAttendee(const char *n);
106 /** Remove all Attendees. */
107 void clearAttendees();
108 /** Return list of attendees. */
109 QPtrList<Attendee> attendees() const { return mAttendees; };
110 /** Return number of attendees. */
111 int attendeeCount() const { return mAttendees.count(); };
112 /** Return the Attendee with this email */
113 Attendee* attendeeByMail(const QString &);
114 /** Return first Attendee with one of this emails */
115 Attendee* attendeeByMails(const QStringList &, const QString& email = QString::null);
116
117 /** pilot syncronization states */
118 enum { SYNCNONE = 0, SYNCMOD = 1, SYNCDEL = 3 };
119 /** Set synchronisation satus. */
120 void setSyncStatus(int stat);
121 /** Return synchronisation status. */
122 int syncStatus() const;
123
124 /** Set Pilot Id. */
125 void setPilotId(int id);
126 /** Return Pilot Id. */
127 int pilotId() const;
128
129 void setZaurusId(int id);
130 int zaurusId() const;
131 void setZaurusUid(int id);
132 int zaurusUid() const;
133 void setZaurusStat(int id);
134 int zaurusStat() const;
135
136 void registerObserver( Observer * );
137 void unRegisterObserver( Observer * );
138 void updated();
139
140 protected:
141 bool mReadOnly;
142 QDateTime getEvenTime( QDateTime );
143
144 private:
145 // base components
146 QDateTime mDtStart;
147 QString mOrganizer;
148 QString mUid;
149 QDateTime mLastModified;
150 QPtrList<Attendee> mAttendees;
151
152 bool mFloats;
153
154 int mDuration;
155 bool mHasDuration;
156 int mZaurusId;
157 int mZaurusUid;
158 int mZaurusStat;
159
160 // PILOT SYNCHRONIZATION STUFF
161 int mPilotId; // unique id for pilot sync
162 int mSyncStatus; // status (for sync)
163
164 QPtrList<Observer> mObservers;
165};
166
167bool operator==( const IncidenceBase&, const IncidenceBase& );
168}
169
170#endif
diff --git a/libkcal/journal.cpp b/libkcal/journal.cpp
new file mode 100644
index 0000000..351fb32
--- a/dev/null
+++ b/libkcal/journal.cpp
@@ -0,0 +1,49 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include "journal.h"
22
23using namespace KCal;
24
25Journal::Journal()
26{
27}
28
29Journal::~Journal()
30{
31}
32
33Incidence *Journal::clone()
34{
35 return new Journal(*this);
36}
37
38
39bool KCal::operator==( const Journal& j1, const Journal& j2 )
40{
41 return operator==( (const Incidence&)j1, (const Incidence&)j2 );
42}
43
44
45QDateTime Journal::getNextAlarmDateTime( bool * ok, int * offset ) const
46{
47 *ok = false;
48 return QDateTime ();
49}
diff --git a/libkcal/journal.h b/libkcal/journal.h
new file mode 100644
index 0000000..cb90c7a
--- a/dev/null
+++ b/libkcal/journal.h
@@ -0,0 +1,50 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef JOURNAL_H
21#define JOURNAL_H
22//
23// Journal component, representing a VJOURNAL object
24//
25
26#include "incidence.h"
27
28namespace KCal {
29
30/**
31 This class provides a Journal in the sense of RFC2445.
32*/
33class Journal : public Incidence
34{
35 public:
36 Journal();
37 ~Journal();
38
39 QCString type() const { return "Journal"; }
40
41 Incidence *clone();
42 QDateTime getNextAlarmDateTime( bool * ok, int * offset ) const;
43private:
44 bool accept(Visitor &v) { return v.visit(this); }
45};
46
47 bool operator==( const Journal&, const Journal& );
48}
49
50#endif
diff --git a/libkcal/kcal.pro.back b/libkcal/kcal.pro.back
new file mode 100644
index 0000000..a33c5f9
--- a/dev/null
+++ b/libkcal/kcal.pro.back
@@ -0,0 +1,84 @@
1 TEMPLATE= lib
2 CONFIG = qt warn_on release
3 TARGET = kcal
4INCLUDEPATH += ../microkde ../qtcompat versit
5INCLUDEPATH += ../libical/src/libical
6INCLUDEPATH += ../libical/src/libicalss
7OBJECTS_DIR = obj/$(PLATFORM)
8MOC_DIR = moc
9DESTDIR = $(QPEDIR)/lib
10LIBS += -lical
11LIBS += -licalss
12
13INTERFACES = \
14
15HEADERS = \
16 alarm.h \
17 attachment.h \
18 attendee.h \
19 calendar.h \
20 calendarlocal.h \
21 calfilter.h \
22 calformat.h \
23 calstorage.h \
24 compat.h \
25 customproperties.h \
26 dummyscheduler.h \
27 duration.h \
28 event.h \
29 exceptions.h \
30 filestorage.h \
31 freebusy.h \
32 icaldrag.h \
33 icalformat.h \
34 icalformatimpl.h \
35 imipscheduler.h \
36 incidence.h \
37 incidencebase.h \
38 journal.h \
39 period.h \
40 person.h \
41 qtopiaformat.h \
42 recurrence.h \
43 scheduler.h \
44 todo.h \
45 vcaldrag.h \
46 vcalformat.h \
47 versit/port.h \
48 versit/vcc.h \
49 versit/vobject.h \
50
51SOURCES = \
52 alarm.cpp \
53 attachment.cpp \
54 attendee.cpp \
55 calendar.cpp \
56 calendarlocal.cpp \
57 calfilter.cpp \
58 calformat.cpp \
59 compat.cpp \
60 customproperties.cpp \
61 dummyscheduler.cpp \
62 duration.cpp \
63 event.cpp \
64 exceptions.cpp \
65 filestorage.cpp \
66 freebusy.cpp \
67 icaldrag.cpp \
68 icalformat.cpp \
69 icalformatimpl.cpp \
70 imipscheduler.cpp \
71 incidence.cpp \
72 incidencebase.cpp \
73 journal.cpp \
74 period.cpp \
75 person.cpp \
76 qtopiaformat.cpp \
77 recurrence.cpp \
78 scheduler.cpp \
79 todo.cpp \
80 vcaldrag.cpp \
81 vcalformat.cpp \
82 versit/vcc.c \
83 versit/vobject.c \
84
diff --git a/libkcal/libkcal.pro b/libkcal/libkcal.pro
new file mode 100644
index 0000000..49aa24b
--- a/dev/null
+++ b/libkcal/libkcal.pro
@@ -0,0 +1,100 @@
1 TEMPLATE= lib
2 CONFIG += qt warn_on
3 TARGET = microkcal
4
5include( ../variables.pri )
6
7INCLUDEPATH += ../microkde versit ../microkde/kdecore
8#../qtcompat
9INCLUDEPATH += ../libical/src/libical
10INCLUDEPATH += ../libical/src/libicalss
11DESTDIR = ../bin
12DEFINES += DESKTOP_VERSION
13unix: {
14LIBS += ../libical/lib/libical.a
15LIBS += ../libical/lib/libicalss.a
16OBJECTS_DIR = obj/unix
17MOC_DIR = moc/unix
18}
19win32: {
20DEFINES += _WIN32_
21
22LIBS += ../libical/lib/ical.lib
23LIBS += ../libical/lib/icalss.lib
24OBJECTS_DIR = obj/win
25MOC_DIR = moc/win
26
27}
28
29INTERFACES = \
30
31HEADERS = \
32 alarm.h \
33 attachment.h \
34 attendee.h \
35 calendar.h \
36 calendarlocal.h \
37 calfilter.h \
38 calformat.h \
39 calstorage.h \
40 compat.h \
41 customproperties.h \
42 dummyscheduler.h \
43 duration.h \
44 event.h \
45 exceptions.h \
46 filestorage.h \
47 freebusy.h \
48 icaldrag.h \
49 icalformat.h \
50 icalformatimpl.h \
51 imipscheduler.h \
52 incidence.h \
53 incidencebase.h \
54 journal.h \
55 period.h \
56 person.h \
57 qtopiaformat.h \
58 recurrence.h \
59 scheduler.h \
60 todo.h \
61 vcaldrag.h \
62 vcalformat.h \
63 versit/port.h \
64 versit/vcc.h \
65 versit/vobject.h \
66
67SOURCES = \
68 alarm.cpp \
69 attachment.cpp \
70 attendee.cpp \
71 calendar.cpp \
72 calendarlocal.cpp \
73 calfilter.cpp \
74 calformat.cpp \
75 compat.cpp \
76 customproperties.cpp \
77 dummyscheduler.cpp \
78 duration.cpp \
79 event.cpp \
80 exceptions.cpp \
81 filestorage.cpp \
82 freebusy.cpp \
83 icaldrag.cpp \
84 icalformat.cpp \
85 icalformatimpl.cpp \
86 imipscheduler.cpp \
87 incidence.cpp \
88 incidencebase.cpp \
89 journal.cpp \
90 period.cpp \
91 person.cpp \
92 qtopiaformat.cpp \
93 recurrence.cpp \
94 scheduler.cpp \
95 todo.cpp \
96 vcaldrag.cpp \
97 vcalformat.cpp \
98 versit/vcc.c \
99 versit/vobject.c \
100
diff --git a/libkcal/libkcalE.pro b/libkcal/libkcalE.pro
new file mode 100644
index 0000000..e27c10f
--- a/dev/null
+++ b/libkcal/libkcalE.pro
@@ -0,0 +1,88 @@
1 TEMPLATE= lib
2 CONFIG += qt warn_on
3 TARGET = microkcal
4
5
6INCLUDEPATH += ../microkde ../qtcompat versit ../microkde/kdecore versit $(QPEDIR)/include
7INCLUDEPATH += ../libical/src/libical
8INCLUDEPATH += ../libical/src/libicalss
9OBJECTS_DIR = obj/$(PLATFORM)
10MOC_DIR = moc/$(PLATFORM)
11DESTDIR = $(QPEDIR)/lib
12LIBS += ../libical/lib/$(PLATFORM)/libical.a
13LIBS += ../libical/lib/$(PLATFORM)/libicalss.a
14
15INTERFACES = \
16
17HEADERS = \
18 alarm.h \
19 attachment.h \
20 attendee.h \
21 calendar.h \
22 calendarlocal.h \
23 calfilter.h \
24 calformat.h \
25 calstorage.h \
26 compat.h \
27 customproperties.h \
28 dummyscheduler.h \
29 duration.h \
30 event.h \
31 exceptions.h \
32 filestorage.h \
33 freebusy.h \
34 icaldrag.h \
35 icalformat.h \
36 icalformatimpl.h \
37 imipscheduler.h \
38 incidence.h \
39 incidencebase.h \
40 journal.h \
41 period.h \
42 person.h \
43 qtopiaformat.h \
44 sharpformat.h \
45 recurrence.h \
46 scheduler.h \
47 todo.h \
48 vcaldrag.h \
49 vcalformat.h \
50 versit/port.h \
51 versit/vcc.h \
52 versit/vobject.h \
53
54SOURCES = \
55 alarm.cpp \
56 attachment.cpp \
57 attendee.cpp \
58 calendar.cpp \
59 calendarlocal.cpp \
60 calfilter.cpp \
61 calformat.cpp \
62 compat.cpp \
63 customproperties.cpp \
64 dummyscheduler.cpp \
65 duration.cpp \
66 event.cpp \
67 exceptions.cpp \
68 filestorage.cpp \
69 freebusy.cpp \
70 icaldrag.cpp \
71 icalformat.cpp \
72 icalformatimpl.cpp \
73 imipscheduler.cpp \
74 incidence.cpp \
75 incidencebase.cpp \
76 journal.cpp \
77 period.cpp \
78 person.cpp \
79 qtopiaformat.cpp \
80 sharpformat.cpp \
81 recurrence.cpp \
82 scheduler.cpp \
83 todo.cpp \
84 vcaldrag.cpp \
85 vcalformat.cpp \
86 versit/vcc.c \
87 versit/vobject.c \
88
diff --git a/libkcal/listbase.h b/libkcal/listbase.h
new file mode 100644
index 0000000..085b13d
--- a/dev/null
+++ b/libkcal/listbase.h
@@ -0,0 +1,97 @@
1/*
2 This file is part of libkcal.
3
4 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21#ifndef KCAL_LISTBASE_H
22#define KCAL_LISTBASE_H
23
24#include <qvaluelist.h>
25
26namespace KCal {
27 class Event;
28 class Todo;
29/**
30 This class provides a template for lists of pointers. It extends QValueList<T
31 *> by auto delete funtionality known from QPtrList.
32*/
33template<class T>
34class ListBase : public QValueList<T *>
35{
36 public:
37 ListBase()
38 : QValueList<T *>(), mAutoDelete( false )
39 {
40 }
41
42 ListBase( const ListBase &l )
43 : QValueList<T *>( l ), mAutoDelete( false )
44 {
45 }
46
47 ~ListBase()
48 {
49 if ( mAutoDelete ) {
50 QValueListIterator<T *> it;
51 for( it = QValueList<T*>::begin(); it != QValueList<T*>::end(); ++it ) {
52 delete *it;
53 }
54 }
55 }
56
57 ListBase &operator=( const ListBase &l )
58 {
59 if ( this == &l ) return *this;
60 QValueList<T *>::operator=( l );
61 return *this;
62 }
63
64 void setAutoDelete( bool autoDelete )
65 {
66 mAutoDelete = autoDelete;
67 }
68
69 bool removeRef( T *t )
70 {
71 QValueListIterator<T *> it = find( t );
72 if ( it == QValueList<T*>::end() ) {
73 return false;
74 } else {
75 if ( mAutoDelete ) delete t;
76 remove( it );
77 return true;
78 }
79 }
80 void fill ( QPtrList<T> list ) {
81 QPtrListIterator<T> it (list);
82 T *item;
83 while ( (item = it.current()) != 0 ) {
84 append( item );
85 ++it;
86 }
87
88 }
89
90
91 private:
92 bool mAutoDelete;
93};
94
95}
96
97#endif
diff --git a/libkcal/period.cpp b/libkcal/period.cpp
new file mode 100644
index 0000000..d188a4c
--- a/dev/null
+++ b/libkcal/period.cpp
@@ -0,0 +1,65 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <kdebug.h>
22#include <klocale.h>
23
24#include "period.h"
25
26using namespace KCal;
27
28Period::Period()
29{
30 mHasDuration = false;
31}
32
33Period::Period( const QDateTime &start, const QDateTime &end )
34{
35 mStart = start;
36 mEnd = end;
37 mHasDuration = false;
38}
39
40Period::Period( const QDateTime &start, const Duration &duration )
41{
42 mStart = start;
43 mEnd = duration.end( start );
44 mHasDuration = true;
45}
46
47QDateTime Period::start() const
48{
49 return mStart;
50}
51
52QDateTime Period::end()const
53{
54 return mEnd;
55}
56
57Duration Period::duration()
58{
59 return Duration( mStart, mEnd );
60}
61
62bool Period::hasDuration()const
63{
64 return mHasDuration;
65}
diff --git a/libkcal/period.h b/libkcal/period.h
new file mode 100644
index 0000000..9d40f12
--- a/dev/null
+++ b/libkcal/period.h
@@ -0,0 +1,51 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef KCAL_PERIOD_H
21#define KCAL_PERIOD_H
22
23#include <qdatetime.h>
24
25#include "duration.h"
26
27namespace KCal {
28
29class Period
30{
31 public:
32 Period();
33 Period( const QDateTime &start, const QDateTime &end );
34 Period( const QDateTime &start, const Duration &duration );
35
36 QDateTime start()const;
37 QDateTime end()const;
38 Duration duration();
39
40 bool hasDuration()const;
41
42 private:
43 QDateTime mStart;
44 QDateTime mEnd;
45
46 bool mHasDuration;
47};
48
49}
50
51#endif
diff --git a/libkcal/person.cpp b/libkcal/person.cpp
new file mode 100644
index 0000000..aca28c2
--- a/dev/null
+++ b/libkcal/person.cpp
@@ -0,0 +1,77 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <kdebug.h>
22#include <klocale.h>
23
24#include "person.h"
25
26using namespace KCal;
27
28Person::Person( const QString &fullName )
29{
30 int emailPos = fullName.find( '<' );
31 if ( emailPos < 0 ) {
32 setEmail(fullName);
33 } else {
34 setEmail(fullName.mid( emailPos + 1, fullName.length() - 1 ));
35 setName(fullName.left( emailPos - 2 ));
36 }
37}
38
39Person::Person( const QString &name, const QString &email )
40{
41 setName(name);
42 setEmail(email);
43}
44
45
46bool KCal::operator==( const Person& p1, const Person& p2 )
47{
48 return ( p1.name() == p2.name() &&
49 p1.email() == p2.email() );
50}
51
52
53QString Person::fullName() const
54{
55 if( mName.isEmpty() ) {
56 return mEmail;
57 } else {
58 if( mEmail.isEmpty() )
59 return mName;
60 else
61 return mName + " <" + mEmail + ">";
62 }
63}
64
65void Person::setName(const QString &name)
66{
67 mName = name;
68}
69
70void Person::setEmail(const QString &email)
71{
72 if (email.left(7).lower() == "mailto:") {
73 mEmail = email.mid(7);
74 } else {
75 mEmail = email;
76 }
77}
diff --git a/libkcal/person.h b/libkcal/person.h
new file mode 100644
index 0000000..c46c5f0
--- a/dev/null
+++ b/libkcal/person.h
@@ -0,0 +1,50 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef KCAL_PERSON_H
21#define KCAL_PERSON_H
22
23#include <qstring.h>
24
25namespace KCal {
26
27class Person
28{
29 public:
30 Person() {}
31 Person( const QString &fullName );
32 Person( const QString &name, const QString &email );
33
34 QString fullName( ) const;
35
36 void setName(const QString &);
37 QString name() const { return mName; }
38
39 void setEmail(const QString &);
40 QString email() const { return mEmail; }
41
42 private:
43 QString mName;
44 QString mEmail;
45};
46
47 bool operator==( const Person& p1, const Person& p2 );
48}
49
50#endif
diff --git a/libkcal/qtopiaformat.cpp b/libkcal/qtopiaformat.cpp
new file mode 100644
index 0000000..0a4a031
--- a/dev/null
+++ b/libkcal/qtopiaformat.cpp
@@ -0,0 +1,333 @@
1/*
2 This file is part of libkcal.
3
4 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#include <qdatetime.h>
23#include <qstring.h>
24#include <qptrlist.h>
25#include <qregexp.h>
26#include <qclipboard.h>
27#include <qfile.h>
28#include <qtextstream.h>
29#include <qxml.h>
30
31#include <kdebug.h>
32#include <klocale.h>
33
34#include "calendar.h"
35#include "calendarlocal.h"
36
37#include "qtopiaformat.h"
38
39using namespace KCal;
40
41class QtopiaParser : public QXmlDefaultHandler
42{
43 public:
44 QtopiaParser( Calendar *calendar ) : mCalendar( calendar ) {
45 oldCategories = 0;
46 }
47
48 bool startElement( const QString &, const QString &, const QString & qName,
49 const QXmlAttributes &attributes )
50 {
51 if ( qName == "event" ) {
52 Event *event = new Event;
53 QString uid = "Qtopia" + attributes.value( "uid" );
54 // event->setUid( uid );
55
56 event->setSummary( attributes.value( "description" ) );
57 event->setLocation( attributes.value( "location" ) );
58 event->setDescription( attributes.value( "note" ) );
59 event->setDtStart( toDateTime( attributes.value( "start" ) ) );
60 event->setDtEnd( toDateTime( attributes.value( "end" ) ) );
61
62 if ( attributes.value( "type" ) == "AllDay" ) {
63 event->setFloats( true );
64 } else {
65 event->setFloats( false );
66 }
67
68 QString rtype = attributes.value( "rtype" );
69 if ( !rtype.isEmpty() ) {
70 QDate startDate = event->dtStart().date();
71
72 QString freqStr = attributes.value( "rfreq" );
73 int freq = freqStr.toInt();
74
75 QString hasEndDateStr = attributes.value( "rhasenddate" );
76 bool hasEndDate = hasEndDateStr == "1";
77
78 QString endDateStr = attributes.value( "enddt" );
79 QDate endDate = toDateTime( endDateStr ).date();
80
81 QString weekDaysStr = attributes.value( "rweekdays" );
82 int weekDaysNum = weekDaysStr.toInt();
83 if ( weekDaysNum == 0 )
84 weekDaysNum = (1 << (event->dtStart().date().dayOfWeek()-1));
85
86 QBitArray weekDays( 7 );
87 weekDays.fill( false );
88 int i;
89 for( i = 0; i < 7; ++i ) {
90 weekDays.setBit( i , ( 1 << i ) & weekDaysNum );
91 qDebug("%d %d %d ",i, weekDaysNum, weekDays.at(i) );
92 }
93
94 QString posStr = attributes.value( "rposition" );
95 int pos = posStr.toInt();
96
97 Recurrence *r = event->recurrence();
98
99 if ( rtype == "Daily" ) {
100 if ( hasEndDate ) r->setDaily( freq, endDate );
101 else r->setDaily( freq, -1 );
102 } else if ( rtype == "Weekly" ) {
103 // fix needed here
104 // rweekdays not set in XML file
105 if ( hasEndDate ) r->setWeekly( freq, weekDays, endDate );
106 else r->setWeekly( freq, weekDays, -1 );
107 } else if ( rtype == "MonthlyDate" ) {
108 if ( hasEndDate )
109 r->setMonthly( Recurrence::rMonthlyDay, freq, endDate );
110 else
111 r->setMonthly( Recurrence::rMonthlyDay, freq, -1 );
112 r->addMonthlyDay( startDate.day() );
113 } else if ( rtype == "MonthlyDay" ) {
114 if ( hasEndDate )
115 r->setMonthly( Recurrence::rMonthlyPos, freq, endDate );
116 else
117 r->setMonthly( Recurrence::rMonthlyPos, freq, -1 );
118 QBitArray days( 7 );
119 days.fill( false );
120 days.setBit( startDate.dayOfWeek() - 1 );
121 r->addMonthlyPos( pos, days );
122 } else if ( rtype == "Yearly" ) {
123 if ( hasEndDate )
124 r->setYearly( Recurrence::rYearlyMonth, freq, endDate );
125 else
126 r->setYearly( Recurrence::rYearlyMonth, freq, -1 );
127 r->addYearlyNum( startDate.month() );
128 }
129 }
130
131 QString categoryList = attributes.value( "categories" );
132 event->setCategories( lookupCategories( categoryList ) );
133
134 QString alarmStr = attributes.value( "alarm" );
135 if ( !alarmStr.isEmpty() ) {
136 Alarm *alarm = new Alarm( event );
137 alarm->setType( Alarm::Display );
138 alarm->setEnabled( true );
139 int alarmOffset = alarmStr.toInt();
140 alarm->setStartOffset( alarmOffset * -60 );
141 event->addAlarm( alarm );
142 }
143 // the following may not be
144 //Event *oldEvent = mCalendar->event( uid );
145 //if ( oldEvent ) mCalendar->deleteEvent( oldEvent );
146
147 mCalendar->addEventNoDup( event );
148 } else if ( qName == "Task" ) {
149 Todo *todo = new Todo;
150
151 QString uid = "Qtopia" + attributes.value( "Uid" );
152 //todo->setUid( uid );
153
154 QString description = attributes.value( "Description" );
155 int pos = description.find( '\n' );
156 if ( pos > 0 ) {
157 QString summary = description.left( pos );
158 todo->setSummary( summary );
159 todo->setDescription( description );
160 } else {
161 todo->setSummary( description );
162 }
163
164 int priority = attributes.value( "Priority" ).toInt();
165 if ( priority == 0 ) priority = 3;
166 todo->setPriority( priority );
167
168 QString categoryList = attributes.value( "Categories" );
169 todo->setCategories( lookupCategories( categoryList ) );
170
171 QString completedStr = attributes.value( "Completed" );
172 if ( completedStr == "1" ) todo->setCompleted( true );
173
174 QString hasDateStr = attributes.value( "HasDate" );
175 if ( hasDateStr == "1" ) {
176 int year = attributes.value( "DateYear" ).toInt();
177 int month = attributes.value( "DateMonth" ).toInt();
178 int day = attributes.value( "DateDay" ).toInt();
179
180 todo->setDtDue( QDateTime( QDate( year, month, day ) ) );
181 todo->setHasDueDate( true );
182 }
183
184 // Todo *oldTodo = mCalendar->todo( uid );
185 //if ( oldTodo ) mCalendar->deleteTodo( oldTodo );
186
187 mCalendar->addTodoNoDup( todo );
188 } else if ( qName == "Category" ) {
189 QString id = attributes.value( "id" );
190 QString name = attributes.value( "name" );
191 setCategory( id, name );
192 }
193
194 return true;
195 }
196
197 bool warning ( const QXmlParseException &exception )
198 {
199 printException( exception );
200 return true;
201 }
202
203 bool error ( const QXmlParseException &exception )
204 {
205 printException( exception );
206 return false;
207 }
208
209 bool fatalError ( const QXmlParseException &exception )
210 {
211 printException( exception );
212 return false;
213 }
214
215 QString errorString ()
216 {
217 return "QtopiaParser: Error!";
218 }
219 void setCategoriesList ( QStringList * c )
220 {
221 oldCategories = c;
222 }
223
224 protected:
225 void printException( const QXmlParseException &exception )
226 {
227 kdError() << "XML Parse Error (line " << exception.lineNumber()
228 << ", col " << exception.columnNumber() << "): "
229 << exception.message() << "(public ID: '"
230 << exception.publicId() << "' system ID: '"
231 << exception.systemId() << "')" << endl;
232 }
233
234 QDateTime toDateTime( const QString &value )
235 {
236 QDateTime dt;
237 dt.setTime_t( value.toUInt() );
238
239 return dt;
240 }
241
242 QStringList lookupCategories( const QString &categoryList )
243 {
244 QStringList categoryIds = QStringList::split( ";", categoryList );
245 QStringList categories;
246 QStringList::ConstIterator it;
247 for( it = categoryIds.begin(); it != categoryIds.end(); ++it ) {
248 QString cate = category( *it );
249 if ( oldCategories ) {
250 if ( ! oldCategories->contains( cate ) )
251 oldCategories->append( cate );
252 }
253 categories.append(cate );
254 }
255 return categories;
256 }
257
258 private:
259 Calendar *mCalendar;
260 QStringList * oldCategories;
261 static QString category( const QString &id )
262 {
263 QMap<QString,QString>::ConstIterator it = mCategoriesMap.find( id );
264 if ( it == mCategoriesMap.end() ) return id;
265 else return *it;
266 }
267
268 static void setCategory( const QString &id, const QString &name )
269 {
270 mCategoriesMap.insert( id, name );
271 }
272
273 static QMap<QString,QString> mCategoriesMap;
274};
275
276QMap<QString,QString> QtopiaParser::mCategoriesMap;
277
278QtopiaFormat::QtopiaFormat()
279{
280 mCategories = 0;
281}
282
283QtopiaFormat::~QtopiaFormat()
284{
285}
286#include <qdom.h>
287bool QtopiaFormat::load( Calendar *calendar, const QString &fileName )
288{
289 clearException();
290 // qDebug("load QtopiaFormat: %s ",fileName.latin1() );
291 QtopiaParser handler( calendar );
292 handler.setCategoriesList( mCategories );
293 QFile xmlFile( fileName );
294 QXmlInputSource source( xmlFile );
295 QXmlSimpleReader reader;
296 reader.setContentHandler( &handler );
297 return reader.parse( source );
298}
299
300bool QtopiaFormat::save( Calendar *calendar, const QString &fileName )
301{
302
303 clearException();
304
305 QString text = toString( calendar );
306
307 if ( text.isNull() ) return false;
308
309 // TODO: write backup file
310
311 QFile file( fileName );
312 if (!file.open( IO_WriteOnly ) ) {
313 setException(new ErrorFormat(ErrorFormat::SaveError,
314 i18n("Could not open file '%1'").arg(fileName)));
315 return false;
316 }
317 QTextStream ts( &file );
318 ts << text;
319 file.close();
320
321 return true;
322}
323
324bool QtopiaFormat::fromString( Calendar *, const QString & )
325{
326
327 return false;
328}
329
330QString QtopiaFormat::toString( Calendar * )
331{
332 return QString::null;
333}
diff --git a/libkcal/qtopiaformat.h b/libkcal/qtopiaformat.h
new file mode 100644
index 0000000..2c69a4e
--- a/dev/null
+++ b/libkcal/qtopiaformat.h
@@ -0,0 +1,53 @@
1/*
2 This file is part of libkcal.
3
4 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21#ifndef QTOPIAFORMAT_H
22#define QTOPIAFORMAT_H
23
24#include <qstring.h>
25
26#include "scheduler.h"
27
28#include "calformat.h"
29
30namespace KCal {
31
32/**
33 This class implements the calendar format used by Qtopia.
34*/
35class QtopiaFormat : public CalFormat {
36 public:
37 /** Create new iCalendar format. */
38 QtopiaFormat();
39 virtual ~QtopiaFormat();
40
41 bool load( Calendar *, const QString &fileName );
42 bool save( Calendar *, const QString &fileName );
43 void setCategoriesList ( QStringList * cat ){ mCategories = cat; }
44 bool fromString( Calendar *, const QString & );
45 QString toString( Calendar * );
46
47 private:
48 QStringList *mCategories;
49};
50
51}
52
53#endif
diff --git a/libkcal/recurrence.cpp b/libkcal/recurrence.cpp
new file mode 100644
index 0000000..5fc5d1f
--- a/dev/null
+++ b/libkcal/recurrence.cpp
@@ -0,0 +1,3360 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (c) 2002 David Jarvie <software@astrojar.org.uk>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21*/
22
23#include <limits.h>
24
25#include <kdebug.h>
26#include <kglobal.h>
27#include <klocale.h>
28
29#include "incidence.h"
30
31#include "recurrence.h"
32
33using namespace KCal;
34
35Recurrence::Feb29Type Recurrence::mFeb29YearlyDefaultType = Recurrence::rMar1;
36
37
38Recurrence::Recurrence(Incidence *parent, int compatVersion)
39: recurs(rNone), // by default, it's not a recurring event
40 rWeekStart(1), // default is Monday
41 rDays(7),
42 mFloats(parent ? parent->doesFloat() : false),
43 mRecurReadOnly(false),
44 mRecurExDatesCount(0),
45 mFeb29YearlyType(mFeb29YearlyDefaultType),
46 mCompatVersion(compatVersion ? compatVersion : INT_MAX),
47 mCompatRecurs(rNone),
48 mCompatDuration(0),
49 mParent(parent)
50{
51 rMonthDays.setAutoDelete( true );
52 rMonthPositions.setAutoDelete( true );
53 rYearNums.setAutoDelete( true );
54}
55
56Recurrence::Recurrence(const Recurrence &r, Incidence *parent)
57: recurs(r.recurs),
58 rWeekStart(r.rWeekStart),
59 rDays(r.rDays.copy()),
60 rFreq(r.rFreq),
61 rDuration(r.rDuration),
62 rEndDateTime(r.rEndDateTime),
63 mRecurStart(r.mRecurStart),
64 mFloats(r.mFloats),
65 mRecurReadOnly(r.mRecurReadOnly),
66 mRecurExDatesCount(r.mRecurExDatesCount),
67 mFeb29YearlyType(r.mFeb29YearlyType),
68 mCompatVersion(r.mCompatVersion),
69 mCompatRecurs(r.mCompatRecurs),
70 mCompatDuration(r.mCompatDuration),
71 mParent(parent)
72{
73 for (QPtrListIterator<rMonthPos> mp(r.rMonthPositions); mp.current(); ++mp) {
74 rMonthPos *tmp = new rMonthPos;
75 tmp->rPos = mp.current()->rPos;
76 tmp->negative = mp.current()->negative;
77 tmp->rDays = mp.current()->rDays.copy();
78 rMonthPositions.append(tmp);
79 }
80 for (QPtrListIterator<int> md(r.rMonthDays); md.current(); ++md) {
81 int *tmp = new int;
82 *tmp = *md.current();
83 rMonthDays.append(tmp);
84 }
85 for (QPtrListIterator<int> yn(r.rYearNums); yn.current(); ++yn) {
86 int *tmp = new int;
87 *tmp = *yn.current();
88 rYearNums.append(tmp);
89 }
90 rMonthDays.setAutoDelete( true );
91 rMonthPositions.setAutoDelete( true );
92 rYearNums.setAutoDelete( true );
93}
94
95Recurrence::~Recurrence()
96{
97}
98
99
100bool Recurrence::operator==( const Recurrence& r2 ) const
101{
102
103 // the following line is obvious
104 if ( recurs == rNone && r2.recurs == rNone )
105 return true;
106 // we need the above line, because two non recurring events may
107 // differ in the other settings, because one (or both)
108 // may be not initialized properly
109 if ( recurs != r2.recurs
110 || rFreq != r2.rFreq
111 || rDuration != r2.rDuration
112 || !rDuration && rEndDateTime != r2.rEndDateTime
113 || mRecurStart != r2.mRecurStart
114 || mFloats != r2.mFloats
115 || mRecurReadOnly != r2.mRecurReadOnly
116 || mRecurExDatesCount != r2.mRecurExDatesCount )
117 return false;
118 // no need to compare mCompat* and mParent
119 // OK to compare the pointers
120 switch ( recurs )
121 {
122 case rWeekly:
123 return rDays == r2.rDays
124 && rWeekStart == r2.rWeekStart;
125 case rMonthlyPos:
126 return rMonthPositions.count() == r2.rMonthPositions.count();
127 case rMonthlyDay:
128 return rMonthDays.count() == r2.rMonthDays.count();
129 case rYearlyPos:
130 return rYearNums.count() == r2.rYearNums.count()
131 && rMonthPositions.count() == r2.rMonthPositions.count();
132 case rYearlyMonth:
133 return rYearNums.count() == r2.rYearNums.count()
134 && mFeb29YearlyType == r2.mFeb29YearlyType;
135 case rYearlyDay:
136 return rYearNums == r2.rYearNums;
137 case rNone:
138 case rMinutely:
139 case rHourly:
140 case rDaily:
141 default:
142 return true;
143 }
144}
145/*
146bool Recurrence::compareLists( const QPtrList<int> &l1 ,const QPtrList<int> &l2)
147{
148 if ( l1.count() != l2.count() )
149 return false;
150 int count = l1.count();
151 int i;
152 for ( i = 0; i < count ; ++i ) {
153 // if ( l1.at(i) != l2.at(i) )
154 return false;
155 qDebug("compüare ");
156 }
157 return true;
158}
159*/
160QString Recurrence::recurrenceText() const
161{
162 QString recurText = i18n("No");
163 if ( recurs == Recurrence::rMinutely )
164 recurText = i18n("minutely");
165 else if ( recurs == Recurrence::rHourly )
166 recurText = i18n("hourly");
167 else if ( recurs == Recurrence::rDaily )
168 recurText = i18n("daily");
169 else if ( recurs == Recurrence::rWeekly )
170 recurText = i18n("weekly");
171 else if ( recurs == Recurrence::rMonthlyPos )
172 recurText = i18n("monthly");
173 else if ( recurs == Recurrence::rMonthlyDay )
174 recurText = i18n("day-monthly");
175 else if ( recurs == Recurrence::rYearlyMonth )
176 recurText = i18n("month-yearly");
177 else if ( recurs == Recurrence::rYearlyDay )
178 recurText = i18n("day-yearly");
179 else if ( recurs == Recurrence::rYearlyPos )
180 recurText = i18n("position-yearly");
181 return recurText;
182}
183
184void Recurrence::setCompatVersion(int version)
185{
186 mCompatVersion = version ? version : INT_MAX;
187}
188
189ushort Recurrence::doesRecur() const
190{
191 return recurs;
192}
193
194bool Recurrence::recursOnPure(const QDate &qd) const
195{
196 switch(recurs) {
197 case rMinutely:
198 return recursSecondly(qd, rFreq*60);
199 case rHourly:
200 return recursSecondly(qd, rFreq*3600);
201 case rDaily:
202 return recursDaily(qd);
203 case rWeekly:
204 return recursWeekly(qd);
205 case rMonthlyPos:
206 case rMonthlyDay:
207 return recursMonthly(qd);
208 case rYearlyMonth:
209 return recursYearlyByMonth(qd);
210 case rYearlyDay:
211 return recursYearlyByDay(qd);
212 case rYearlyPos:
213 return recursYearlyByPos(qd);
214 default:
215 return false;
216 case rNone:
217 return false;
218 } // case
219 return false;
220}
221
222bool Recurrence::recursAtPure(const QDateTime &dt) const
223{
224 switch(recurs) {
225 case rMinutely:
226 return recursMinutelyAt(dt, rFreq);
227 case rHourly:
228 return recursMinutelyAt(dt, rFreq*60);
229 default:
230 if (dt.time() != mRecurStart.time())
231 return false;
232 switch(recurs) {
233 case rDaily:
234 return recursDaily(dt.date());
235 case rWeekly:
236 return recursWeekly(dt.date());
237 case rMonthlyPos:
238 case rMonthlyDay:
239 return recursMonthly(dt.date());
240 case rYearlyMonth:
241 return recursYearlyByMonth(dt.date());
242 case rYearlyDay:
243 return recursYearlyByDay(dt.date());
244 case rYearlyPos:
245 return recursYearlyByPos(dt.date());
246 default:
247 return false;
248 case rNone:
249 return false;
250 }
251 } // case
252 return false;
253}
254
255QDate Recurrence::endDate() const
256{
257 int count = 0;
258 QDate end;
259 if (recurs != rNone) {
260 if (rDuration < 0)
261 return QDate(); // infinite recurrence
262 if (rDuration == 0)
263 return rEndDateTime.date();
264
265 // The end date is determined by the recurrence count
266 QDate dStart = mRecurStart.date();
267 switch (recurs)
268 {
269 case rMinutely:
270 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60).date();
271 case rHourly:
272 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600).date();
273 case rDaily:
274 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq);
275
276 case rWeekly:
277 count = weeklyCalc(END_DATE_AND_COUNT, end);
278 break;
279 case rMonthlyPos:
280 case rMonthlyDay:
281 count = monthlyCalc(END_DATE_AND_COUNT, end);
282 break;
283 case rYearlyMonth:
284 count = yearlyMonthCalc(END_DATE_AND_COUNT, end);
285 break;
286 case rYearlyDay:
287 count = yearlyDayCalc(END_DATE_AND_COUNT, end);
288 break;
289 case rYearlyPos:
290 count = yearlyPosCalc(END_DATE_AND_COUNT, end);
291 break;
292 default:
293 // catch-all. Should never get here.
294 kdDebug(5800) << "Control should never reach here in endDate()!" << endl;
295 break;
296 }
297 }
298 if (!count)
299 return QDate(); // error - there is no recurrence
300 return end;
301}
302
303QDateTime Recurrence::endDateTime() const
304{
305 int count = 0;
306 QDate end;
307 if (recurs != rNone) {
308 if (rDuration < 0)
309 return QDateTime(); // infinite recurrence
310 if (rDuration == 0)
311 return rEndDateTime;
312
313 // The end date is determined by the recurrence count
314 QDate dStart = mRecurStart.date();
315 switch (recurs)
316 {
317 case rMinutely:
318 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60);
319 case rHourly:
320 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600);
321 case rDaily:
322 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq);
323
324 case rWeekly:
325 count = weeklyCalc(END_DATE_AND_COUNT, end);
326 break;
327 case rMonthlyPos:
328 case rMonthlyDay:
329 count = monthlyCalc(END_DATE_AND_COUNT, end);
330 break;
331 case rYearlyMonth:
332 count = yearlyMonthCalc(END_DATE_AND_COUNT, end);
333 break;
334 case rYearlyDay:
335 count = yearlyDayCalc(END_DATE_AND_COUNT, end);
336 break;
337 case rYearlyPos:
338 count = yearlyPosCalc(END_DATE_AND_COUNT, end);
339 break;
340 default:
341 // catch-all. Should never get here.
342 kdDebug(5800) << "Control should never reach here in endDate()!" << endl;
343 break;
344 }
345 }
346 if (!count)
347 return QDateTime(); // error - there is no recurrence
348 return QDateTime(end, mRecurStart.time());
349}
350
351int Recurrence::durationTo(const QDate &date) const
352{
353 QDate d = date;
354 return recurCalc(COUNT_TO_DATE, d);
355}
356
357int Recurrence::durationTo(const QDateTime &datetime) const
358{
359 QDateTime dt = datetime;
360 return recurCalc(COUNT_TO_DATE, dt);
361}
362
363void Recurrence::unsetRecurs()
364{
365 if (mRecurReadOnly) return;
366 recurs = rNone;
367 rMonthPositions.clear();
368 rMonthDays.clear();
369 rYearNums.clear();
370}
371
372void Recurrence::setRecurStart(const QDateTime &start)
373{
374 mRecurStart = start;
375 mFloats = false;
376 switch (recurs)
377 {
378 case rMinutely:
379 case rHourly:
380 break;
381 case rDaily:
382 case rWeekly:
383 case rMonthlyPos:
384 case rMonthlyDay:
385 case rYearlyMonth:
386 case rYearlyDay:
387 case rYearlyPos:
388 default:
389 rEndDateTime.setTime(start.time());
390 break;
391 }
392}
393
394void Recurrence::setRecurStart(const QDate &start)
395{
396 mRecurStart.setDate(start);
397 mRecurStart.setTime(QTime(0,0,0));
398 switch (recurs)
399 {
400 case rMinutely:
401 case rHourly:
402 break;
403 case rDaily:
404 case rWeekly:
405 case rMonthlyPos:
406 case rMonthlyDay:
407 case rYearlyMonth:
408 case rYearlyDay:
409 case rYearlyPos:
410 default:
411 mFloats = true;
412 break;
413 }
414}
415
416void Recurrence::setFloats(bool f)
417{
418 switch (recurs)
419 {
420 case rDaily:
421 case rWeekly:
422 case rMonthlyPos:
423 case rMonthlyDay:
424 case rYearlyMonth:
425 case rYearlyDay:
426 case rYearlyPos:
427 break;
428 case rMinutely:
429 case rHourly:
430 default:
431 return; // can't set sub-daily to floating
432 }
433 mFloats = f;
434 if (f) {
435 mRecurStart.setTime(QTime(0,0,0));
436 rEndDateTime.setTime(QTime(0,0,0));
437 }
438}
439
440int Recurrence::frequency() const
441{
442 return rFreq;
443}
444
445int Recurrence::duration() const
446{
447 return rDuration;
448}
449
450void Recurrence::setDuration(int _rDuration)
451{
452 if (mRecurReadOnly) return;
453 if (_rDuration > 0) {
454 rDuration = _rDuration;
455 // Compatibility mode is only needed when reading the calendar in ICalFormatImpl,
456 // so explicitly setting the duration means no backwards compatibility is needed.
457 mCompatDuration = 0;
458 }
459}
460
461QString Recurrence::endDateStr(bool shortfmt) const
462{
463 return KGlobal::locale()->formatDate(rEndDateTime.date(),shortfmt);
464}
465
466const QBitArray &Recurrence::days() const
467{
468 return rDays;
469}
470
471const QPtrList<Recurrence::rMonthPos> &Recurrence::monthPositions() const
472{
473 return rMonthPositions;
474}
475
476const QPtrList<Recurrence::rMonthPos> &Recurrence::yearMonthPositions() const
477{
478 return rMonthPositions;
479}
480
481const QPtrList<int> &Recurrence::monthDays() const
482{
483 return rMonthDays;
484}
485
486void Recurrence::setMinutely(int _rFreq, int _rDuration)
487{
488 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
489 return;
490 setDailySub(rMinutely, _rFreq, _rDuration);
491}
492
493void Recurrence::setMinutely(int _rFreq, const QDateTime &_rEndDateTime)
494{
495 if (mRecurReadOnly) return;
496 rEndDateTime = _rEndDateTime;
497 setDailySub(rMinutely, _rFreq, 0);
498}
499
500void Recurrence::setHourly(int _rFreq, int _rDuration)
501{
502 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
503 return;
504 setDailySub(rHourly, _rFreq, _rDuration);
505}
506
507void Recurrence::setHourly(int _rFreq, const QDateTime &_rEndDateTime)
508{
509 if (mRecurReadOnly) return;
510 rEndDateTime = _rEndDateTime;
511 setDailySub(rHourly, _rFreq, 0);
512}
513
514void Recurrence::setDaily(int _rFreq, int _rDuration)
515{
516 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
517 return;
518 setDailySub(rDaily, _rFreq, _rDuration);
519}
520
521void Recurrence::setDaily(int _rFreq, const QDate &_rEndDate)
522{
523 if (mRecurReadOnly) return;
524 rEndDateTime.setDate(_rEndDate);
525 rEndDateTime.setTime(mRecurStart.time());
526 setDailySub(rDaily, _rFreq, 0);
527}
528
529void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays,
530 int _rDuration, int _rWeekStart)
531{
532 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
533 return;
534 recurs = rWeekly;
535
536 rFreq = _rFreq;
537 rDays = _rDays;
538 rWeekStart = _rWeekStart;
539 rDuration = _rDuration;
540 if (mCompatVersion < 310 && _rDuration > 0) {
541 // Backwards compatibility for KDE < 3.1.
542 // rDuration was set to the number of time periods to recur,
543 // with week start always on a Monday.
544 // Convert this to the number of occurrences.
545 mCompatDuration = _rDuration;
546 int weeks = ((mCompatDuration-1+mRecurExDatesCount)*7) + (7 - mRecurStart.date().dayOfWeek());
547 QDate end(mRecurStart.date().addDays(weeks * rFreq));
548 rDuration = INT_MAX; // ensure that weeklyCalc() does its job correctly
549 rDuration = weeklyCalc(COUNT_TO_DATE, end);
550 } else {
551 mCompatDuration = 0;
552 }
553 rMonthPositions.clear();
554 rMonthDays.clear();
555 if (mParent) mParent->updated();
556}
557
558void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays,
559 const QDate &_rEndDate, int _rWeekStart)
560{
561 if (mRecurReadOnly) return;
562 recurs = rWeekly;
563
564 rFreq = _rFreq;
565 rDays = _rDays;
566 rWeekStart = _rWeekStart;
567 rEndDateTime.setDate(_rEndDate);
568 rEndDateTime.setTime(mRecurStart.time());
569 rDuration = 0; // set to 0 because there is an end date
570 mCompatDuration = 0;
571 rMonthPositions.clear();
572 rMonthDays.clear();
573 rYearNums.clear();
574 if (mParent) mParent->updated();
575}
576
577void Recurrence::setMonthly(short type, int _rFreq, int _rDuration)
578{
579 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
580 return;
581 recurs = type;
582
583 rFreq = _rFreq;
584 rDuration = _rDuration;
585 if (mCompatVersion < 310)
586 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
587 rYearNums.clear();
588 if (mParent) mParent->updated();
589}
590
591void Recurrence::setMonthly(short type, int _rFreq,
592 const QDate &_rEndDate)
593{
594 if (mRecurReadOnly) return;
595 recurs = type;
596
597 rFreq = _rFreq;
598 rEndDateTime.setDate(_rEndDate);
599 rEndDateTime.setTime(mRecurStart.time());
600 rDuration = 0; // set to 0 because there is an end date
601 mCompatDuration = 0;
602 rYearNums.clear();
603 if (mParent) mParent->updated();
604}
605
606void Recurrence::addMonthlyPos(short _rPos, const QBitArray &_rDays)
607{
608 if (recurs == rMonthlyPos)
609 addMonthlyPos_(_rPos, _rDays);
610}
611
612void Recurrence::addMonthlyPos_(short _rPos, const QBitArray &_rDays)
613{
614 if (mRecurReadOnly
615 || _rPos == 0 || _rPos > 5 || _rPos < -5) // invalid week number
616 return;
617
618 for (rMonthPos* it = rMonthPositions.first(); it; it = rMonthPositions.next()) {
619 int itPos = it->negative ? -it->rPos : it->rPos;
620 if (_rPos == itPos) {
621 // This week is already in the list.
622 // Combine the specified days with those in the list.
623 it->rDays |= _rDays;
624 if (mParent) mParent->updated();
625 return;
626 }
627 }
628 // Add the new position to the list
629 rMonthPos *tmpPos = new rMonthPos;
630 if (_rPos > 0) {
631 tmpPos->rPos = _rPos;
632 tmpPos->negative = false;
633 } else {
634 tmpPos->rPos = -_rPos; // take abs()
635 tmpPos->negative = true;
636 }
637 tmpPos->rDays = _rDays;
638 tmpPos->rDays.detach();
639 rMonthPositions.append(tmpPos);
640
641 if (mCompatVersion < 310 && mCompatDuration > 0) {
642 // Backwards compatibility for KDE < 3.1.
643 // rDuration was set to the number of time periods to recur.
644 // Convert this to the number of occurrences.
645 int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq;
646 int month = mRecurStart.date().month() - 1 + monthsAhead;
647 QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31);
648 rDuration = INT_MAX; // ensure that recurCalc() does its job correctly
649 rDuration = recurCalc(COUNT_TO_DATE, end);
650 }
651
652 if (mParent) mParent->updated();
653}
654
655void Recurrence::addMonthlyDay(short _rDay)
656{
657 if (mRecurReadOnly || recurs != rMonthlyDay
658 || _rDay == 0 || _rDay > 31 || _rDay < -31) // invalid day number
659 return;
660 for (int* it = rMonthDays.first(); it; it = rMonthDays.next()) {
661 if (_rDay == *it)
662 return; // this day is already in the list - avoid duplication
663 }
664 int *tmpDay = new int;
665 *tmpDay = _rDay;
666 rMonthDays.append(tmpDay);
667
668 if (mCompatVersion < 310 && mCompatDuration > 0) {
669 // Backwards compatibility for KDE < 3.1.
670 // rDuration was set to the number of time periods to recur.
671 // Convert this to the number of occurrences.
672 int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq;
673 int month = mRecurStart.date().month() - 1 + monthsAhead;
674 QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31);
675 rDuration = INT_MAX; // ensure that recurCalc() does its job correctly
676 rDuration = recurCalc(COUNT_TO_DATE, end);
677 }
678
679 if (mParent) mParent->updated();
680}
681
682void Recurrence::setYearly(int type, int _rFreq, int _rDuration)
683{
684 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
685 return;
686 if (mCompatVersion < 310)
687 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
688 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, _rDuration);
689}
690
691void Recurrence::setYearly(int type, int _rFreq, const QDate &_rEndDate)
692{
693 if (mRecurReadOnly) return;
694 rEndDateTime.setDate(_rEndDate);
695 rEndDateTime.setTime(mRecurStart.time());
696 mCompatDuration = 0;
697 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, 0);
698}
699
700void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, int _rDuration)
701{
702 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
703 return;
704 if (mCompatVersion < 310)
705 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
706 setYearly_(rYearlyMonth, type, _rFreq, _rDuration);
707}
708
709void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, const QDate &_rEndDate)
710{
711 if (mRecurReadOnly) return;
712 rEndDateTime.setDate(_rEndDate);
713 rEndDateTime.setTime(mRecurStart.time());
714 mCompatDuration = 0;
715 setYearly_(rYearlyMonth, type, _rFreq, 0);
716}
717
718void Recurrence::addYearlyMonthPos(short _rPos, const QBitArray &_rDays)
719{
720 if (recurs == rYearlyPos)
721 addMonthlyPos_(_rPos, _rDays);
722}
723
724const QPtrList<int> &Recurrence::yearNums() const
725{
726 return rYearNums;
727}
728
729void Recurrence::addYearlyNum(short _rNum)
730{
731 if (mRecurReadOnly
732 || (recurs != rYearlyMonth && recurs != rYearlyDay && recurs != rYearlyPos)
733 || _rNum <= 0) // invalid day/month number
734 return;
735
736 if (mCompatVersion < 310 && mCompatRecurs == rYearlyDay) {
737 // Backwards compatibility for KDE < 3.1.
738 // Dates were stored as day numbers, with a fiddle to take account of leap years.
739 // Convert the day number to a month.
740 if (_rNum <= 0 || _rNum > 366 || (_rNum == 366 && mRecurStart.date().daysInYear() < 366))
741 return; // invalid day number
742 _rNum = QDate(mRecurStart.date().year(), 1, 1).addDays(_rNum - 1).month();
743 } else
744 if ((recurs == rYearlyMonth || recurs == rYearlyPos) && _rNum > 12
745 || recurs == rYearlyDay && _rNum > 366)
746 return; // invalid day number
747
748 uint i = 0;
749 for (int* it = rYearNums.first(); it && _rNum >= *it; it = rYearNums.next()) {
750 if (_rNum == *it)
751 return; // this day/month is already in the list - avoid duplication
752 ++i;
753 }
754
755 int *tmpNum = new int;
756 *tmpNum = _rNum;
757 rYearNums.insert(i, tmpNum); // insert the day/month in a sorted position
758
759 if (mCompatVersion < 310 && mCompatDuration > 0) {
760 // Backwards compatibility for KDE < 3.1.
761 // rDuration was set to the number of time periods to recur.
762 // Convert this to the number of occurrences.
763 QDate end(mRecurStart.date().year() + (mCompatDuration-1+mRecurExDatesCount)*rFreq, 12, 31);
764 rDuration = INT_MAX; // ensure that recurCalc() does its job correctly
765 rDuration = recurCalc(COUNT_TO_DATE, end);
766 }
767
768 if (mParent) mParent->updated();
769}
770
771
772QDateTime Recurrence::getNextDateTime(const QDateTime &preDateTime, bool *last) const
773{
774 if (last)
775 *last = false;
776 int freq;
777 switch (recurs)
778 {
779 case rMinutely:
780 freq = rFreq * 60;
781 break;
782 case rHourly:
783 freq = rFreq * 3600;
784 break;
785 case rDaily:
786 case rWeekly:
787 case rMonthlyPos:
788 case rMonthlyDay:
789 case rYearlyMonth:
790 case rYearlyDay:
791 case rYearlyPos: {
792 QDate preDate = preDateTime.date();
793 if (!mFloats && mRecurStart.time() > preDateTime.time())
794 preDate = preDate.addDays(-1);
795 return QDateTime(getNextDateNoTime(preDate, last), mRecurStart.time());
796 }
797 default:
798 return QDateTime();
799 }
800
801 // It's a sub-daily recurrence
802 if (preDateTime < mRecurStart)
803 return mRecurStart;
804 int count = mRecurStart.secsTo(preDateTime) / freq + 2;
805 if (rDuration > 0) {
806 if (count > rDuration)
807 return QDateTime();
808 if (last && count == rDuration)
809 *last = true;
810 }
811 QDateTime endtime = mRecurStart.addSecs((count - 1)*freq);
812 if (rDuration == 0) {
813 if (endtime > rEndDateTime)
814 return QDateTime();
815 if (last && endtime == rEndDateTime)
816 *last = true;
817 }
818 return endtime;
819}
820
821QDate Recurrence::getNextDate(const QDate &preDate, bool *last) const
822{
823 if (last)
824 *last = false;
825 switch (recurs)
826 {
827 case rMinutely:
828 case rHourly:
829 return getNextDateTime(QDateTime(preDate, QTime(23,59,59)), last).date();
830 case rDaily:
831 case rWeekly:
832 case rMonthlyPos:
833 case rMonthlyDay:
834 case rYearlyMonth:
835 case rYearlyDay:
836 case rYearlyPos:
837 return getNextDateNoTime(preDate, last);
838 default:
839 return QDate();
840 }
841}
842
843
844QDateTime Recurrence::getPreviousDateTime(const QDateTime &afterDateTime, bool *last) const
845{
846 if (last)
847 *last = false;
848 int freq;
849 switch (recurs)
850 {
851 case rMinutely:
852 freq = rFreq * 60;
853 break;
854 case rHourly:
855 freq = rFreq * 3600;
856 break;
857 case rDaily:
858 case rWeekly:
859 case rMonthlyPos:
860 case rMonthlyDay:
861 case rYearlyMonth:
862 case rYearlyDay:
863 case rYearlyPos: {
864 QDate afterDate = afterDateTime.date();
865 if (!mFloats && mRecurStart.time() < afterDateTime.time())
866 afterDate = afterDate.addDays(1);
867 return QDateTime(getPreviousDateNoTime(afterDate, last), mRecurStart.time());
868 }
869 default:
870 return QDateTime();
871 }
872
873 // It's a sub-daily recurrence
874 if (afterDateTime <= mRecurStart)
875 return QDateTime();
876 int count = (mRecurStart.secsTo(afterDateTime) - 1) / freq + 1;
877 if (rDuration > 0) {
878 if (count > rDuration)
879 count = rDuration;
880 if (last && count == rDuration)
881 *last = true;
882 }
883 QDateTime endtime = mRecurStart.addSecs((count - 1)*freq);
884 if (rDuration == 0) {
885 if (endtime > rEndDateTime)
886 endtime = rEndDateTime;
887 if (last && endtime == rEndDateTime)
888 *last = true;
889 }
890 return endtime;
891}
892
893QDate Recurrence::getPreviousDate(const QDate &afterDate, bool *last) const
894{
895 if (last)
896 *last = false;
897 switch (recurs)
898 {
899 case rMinutely:
900 case rHourly:
901 return getPreviousDateTime(QDateTime(afterDate, QTime(0,0,0)), last).date();
902 case rDaily:
903 case rWeekly:
904 case rMonthlyPos:
905 case rMonthlyDay:
906 case rYearlyMonth:
907 case rYearlyDay:
908 case rYearlyPos:
909 return getPreviousDateNoTime(afterDate, last);
910 default:
911 return QDate();
912 }
913}
914
915
916/***************************** PROTECTED FUNCTIONS ***************************/
917
918bool Recurrence::recursSecondly(const QDate &qd, int secondFreq) const
919{
920 if ((qd >= mRecurStart.date()) &&
921 ((rDuration > 0) && (qd <= endDate()) ||
922 ((rDuration == 0) && (qd <= rEndDateTime.date())) ||
923 (rDuration == -1))) {
924 // The date queried falls within the range of the event.
925 if (secondFreq < 24*3600)
926 return true; // the event recurs at least once each day
927 int after = mRecurStart.secsTo(QDateTime(qd));
928 if (after / secondFreq != (after + 24*3600) / secondFreq)
929 return true;
930 }
931 return false;
932}
933
934bool Recurrence::recursMinutelyAt(const QDateTime &dt, int minuteFreq) const
935{
936 if ((dt >= mRecurStart) &&
937 ((rDuration > 0) && (dt <= endDateTime()) ||
938 ((rDuration == 0) && (dt <= rEndDateTime)) ||
939 (rDuration == -1))) {
940 // The time queried falls within the range of the event.
941 if (((mRecurStart.secsTo(dt) / 60) % minuteFreq) == 0)
942 return true;
943 }
944 return false;
945}
946
947bool Recurrence::recursDaily(const QDate &qd) const
948{
949 QDate dStart = mRecurStart.date();
950 if ((dStart.daysTo(qd) % rFreq) == 0) {
951 // The date is a day which recurs
952 if (qd >= dStart
953 && ((rDuration > 0 && qd <= endDate()) ||
954 (rDuration == 0 && qd <= rEndDateTime.date()) ||
955 rDuration == -1)) {
956 // The date queried falls within the range of the event.
957 return true;
958 }
959 }
960 return false;
961}
962
963bool Recurrence::recursWeekly(const QDate &qd) const
964{
965 QDate dStart = mRecurStart.date();
966 if ((dStart.daysTo(qd)/7) % rFreq == 0) {
967 // The date is in a week which recurs
968 if (qd >= dStart
969 && ((rDuration > 0 && qd <= endDate()) ||
970 (rDuration == 0 && qd <= rEndDateTime.date()) ||
971 rDuration == -1)) {
972 // The date queried falls within the range of the event.
973 // check if the bits set match today.
974 int i = qd.dayOfWeek()-1;
975 if (rDays.testBit((uint) i))
976 return true;
977 }
978 }
979 return false;
980}
981
982bool Recurrence::recursMonthly(const QDate &qd) const
983{
984 QDate dStart = mRecurStart.date();
985 int year = qd.year();
986 int month = qd.month();
987 int day = qd.day();
988 // calculate how many months ahead this date is from the original
989 // event's date
990 int monthsAhead = (year - dStart.year()) * 12 + (month - dStart.month());
991 if ((monthsAhead % rFreq) == 0) {
992 // The date is in a month which recurs
993 if (qd >= dStart
994 && ((rDuration > 0 && qd <= endDate()) ||
995 (rDuration == 0 && qd <= rEndDateTime.date()) ||
996 rDuration == -1)) {
997 // The date queried falls within the range of the event.
998 QValueList<int> days;
999 int daysInMonth = qd.daysInMonth();
1000 if (recurs == rMonthlyDay)
1001 getMonthlyDayDays(days, daysInMonth);
1002 else if (recurs == rMonthlyPos)
1003 getMonthlyPosDays(days, daysInMonth, QDate(year, month, 1).dayOfWeek());
1004 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) {
1005 if (*it == day)
1006 return true;
1007 }
1008 // no dates matched
1009 }
1010 }
1011 return false;
1012}
1013
1014bool Recurrence::recursYearlyByMonth(const QDate &qd) const
1015{
1016 QDate dStart = mRecurStart.date();
1017 int startDay = dStart.day();
1018 int qday = qd.day();
1019 int qmonth = qd.month();
1020 int qyear = qd.year();
1021 bool match = (qday == startDay);
1022 if (!match && startDay == 29 && dStart.month() == 2) {
1023 // It's a recurrence on February 29th
1024 switch (mFeb29YearlyType) {
1025 case rFeb28:
1026 if (qday == 28 && qmonth == 2 && !QDate::leapYear(qyear))
1027 match = true;
1028 break;
1029 case rMar1:
1030 if (qday == 1 && qmonth == 3 && !QDate::leapYear(qyear)) {
1031 qmonth = 2;
1032 match = true;
1033 }
1034 break;
1035 case rFeb29:
1036 break;
1037 }
1038 }
1039
1040 if (match) {
1041 // The day of the month matches. Calculate how many years ahead
1042 // this date is from the original event's date.
1043 int yearsAhead = (qyear - dStart.year());
1044 if (yearsAhead % rFreq == 0) {
1045 // The date is in a year which recurs
1046 if (qd >= dStart
1047 && ((rDuration > 0 && qd <= endDate()) ||
1048 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1049 rDuration == -1)) {
1050 // The date queried falls within the range of the event.
1051 int i = qmonth;
1052 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
1053 if (i == *qlin.current())
1054 return true;
1055 }
1056 }
1057 }
1058 }
1059 return false;
1060}
1061
1062bool Recurrence::recursYearlyByPos(const QDate &qd) const
1063{
1064 QDate dStart = mRecurStart.date();
1065 int year = qd.year();
1066 int month = qd.month();
1067 int day = qd.day();
1068 // calculate how many years ahead this date is from the original
1069 // event's date
1070 int yearsAhead = (year - dStart.year());
1071 if (yearsAhead % rFreq == 0) {
1072 // The date is in a year which recurs
1073 if (qd >= dStart
1074 && ((rDuration > 0 && qd <= endDate()) ||
1075 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1076 rDuration == -1)) {
1077 // The date queried falls within the range of the event.
1078 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
1079 if (month == *qlin.current()) {
1080 // The month recurs
1081 QValueList<int> days;
1082 getMonthlyPosDays(days, qd.daysInMonth(), QDate(year, month, 1).dayOfWeek());
1083 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) {
1084 if (*it == day)
1085 return true;
1086 }
1087 }
1088 }
1089 }
1090 }
1091 return false;
1092}
1093
1094bool Recurrence::recursYearlyByDay(const QDate &qd) const
1095{
1096 QDate dStart = mRecurStart.date();
1097 // calculate how many years ahead this date is from the original
1098 // event's date
1099 int yearsAhead = (qd.year() - dStart.year());
1100 if (yearsAhead % rFreq == 0) {
1101 // The date is in a year which recurs
1102 if (qd >= dStart
1103 && ((rDuration > 0 && qd <= endDate()) ||
1104 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1105 rDuration == -1)) {
1106 // The date queried falls within the range of the event.
1107 int i = qd.dayOfYear();
1108 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
1109 if (i == *qlin.current())
1110 return true;
1111 }
1112 }
1113 }
1114 return false;
1115}
1116
1117/* Get the date of the next recurrence, after the specified date.
1118 * If 'last' is non-null, '*last' is set to true if the next recurrence is the
1119 * last recurrence, else false.
1120 * Reply = date of next recurrence, or invalid date if none.
1121 */
1122QDate Recurrence::getNextDateNoTime(const QDate &preDate, bool *last) const
1123{
1124 if (last)
1125 *last = false;
1126 QDate dStart = mRecurStart.date();
1127 if (preDate < dStart)
1128 return dStart;
1129 QDate earliestDate = preDate.addDays(1);
1130 QDate nextDate;
1131
1132 switch (recurs) {
1133 case rDaily:
1134 nextDate = dStart.addDays((dStart.daysTo(preDate)/rFreq + 1) * rFreq);
1135 break;
1136
1137 case rWeekly: {
1138 QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart
1139 int earliestDayOfWeek = earliestDate.dayOfWeek();
1140 int weeksAhead = start.daysTo(earliestDate) / 7;
1141 int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week
1142 weeksAhead -= notThisWeek; // latest week which recurred
1143 int weekday = 0;
1144 // First check for any remaining day this week, if this week is a recurring week
1145 if (!notThisWeek)
1146 weekday = getFirstDayInWeek(earliestDayOfWeek);
1147 // Check for a day in the next scheduled week
1148 if (!weekday && earliestDayOfWeek > 1)
1149 weekday = getFirstDayInWeek(rWeekStart) + rFreq*7;
1150 if (weekday)
1151 nextDate = start.addDays(weeksAhead*7 + weekday - 1);
1152 break;
1153 }
1154 case rMonthlyDay:
1155 case rMonthlyPos: {
1156 int startYear = dStart.year();
1157 int startMonth = dStart.month(); // 1..12
1158 int earliestYear = earliestDate.year();
1159 int monthsAhead = (earliestYear - startYear)*12 + earliestDate.month() - startMonth;
1160 int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month
1161 monthsAhead -= notThisMonth; // latest month which recurred
1162 // Check for the first later day in the current month
1163 if (!notThisMonth)
1164 nextDate = getFirstDateInMonth(earliestDate);
1165 if (!nextDate.isValid() && earliestDate.day() > 1) {
1166 // Check for a day in the next scheduled month
1167 int months = startMonth - 1 + monthsAhead + rFreq;
1168 nextDate = getFirstDateInMonth(QDate(startYear + months/12, months%12 + 1, 1));
1169 }
1170 break;
1171 }
1172 case rYearlyMonth:
1173 case rYearlyPos:
1174 case rYearlyDay: {
1175 int startYear = dStart.year();
1176 int yearsAhead = earliestDate.year() - startYear;
1177 int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year
1178 yearsAhead -= notThisYear; // latest year which recurred
1179 // Check for the first later date in the current year
1180 if (!notThisYear)
1181 nextDate = getFirstDateInYear(earliestDate);
1182 // Check for a date in the next scheduled year
1183 if (!nextDate.isValid() && earliestDate.dayOfYear() > 1)
1184 nextDate = getFirstDateInYear(QDate(startYear + yearsAhead + rFreq, 1, 1));
1185 break;
1186 }
1187 case rNone:
1188 default:
1189 return QDate();
1190 }
1191
1192 if (rDuration >= 0 && nextDate.isValid()) {
1193 // Check that the date found is within the range of the recurrence
1194 QDate end = endDate();
1195 if (nextDate > end)
1196 return QDate();
1197 if (last && nextDate == end)
1198 *last = true;
1199 }
1200 return nextDate;
1201}
1202
1203/* Get the date of the last previous recurrence, before the specified date.
1204 * Reply = date of previous recurrence, or invalid date if none.
1205 */
1206QDate Recurrence::getPreviousDateNoTime(const QDate &afterDate, bool *last) const
1207{
1208 if (last)
1209 *last = false;
1210 QDate dStart = mRecurStart.date();
1211 QDate latestDate = afterDate.addDays(-1);
1212 if (latestDate < dStart)
1213 return QDate();
1214 QDate prevDate;
1215
1216 switch (recurs) {
1217 case rDaily:
1218 prevDate = dStart.addDays((dStart.daysTo(latestDate) / rFreq) * rFreq);
1219 break;
1220
1221 case rWeekly: {
1222 QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart
1223 int latestDayOfWeek = latestDate.dayOfWeek();
1224 int weeksAhead = start.daysTo(latestDate) / 7;
1225 int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week
1226 weeksAhead -= notThisWeek; // latest week which recurred
1227 int weekday = 0;
1228 // First check for any previous day this week, if this week is a recurring week
1229 if (!notThisWeek)
1230 weekday = getLastDayInWeek(latestDayOfWeek);
1231 // Check for a day in the previous scheduled week
1232 if (!weekday) {
1233 int weekEnd = (rWeekStart + 5)%7 + 1;
1234 if (latestDayOfWeek < weekEnd) {
1235 if (!notThisWeek)
1236 weeksAhead -= rFreq;
1237 weekday = getLastDayInWeek(weekEnd);
1238 }
1239 }
1240 if (weekday)
1241 prevDate = start.addDays(weeksAhead*7 + weekday - 1);
1242 break;
1243 }
1244 case rMonthlyDay:
1245 case rMonthlyPos: {
1246 int startYear = dStart.year();
1247 int startMonth = dStart.month(); // 1..12
1248 int latestYear = latestDate.year();
1249 int monthsAhead = (latestYear - startYear)*12 + latestDate.month() - startMonth;
1250 int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month
1251 monthsAhead -= notThisMonth; // latest month which recurred
1252 // Check for the last earlier day in the current month
1253 if (!notThisMonth)
1254 prevDate = getLastDateInMonth(latestDate);
1255 if (!prevDate.isValid() && latestDate.day() < latestDate.daysInMonth()) {
1256 // Check for a day in the previous scheduled month
1257 if (!notThisMonth)
1258 monthsAhead -= rFreq;
1259 int months = startMonth + monthsAhead; // get the month after the one that recurs
1260 prevDate = getLastDateInMonth(QDate(startYear + months/12, months%12 + 1, 1).addDays(-1));
1261 }
1262 break;
1263 }
1264 case rYearlyMonth:
1265 case rYearlyPos:
1266 case rYearlyDay: {
1267 int startYear = dStart.year();
1268 int yearsAhead = latestDate.year() - startYear;
1269 int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year
1270 yearsAhead -= notThisYear; // latest year which recurred
1271 // Check for the first later date in the current year
1272 if (!notThisYear)
1273 prevDate = getLastDateInYear(latestDate);
1274 if (!prevDate.isValid() && latestDate.dayOfYear() < latestDate.daysInYear()) {
1275 // Check for a date in the next scheduled year
1276 if (!notThisYear)
1277 yearsAhead -= rFreq;
1278 prevDate = getLastDateInYear(QDate(startYear + yearsAhead, 12, 31));
1279 }
1280 break;
1281 }
1282 case rNone:
1283 default:
1284 return QDate();
1285 }
1286
1287 if (prevDate.isValid()) {
1288 // Check that the date found is within the range of the recurrence
1289 if (prevDate < dStart)
1290 return QDate();
1291 if (rDuration >= 0) {
1292 QDate end = endDate();
1293 if (prevDate >= end) {
1294 if (last)
1295 *last = true;
1296 return end;
1297 }
1298 }
1299 }
1300 return prevDate;
1301}
1302
1303void Recurrence::setDailySub(short type, int freq, int duration)
1304{
1305 recurs = type;
1306 rFreq = freq;
1307 rDuration = duration;
1308 rMonthPositions.clear();
1309 rMonthDays.clear();
1310 rYearNums.clear();
1311 if (type != rDaily)
1312 mFloats = false; // sub-daily types can't be floating
1313
1314 if (mParent) mParent->updated();
1315}
1316
1317void Recurrence::setYearly_(short type, Feb29Type feb29type, int freq, int duration)
1318{
1319 recurs = type;
1320 if (mCompatVersion < 310 && type == rYearlyDay) {
1321 mCompatRecurs = rYearlyDay;
1322 recurs = rYearlyMonth; // convert old yearly-by-day to yearly-by-month
1323 feb29type = rMar1; // retain the same day number in the year
1324 }
1325
1326 mFeb29YearlyType = feb29type;
1327 rFreq = freq;
1328 rDuration = duration;
1329 if (type != rYearlyPos)
1330 rMonthPositions.clear();
1331 rMonthDays.clear();
1332 if (mParent) mParent->updated();
1333}
1334
1335int Recurrence::recurCalc(PeriodFunc func, QDateTime &endtime) const
1336{
1337 QDate enddate = endtime.date();
1338 switch (func) {
1339 case END_DATE_AND_COUNT:
1340 if (rDuration < 0) {
1341 endtime = QDateTime();
1342 return 0; // infinite recurrence
1343 }
1344 if (rDuration == 0) {
1345 endtime = rEndDateTime;
1346 func = COUNT_TO_DATE;
1347 }
1348 break;
1349 case COUNT_TO_DATE:
1350 // Count recurrences up to and including the specified date/time.
1351 if (endtime < mRecurStart)
1352 return 0;
1353 if (rDuration == 0 && endtime > rEndDateTime)
1354 enddate = rEndDateTime.date();
1355 else if (!mFloats && mRecurStart.time() > endtime.time())
1356 enddate = enddate.addDays(-1);
1357 break;
1358 case NEXT_AFTER_DATE:
1359 // Find next recurrence AFTER endtime
1360 if (endtime < mRecurStart) {
1361 endtime = mRecurStart;
1362 return 1;
1363 }
1364 if (rDuration == 0 && endtime >= rEndDateTime) {
1365 endtime = QDateTime();
1366 return 0;
1367 }
1368 if (!mFloats && mRecurStart.time() > endtime.time())
1369 enddate = enddate.addDays(-1);
1370 break;
1371 default:
1372 endtime = QDateTime();
1373 return 0;
1374 }
1375
1376 int count = 0; // default = error
1377 bool timed = false;
1378 switch (recurs) {
1379 case rMinutely:
1380 timed = true;
1381 count = secondlyCalc(func, endtime, rFreq*60);
1382 break;
1383 case rHourly:
1384 timed = true;
1385 count = secondlyCalc(func, endtime, rFreq*3600);
1386 break;
1387 case rDaily:
1388 count = dailyCalc(func, enddate);
1389 break;
1390 case rWeekly:
1391 count = weeklyCalc(func, enddate);
1392 break;
1393 case rMonthlyPos:
1394 case rMonthlyDay:
1395 count = monthlyCalc(func, enddate);
1396 break;
1397 case rYearlyMonth:
1398 count = yearlyMonthCalc(func, enddate);
1399 break;
1400 case rYearlyPos:
1401 count = yearlyPosCalc(func, enddate);
1402 break;
1403 case rYearlyDay:
1404 count = yearlyDayCalc(func, enddate);
1405 break;
1406 default:
1407 break;
1408 }
1409
1410 switch (func) {
1411 case END_DATE_AND_COUNT:
1412 case NEXT_AFTER_DATE:
1413 if (count == 0)
1414 endtime = QDateTime();
1415 else if (!timed) {
1416 endtime.setDate(enddate);
1417 endtime.setTime(mRecurStart.time());
1418 }
1419 break;
1420 case COUNT_TO_DATE:
1421 break;
1422 }
1423 return count;
1424}
1425
1426int Recurrence::recurCalc(PeriodFunc func, QDate &enddate) const
1427{
1428 QDateTime endtime(enddate, QTime(23,59,59));
1429 switch (func) {
1430 case END_DATE_AND_COUNT:
1431 if (rDuration < 0) {
1432 enddate = QDate();
1433 return 0; // infinite recurrence
1434 }
1435 if (rDuration == 0) {
1436 enddate = rEndDateTime.date();
1437 func = COUNT_TO_DATE;
1438 }
1439 break;
1440 case COUNT_TO_DATE:
1441 // Count recurrences up to and including the specified date.
1442 if (enddate < mRecurStart.date())
1443 return 0;
1444 if (rDuration == 0 && enddate > rEndDateTime.date()) {
1445 enddate = rEndDateTime.date();
1446 endtime.setDate(enddate);
1447 }
1448 break;
1449 case NEXT_AFTER_DATE:
1450 if (enddate < mRecurStart.date()) {
1451 enddate = mRecurStart.date();
1452 return 1;
1453 }
1454 if (rDuration == 0 && enddate >= rEndDateTime.date()) {
1455 enddate = QDate();
1456 return 0;
1457 }
1458 break;
1459 default:
1460 enddate = QDate();
1461 return 0;
1462 }
1463
1464 int count = 0; // default = error
1465 bool timed = false;
1466 switch (recurs) {
1467 case rMinutely:
1468 timed = true;
1469 count = secondlyCalc(func, endtime, rFreq*60);
1470 break;
1471 case rHourly:
1472 timed = true;
1473 count = secondlyCalc(func, endtime, rFreq*3600);
1474 break;
1475 case rDaily:
1476 count = dailyCalc(func, enddate);
1477 break;
1478 case rWeekly:
1479 count = weeklyCalc(func, enddate);
1480 break;
1481 case rMonthlyPos:
1482 case rMonthlyDay:
1483 count = monthlyCalc(func, enddate);
1484 break;
1485 case rYearlyMonth:
1486 count = yearlyMonthCalc(func, enddate);
1487 break;
1488 case rYearlyPos:
1489 count = yearlyPosCalc(func, enddate);
1490 break;
1491 case rYearlyDay:
1492 count = yearlyDayCalc(func, enddate);
1493 break;
1494 default:
1495 break;
1496 }
1497
1498 switch (func) {
1499 case END_DATE_AND_COUNT:
1500 case NEXT_AFTER_DATE:
1501 if (count == 0)
1502 endtime = QDate();
1503 else if (timed)
1504 enddate = endtime.date();
1505 break;
1506 case COUNT_TO_DATE:
1507 break;
1508 }
1509 return count;
1510}
1511
1512/* Find count and, depending on 'func', the end date/time of a secondly recurrence.
1513 * Reply = total number of occurrences up to 'endtime', or 0 if error.
1514 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'endtime' is updated to the
1515 * recurrence end date/time.
1516 */
1517int Recurrence::secondlyCalc(PeriodFunc func, QDateTime &endtime, int freq) const
1518{
1519 switch (func) {
1520 case END_DATE_AND_COUNT:
1521 endtime = mRecurStart.addSecs((rDuration + mRecurExDatesCount - 1) * freq);
1522 return rDuration + mRecurExDatesCount;
1523 case COUNT_TO_DATE: {
1524 int n = mRecurStart.secsTo(endtime)/freq + 1;
1525 if (rDuration > 0 && n > rDuration + mRecurExDatesCount)
1526 return rDuration + mRecurExDatesCount;
1527 return n;
1528 }
1529 case NEXT_AFTER_DATE: {
1530 int count = mRecurStart.secsTo(endtime) / freq + 2;
1531 if (rDuration > 0 && count > rDuration)
1532 return 0;
1533 endtime = mRecurStart.addSecs((count - 1)*freq);
1534 return count;
1535 }
1536 }
1537 return 0;
1538}
1539
1540/* Find count and, depending on 'func', the end date of a daily recurrence.
1541 * Reply = total number of occurrences up to 'enddate', or 0 if error.
1542 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
1543 * recurrence end date.
1544 */
1545int Recurrence::dailyCalc(PeriodFunc func, QDate &enddate) const
1546{
1547 QDate dStart = mRecurStart.date();
1548 switch (func) {
1549 case END_DATE_AND_COUNT:
1550 enddate = dStart.addDays((rDuration + mRecurExDatesCount - 1) * rFreq);
1551 return rDuration + mRecurExDatesCount;
1552 case COUNT_TO_DATE: {
1553 int n = dStart.daysTo(enddate)/rFreq + 1;
1554 if (rDuration > 0 && n > rDuration + mRecurExDatesCount)
1555 return rDuration + mRecurExDatesCount;
1556 return n;
1557 }
1558 case NEXT_AFTER_DATE: {
1559 int count = dStart.daysTo(enddate) / rFreq + 2;
1560 if (rDuration > 0 && count > rDuration)
1561 return 0;
1562 enddate = dStart.addDays((count - 1)*rFreq);
1563 return count;
1564 }
1565 }
1566 return 0;
1567}
1568
1569/* Find count and, depending on 'func', the end date of a weekly recurrence.
1570 * Reply = total number of occurrences up to 'enddate', or 0 if error.
1571 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
1572 * recurrence end date.
1573 */
1574int Recurrence::weeklyCalc(PeriodFunc func, QDate &enddate) const
1575{
1576 int daysPerWeek = 0;
1577 for (int i = 0; i < 7; ++i) {
1578 if (rDays.testBit((uint)i))
1579 ++daysPerWeek;
1580 }
1581 if (!daysPerWeek)
1582 return 0; // there are no days to recur on
1583
1584 switch (func) {
1585 case END_DATE_AND_COUNT:
1586 return weeklyCalcEndDate(enddate, daysPerWeek);
1587 case COUNT_TO_DATE:
1588 return weeklyCalcToDate(enddate, daysPerWeek);
1589 case NEXT_AFTER_DATE:
1590 return weeklyCalcNextAfter(enddate, daysPerWeek);
1591 }
1592 return 0;
1593}
1594
1595int Recurrence::weeklyCalcEndDate(QDate &enddate, int daysPerWeek) const
1596{
1597 int startDayOfWeek = mRecurStart.date().dayOfWeek(); // 1..7
1598 int countGone = 0;
1599 int daysGone = 0;
1600 uint countTogo = rDuration + mRecurExDatesCount;
1601 if (startDayOfWeek != rWeekStart) {
1602 // Check what remains of the start week
1603 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) {
1604 ++daysGone;
1605 if (rDays.testBit((uint)i)) {
1606 ++countGone;
1607 if (--countTogo == 0)
1608 break;
1609 }
1610 }
1611 daysGone += 7 * (rFreq - 1);
1612 }
1613 if (countTogo) {
1614 // Skip the remaining whole weeks
1615 // Leave at least 1 recurrence remaining, in order to get its date
1616 int wholeWeeks = (countTogo - 1) / daysPerWeek;
1617 daysGone += wholeWeeks * 7 * rFreq;
1618 countGone += wholeWeeks * daysPerWeek;
1619 countTogo -= wholeWeeks * daysPerWeek;
1620 // Check the last week in the recurrence
1621 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
1622 ++daysGone;
1623 if (rDays.testBit((uint)i)) {
1624 ++countGone;
1625 if (--countTogo == 0)
1626 break;
1627 }
1628 }
1629 }
1630 enddate = mRecurStart.date().addDays(daysGone);
1631 return countGone;
1632}
1633
1634int Recurrence::weeklyCalcToDate(const QDate &enddate, int daysPerWeek) const
1635{
1636 QDate dStart = mRecurStart.date();
1637 int startDayOfWeek = dStart.dayOfWeek(); // 1..7
1638 int countGone = 0;
1639 int daysGone = 0;
1640 int totalDays = dStart.daysTo(enddate) + 1;
1641 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
1642
1643 if (startDayOfWeek != rWeekStart) {
1644 // Check what remains of the start week
1645 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) {
1646 if (rDays.testBit((uint)i)) {
1647 if (++countGone >= countMax)
1648 return countMax;
1649 }
1650 if (++daysGone == totalDays)
1651 return countGone;
1652 }
1653 daysGone += 7 * (rFreq - 1);
1654 if (daysGone >= totalDays)
1655 return countGone;
1656 }
1657 // Skip the remaining whole weeks
1658 int wholeWeeks = (totalDays - daysGone) / 7;
1659 countGone += (wholeWeeks / rFreq) * daysPerWeek;
1660 if (countGone >= countMax)
1661 return countMax;
1662 daysGone += wholeWeeks * 7;
1663 if (daysGone >= totalDays // have we reached the end date?
1664 || wholeWeeks % rFreq) // is end week a recurrence week?
1665 return countGone;
1666
1667 // Check the last week in the recurrence
1668 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
1669 if (rDays.testBit((uint)i)) {
1670 if (++countGone >= countMax)
1671 return countMax;
1672 }
1673 if (++daysGone == totalDays)
1674 return countGone;
1675 }
1676 return countGone;
1677}
1678
1679int Recurrence::weeklyCalcNextAfter(QDate &enddate, int daysPerWeek) const
1680{
1681 QDate dStart = mRecurStart.date();
1682 int startDayOfWeek = dStart.dayOfWeek(); // 1..7
1683 int totalDays = dStart.daysTo(enddate) + 1;
1684 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
1685 int countGone = 0;
1686 int daysGone = 0;
1687 int recurWeeks;
1688
1689 if (startDayOfWeek != rWeekStart) {
1690 // Check what remains of the start week
1691 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) {
1692 ++daysGone;
1693 if (rDays.testBit((uint)i)) {
1694 ++countGone;
1695 if (daysGone > totalDays)
1696 goto ex;
1697 if (--countTogo == 0)
1698 return 0;
1699 }
1700 }
1701 daysGone += 7 * (rFreq - 1);
1702 }
1703
1704 // Skip the remaining whole weeks
1705 recurWeeks = (totalDays - daysGone) / (7 * rFreq);
1706 if (recurWeeks) {
1707 int n = recurWeeks * daysPerWeek;
1708 if (static_cast<uint>(n) > countTogo)
1709 return 0; // reached end of recurrence
1710 countGone += n;
1711 countTogo -= n;
1712 daysGone += recurWeeks * 7 * rFreq;
1713 }
1714
1715 // Check the last week or two in the recurrence
1716 for ( ; ; ) {
1717 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
1718 ++daysGone;
1719 if (rDays.testBit((uint)i)) {
1720 ++countGone;
1721 if (daysGone > totalDays)
1722 goto ex;
1723 if (--countTogo == 0)
1724 return 0;
1725 }
1726 }
1727 daysGone += 7 * (rFreq - 1);
1728 }
1729ex:
1730 enddate = dStart.addDays(daysGone);
1731 return countGone;
1732}
1733
1734/* Find count and, depending on 'func', the end date of a monthly recurrence.
1735 * Reply = total number of occurrences up to 'enddate', or 0 if error.
1736 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
1737 * recurrence end date.
1738 */
1739struct Recurrence::MonthlyData {
1740 const Recurrence *recurrence;
1741 int year; // current year
1742 int month; // current month 0..11
1743 int day; // current day of month 1..31
1744 bool varies; // true if recurring days vary between different months
1745 private:
1746 QValueList<int> days28, days29, days30, days31; // recurring days in months of each length
1747 QValueList<int> *recurDays[4];
1748 public:
1749 MonthlyData(const Recurrence* r, const QDate &date)
1750 : recurrence(r), year(date.year()), month(date.month()-1), day(date.day())
1751 { recurDays[0] = &days28;
1752 recurDays[1] = &days29;
1753 recurDays[2] = &days30;
1754 recurDays[3] = &days31;
1755 varies = (recurrence->recurs == rMonthlyPos)
1756 ? true : recurrence->getMonthlyDayDays(days31, 31);
1757 }
1758 const QValueList<int>* dayList() const {
1759 if (!varies)
1760 return &days31;
1761 QDate startOfMonth(year, month + 1, 1);
1762 int daysInMonth = startOfMonth.daysInMonth();
1763 QValueList<int>* days = recurDays[daysInMonth - 28];
1764 if (recurrence->recurs == rMonthlyPos)
1765 recurrence->getMonthlyPosDays(*days, daysInMonth, startOfMonth.dayOfWeek());
1766 else if (days->isEmpty())
1767 recurrence->getMonthlyDayDays(*days, daysInMonth);
1768 return days;
1769 }
1770 int yearMonth() const { return year*12 + month; }
1771 void addMonths(int diff) { month += diff; year += month / 12; month %= 12; }
1772 QDate date() const { return QDate(year, month + 1, day); }
1773};
1774
1775int Recurrence::monthlyCalc(PeriodFunc func, QDate &enddate) const
1776{
1777 if (recurs == rMonthlyPos && rMonthPositions.isEmpty()
1778 || recurs == rMonthlyDay && rMonthDays.isEmpty())
1779 return 0;
1780
1781 MonthlyData data(this, mRecurStart.date());
1782 switch (func) {
1783 case END_DATE_AND_COUNT:
1784 return monthlyCalcEndDate(enddate, data);
1785 case COUNT_TO_DATE:
1786 return monthlyCalcToDate(enddate, data);
1787 case NEXT_AFTER_DATE:
1788 return monthlyCalcNextAfter(enddate, data);
1789 }
1790 return 0;
1791}
1792
1793int Recurrence::monthlyCalcEndDate(QDate &enddate, MonthlyData &data) const
1794{
1795 uint countTogo = rDuration + mRecurExDatesCount;
1796 int countGone = 0;
1797 QValueList<int>::ConstIterator it;
1798 const QValueList<int>* days = data.dayList();
1799
1800 if (data.day > 1) {
1801 // Check what remains of the start month
1802 for (it = days->begin(); it != days->end(); ++it) {
1803 if (*it >= data.day) {
1804 ++countGone;
1805 if (--countTogo == 0) {
1806 data.day = *it;
1807 break;
1808 }
1809 }
1810 }
1811 if (countTogo) {
1812 data.day = 1;
1813 data.addMonths(rFreq);
1814 }
1815 }
1816 if (countTogo) {
1817 if (data.varies) {
1818 // The number of recurrence days varies from month to month,
1819 // so we need to check month by month.
1820 for ( ; ; ) {
1821 days = data.dayList();
1822 uint n = days->count(); // number of recurrence days in this month
1823 if (n >= countTogo)
1824 break;
1825 countTogo -= n;
1826 countGone += n;
1827 data.addMonths(rFreq);
1828 }
1829 } else {
1830 // The number of recurrences is the same every month,
1831 // so skip the month-by-month check.
1832 // Skip the remaining whole months, but leave at least
1833 // 1 recurrence remaining, in order to get its date.
1834 int daysPerMonth = days->count();
1835 int wholeMonths = (countTogo - 1) / daysPerMonth;
1836 data.addMonths(wholeMonths * rFreq);
1837 countGone += wholeMonths * daysPerMonth;
1838 countTogo -= wholeMonths * daysPerMonth;
1839 }
1840 if (countTogo) {
1841 // Check the last month in the recurrence
1842 for (it = days->begin(); it != days->end(); ++it) {
1843 ++countGone;
1844 if (--countTogo == 0) {
1845 data.day = *it;
1846 break;
1847 }
1848 }
1849 }
1850 }
1851 enddate = data.date();
1852 return countGone;
1853}
1854
1855int Recurrence::monthlyCalcToDate(const QDate &enddate, MonthlyData &data) const
1856{
1857 int countGone = 0;
1858 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
1859 int endYear = enddate.year();
1860 int endMonth = enddate.month() - 1; // zero-based
1861 int endDay = enddate.day();
1862 int endYearMonth = endYear*12 + endMonth;
1863 QValueList<int>::ConstIterator it;
1864 const QValueList<int>* days = data.dayList();
1865
1866 if (data.day > 1) {
1867 // Check what remains of the start month
1868 for (it = days->begin(); it != days->end(); ++it) {
1869 if (*it >= data.day) {
1870 if (data.yearMonth() == endYearMonth && *it > endDay)
1871 return countGone;
1872 if (++countGone >= countMax)
1873 return countMax;
1874 }
1875 }
1876 data.day = 1;
1877 data.addMonths(rFreq);
1878 }
1879
1880 if (data.varies) {
1881 // The number of recurrence days varies from month to month,
1882 // so we need to check month by month.
1883 while (data.yearMonth() < endYearMonth) {
1884 countGone += data.dayList()->count();
1885 if (countGone >= countMax)
1886 return countMax;
1887 data.addMonths(rFreq);
1888 }
1889 days = data.dayList();
1890 } else {
1891 // The number of recurrences is the same every month,
1892 // so skip the month-by-month check.
1893 // Skip the remaining whole months.
1894 int daysPerMonth = days->count();
1895 int wholeMonths = endYearMonth - data.yearMonth();
1896 countGone += (wholeMonths / rFreq) * daysPerMonth;
1897 if (countGone >= countMax)
1898 return countMax;
1899 if (wholeMonths % rFreq)
1900 return countGone; // end year isn't a recurrence year
1901 data.year = endYear;
1902 data.month = endMonth;
1903 }
1904
1905 // Check the last month in the recurrence
1906 for (it = days->begin(); it != days->end(); ++it) {
1907 if (*it > endDay)
1908 return countGone;
1909 if (++countGone >= countMax)
1910 return countMax;
1911 }
1912 return countGone;
1913}
1914
1915int Recurrence::monthlyCalcNextAfter(QDate &enddate, MonthlyData &data) const
1916{
1917 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
1918 int countGone = 0;
1919 int endYear = enddate.year();
1920 int endDay = enddate.day();
1921 int endYearMonth = endYear*12 + enddate.month() - 1;
1922 QValueList<int>::ConstIterator it;
1923 const QValueList<int>* days = data.dayList();
1924
1925 if (data.day > 1) {
1926 // Check what remains of the start month
1927 for (it = days->begin(); it != days->end(); ++it) {
1928 if (*it >= data.day) {
1929 ++countGone;
1930 if (data.yearMonth() == endYearMonth && *it > endDay) {
1931 data.day = *it;
1932 goto ex;
1933 }
1934 if (--countTogo == 0)
1935 return 0;
1936 }
1937 }
1938 data.day = 1;
1939 data.addMonths(rFreq);
1940 }
1941
1942 if (data.varies) {
1943 // The number of recurrence days varies from month to month,
1944 // so we need to check month by month.
1945 while (data.yearMonth() <= endYearMonth) {
1946 days = data.dayList();
1947 uint n = days->count(); // number of recurrence days in this month
1948 if (data.yearMonth() == endYearMonth && days->last() > endDay)
1949 break;
1950 if (n >= countTogo)
1951 return 0;
1952 countGone += n;
1953 countTogo -= n;
1954 data.addMonths(rFreq);
1955 }
1956 days = data.dayList();
1957 } else {
1958 // The number of recurrences is the same every month,
1959 // so skip the month-by-month check.
1960 // Skip the remaining whole months to at least end year/month.
1961 int daysPerMonth = days->count();
1962 int elapsed = endYearMonth - data.yearMonth();
1963 int recurMonths = (elapsed + rFreq - 1) / rFreq;
1964 if (elapsed % rFreq == 0 && days->last() <= endDay)
1965 ++recurMonths; // required month is after endYearMonth
1966 if (recurMonths) {
1967 int n = recurMonths * daysPerMonth;
1968 if (static_cast<uint>(n) > countTogo)
1969 return 0; // reached end of recurrence
1970 countTogo -= n;
1971 countGone += n;
1972 data.addMonths(recurMonths * rFreq);
1973 }
1974 }
1975
1976 // Check the last month in the recurrence
1977 for (it = days->begin(); it != days->end(); ++it) {
1978 ++countGone;
1979 if (data.yearMonth() > endYearMonth || *it > endDay) {
1980 data.day = *it;
1981 break;
1982 }
1983 if (--countTogo == 0)
1984 return 0;
1985 }
1986ex:
1987 enddate = data.date();
1988 return countGone;
1989}
1990
1991
1992/* Find count and, depending on 'func', the end date of an annual recurrence by date.
1993 * Reply = total number of occurrences up to 'enddate', or 0 if error.
1994 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
1995 * recurrence end date.
1996 */
1997struct Recurrence::YearlyMonthData {
1998 const Recurrence *recurrence;
1999 int year; // current year
2000 int month; // current month 1..12
2001 int day; // current day of month 1..31
2002 bool leapyear; // true if February 29th recurs and current year is a leap year
2003 bool feb29; // true if February 29th recurs
2004 private:
2005 QValueList<int> months; // recurring months in non-leap years 1..12
2006 QValueList<int> leapMonths; // recurring months in leap years 1..12
2007 public:
2008 YearlyMonthData(const Recurrence* r, const QDate &date)
2009 : recurrence(r), year(date.year()), month(date.month()), day(date.day())
2010 { feb29 = recurrence->getYearlyMonthMonths(day, months, leapMonths);
2011 leapyear = feb29 && QDate::leapYear(year);
2012 }
2013 const QValueList<int>* monthList() const
2014 { return leapyear ? &leapMonths : &months; }
2015 const QValueList<int>* leapMonthList() const { return &leapMonths; }
2016 QDate date() const { return QDate(year, month, day); }
2017};
2018
2019int Recurrence::yearlyMonthCalc(PeriodFunc func, QDate &enddate) const
2020{
2021 if (rYearNums.isEmpty())
2022 return 0;
2023 YearlyMonthData data(this, mRecurStart.date());
2024 switch (func) {
2025 case END_DATE_AND_COUNT:
2026 return yearlyMonthCalcEndDate(enddate, data);
2027 case COUNT_TO_DATE:
2028 return yearlyMonthCalcToDate(enddate, data);
2029 case NEXT_AFTER_DATE:
2030 return yearlyMonthCalcNextAfter(enddate, data);
2031 }
2032 return 0;
2033}
2034
2035// Find total count and end date of an annual recurrence by date.
2036// Reply = total number of occurrences.
2037int Recurrence::yearlyMonthCalcEndDate(QDate &enddate, YearlyMonthData &data) const
2038{
2039 uint countTogo = rDuration + mRecurExDatesCount;
2040 int countGone = 0;
2041 QValueList<int>::ConstIterator it;
2042 const QValueList<int>* mons = data.monthList(); // get recurring months for this year
2043
2044 if (data.month > 1) {
2045 // Check what remains of the start year
2046 for (it = mons->begin(); it != mons->end(); ++it) {
2047 if (*it >= data.month) {
2048 ++countGone;
2049 if (--countTogo == 0) {
2050 data.month = *it;
2051 if (data.month == 2 && data.feb29 && !data.leapyear) {
2052 // The recurrence should end on February 29th, but it's a non-leap year
2053 switch (mFeb29YearlyType) {
2054 case rFeb28:
2055 data.day = 28;
2056 break;
2057 case rMar1:
2058 data.month = 3;
2059 data.day = 1;
2060 break;
2061 case rFeb29:
2062 break;
2063 }
2064 }
2065 break;
2066 }
2067 }
2068 }
2069 if (countTogo) {
2070 data.month = 1;
2071 data.year += rFreq;
2072 }
2073 }
2074 if (countTogo) {
2075 if (data.feb29 && mFeb29YearlyType == rFeb29) {
2076 // The number of recurrences is different on leap years,
2077 // so check year-by-year.
2078 for ( ; ; ) {
2079 mons = data.monthList();
2080 uint n = mons->count();
2081 if (n >= countTogo)
2082 break;
2083 countTogo -= n;
2084 countGone += n;
2085 data.year += rFreq;
2086 }
2087 } else {
2088 // The number of recurrences is the same every year,
2089 // so skip the year-by-year check.
2090 // Skip the remaining whole years, but leave at least
2091 // 1 recurrence remaining, in order to get its date.
2092 int monthsPerYear = mons->count();
2093 int wholeYears = (countTogo - 1) / monthsPerYear;
2094 data.year += wholeYears * rFreq;
2095 countGone += wholeYears * monthsPerYear;
2096 countTogo -= wholeYears * monthsPerYear;
2097 }
2098 if (countTogo) {
2099 // Check the last year in the recurrence
2100 for (it = mons->begin(); it != mons->end(); ++it) {
2101 ++countGone;
2102 if (--countTogo == 0) {
2103 data.month = *it;
2104 if (data.month == 2 && data.feb29 && !QDate::leapYear(data.year)) {
2105 // The recurrence should end on February 29th, but it's a non-leap year
2106 switch (mFeb29YearlyType) {
2107 case rFeb28:
2108 data.day = 28;
2109 break;
2110 case rMar1:
2111 data.month = 3;
2112 data.day = 1;
2113 break;
2114 case rFeb29:
2115 break;
2116 }
2117 }
2118 break;
2119 }
2120 }
2121 }
2122 }
2123 enddate = data.date();
2124 return countGone;
2125}
2126
2127// Find count of an annual recurrence by date.
2128// Reply = total number of occurrences up to 'enddate'.
2129int Recurrence::yearlyMonthCalcToDate(const QDate &enddate, YearlyMonthData &data) const
2130{
2131 int countGone = 0;
2132 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
2133 int endYear = enddate.year();
2134 int endMonth = enddate.month();
2135 int endDay = enddate.day();
2136 if (endDay < data.day) {
2137 /* The end day of the month is earlier than the recurrence day of the month.
2138 * If Feb 29th recurs and:
2139 * 1) it recurs on Feb 28th in non-leap years, don't adjust the end month
2140 * if enddate is Feb 28th on a non-leap year.
2141 * 2) it recurs on Mar 1st in non-leap years, allow the end month to be
2142 * adjusted to February, to simplify calculations.
2143 */
2144 if (data.feb29 && !QDate::leapYear(endYear)
2145 && mFeb29YearlyType == rFeb28 && endDay == 28 && endMonth == 2) {
2146 }
2147 else if (--endMonth == 0) {
2148 endMonth = 12;
2149 --endYear;
2150 }
2151 }
2152 QValueList<int>::ConstIterator it;
2153 const QValueList<int>* mons = data.monthList();
2154
2155 if (data.month > 1) {
2156 // Check what remains of the start year
2157 for (it = mons->begin(); it != mons->end(); ++it) {
2158 if (*it >= data.month) {
2159 if (data.year == endYear && *it > endMonth)
2160 return countGone;
2161 if (++countGone >= countMax)
2162 return countMax;
2163 }
2164 }
2165 data.month = 1;
2166 data.year += rFreq;
2167 }
2168 if (data.feb29 && mFeb29YearlyType == rFeb29) {
2169 // The number of recurrences is different on leap years,
2170 // so check year-by-year.
2171 while (data.year < endYear) {
2172 countGone += data.monthList()->count();
2173 if (countGone >= countMax)
2174 return countMax;
2175 data.year += rFreq;
2176 }
2177 mons = data.monthList();
2178 } else {
2179 // The number of recurrences is the same every year,
2180 // so skip the year-by-year check.
2181 // Skip the remaining whole years.
2182 int monthsPerYear = mons->count();
2183 int wholeYears = endYear - data.year;
2184 countGone += (wholeYears / rFreq) * monthsPerYear;
2185 if (countGone >= countMax)
2186 return countMax;
2187 if (wholeYears % rFreq)
2188 return countGone; // end year isn't a recurrence year
2189 data.year = endYear;
2190 }
2191
2192 // Check the last year in the recurrence
2193 for (it = mons->begin(); it != mons->end(); ++it) {
2194 if (*it > endMonth)
2195 return countGone;
2196 if (++countGone >= countMax)
2197 return countMax;
2198 }
2199 return countGone;
2200}
2201
2202// Find count and date of first recurrence after 'enddate' of an annual recurrence by date.
2203// Reply = total number of occurrences up to 'enddate'.
2204int Recurrence::yearlyMonthCalcNextAfter(QDate &enddate, YearlyMonthData &data) const
2205{
2206 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
2207 int countGone = 0;
2208 int endYear = enddate.year();
2209 int endMonth = enddate.month();
2210 int endDay = enddate.day();
2211 bool mar1TooEarly = false;
2212 bool feb28ok = false;
2213 if (endDay < data.day) {
2214 if (data.feb29 && mFeb29YearlyType == rMar1 && endMonth == 3)
2215 mar1TooEarly = true;
2216 if (data.feb29 && mFeb29YearlyType == rFeb28 && endMonth == 2 && endDay == 28)
2217 feb28ok = true;
2218 else if (--endMonth == 0) {
2219 endMonth = 12;
2220 --endYear;
2221 }
2222 }
2223 QValueList<int>::ConstIterator it;
2224 const QValueList<int>* mons = data.monthList();
2225
2226 if (data.month > 1) {
2227 // Check what remains of the start year
2228 for (it = mons->begin(); it != mons->end(); ++it) {
2229 if (*it >= data.month) {
2230 ++countGone;
2231 if (data.year == endYear
2232 && ( *it > endMonth && (*it > 3 || !mar1TooEarly)
2233 || *it == 2 && feb28ok && data.leapyear)) {
2234 if (*it == 2 && data.feb29 && !data.leapyear) {
2235 // The next recurrence should be on February 29th, but it's a non-leap year
2236 switch (mFeb29YearlyType) {
2237 case rFeb28:
2238 data.month = 2;
2239 data.day = 28;
2240 break;
2241 case rMar1:
2242 data.month = 3;
2243 data.day = 1;
2244 break;
2245 case rFeb29: // impossible in this context!
2246 break;
2247 }
2248 }
2249 else
2250 data.month = *it;
2251 goto ex;
2252 }
2253 if (--countTogo == 0)
2254 return 0;
2255 }
2256 }
2257 data.month = 1;
2258 data.year += rFreq;
2259 }
2260
2261 if (data.feb29 && mFeb29YearlyType == rFeb29) {
2262 // The number of recurrences is different on leap years,
2263 // so check year-by-year.
2264 while (data.year <= endYear) {
2265 mons = data.monthList();
2266 if (data.year == endYear && mons->last() > endMonth)
2267 break;
2268 uint n = mons->count();
2269 if (n >= countTogo)
2270 break;
2271 countTogo -= n;
2272 countGone += n;
2273 data.year += rFreq;
2274 }
2275 mons = data.monthList();
2276 } else {
2277 // The number of recurrences is the same every year,
2278 // so skip the year-by-year check.
2279 // Skip the remaining whole years to at least endYear.
2280 int monthsPerYear = mons->count();
2281 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
2282 if ((endYear - data.year)%rFreq == 0
2283 && mons->last() <= endMonth)
2284 ++recurYears; // required year is after endYear
2285 if (recurYears) {
2286 int n = recurYears * monthsPerYear;
2287 if (static_cast<uint>(n) > countTogo)
2288 return 0; // reached end of recurrence
2289 countTogo -= n;
2290 countGone += n;
2291 data.year += recurYears * rFreq;
2292 }
2293 }
2294
2295 // Check the last year in the recurrence
2296 for (it = mons->begin(); it != mons->end(); ++it) {
2297 ++countGone;
2298 if (data.year > endYear
2299 || ( *it > endMonth && (*it > 3 || !mar1TooEarly)
2300 || *it == 2 && feb28ok && QDate::leapYear(data.year))) {
2301 if (*it == 2 && data.feb29 && !QDate::leapYear(data.year)) {
2302 // The next recurrence should be on February 29th, but it's a non-leap year
2303 switch (mFeb29YearlyType) {
2304 case rFeb28:
2305 data.month = 2;
2306 data.day = 28;
2307 break;
2308 case rMar1:
2309 data.month = 3;
2310 data.day = 1;
2311 break;
2312 case rFeb29: // impossible in this context!
2313 break;
2314 }
2315 }
2316 else
2317 data.month = *it;
2318 break;
2319 }
2320 if (--countTogo == 0)
2321 return 0;
2322 }
2323ex:
2324 enddate = data.date();
2325 return countGone;
2326}
2327
2328
2329/* Find count and, depending on 'func', the end date of an annual recurrence by date.
2330 * Reply = total number of occurrences up to 'enddate', or 0 if error.
2331 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
2332 * recurrence end date.
2333 */
2334struct Recurrence::YearlyPosData {
2335 const Recurrence *recurrence;
2336 int year; // current year
2337 int month; // current month 1..12
2338 int day; // current day of month 1..31
2339 int daysPerMonth; // number of days which recur each month, or -1 if variable
2340 int count; // number of days which recur each year, or -1 if variable
2341 bool varies; // true if number of days varies from year to year
2342 private:
2343 mutable QValueList<int> days;
2344 public:
2345 YearlyPosData(const Recurrence* r, const QDate &date)
2346 : recurrence(r), year(date.year()), month(date.month()), day(date.day()), count(-1)
2347 { if ((daysPerMonth = r->countMonthlyPosDays()) > 0)
2348 count = daysPerMonth * r->rYearNums.count();
2349 varies = (daysPerMonth < 0);
2350 }
2351 const QValueList<int>* dayList() const {
2352 QDate startOfMonth(year, month, 1);
2353 recurrence->getMonthlyPosDays(days, startOfMonth.daysInMonth(), startOfMonth.dayOfWeek());
2354 return &days;
2355 }
2356 int yearMonth() const { return year*12 + month - 1; }
2357 void addMonths(int diff) { month += diff - 1; year += month / 12; month = month % 12 + 1; }
2358 QDate date() const { return QDate(year, month, day); }
2359};
2360
2361int Recurrence::yearlyPosCalc(PeriodFunc func, QDate &enddate) const
2362{
2363 if (rYearNums.isEmpty() || rMonthPositions.isEmpty())
2364 return 0;
2365 YearlyPosData data(this, mRecurStart.date());
2366 switch (func) {
2367 case END_DATE_AND_COUNT:
2368 return yearlyPosCalcEndDate(enddate, data);
2369 case COUNT_TO_DATE:
2370 return yearlyPosCalcToDate(enddate, data);
2371 case NEXT_AFTER_DATE:
2372 return yearlyPosCalcNextAfter(enddate, data);
2373 }
2374 return 0;
2375}
2376
2377int Recurrence::yearlyPosCalcEndDate(QDate &enddate, YearlyPosData &data) const
2378{
2379 uint countTogo = rDuration + mRecurExDatesCount;
2380 int countGone = 0;
2381 QValueList<int>::ConstIterator id;
2382 const QValueList<int>* days;
2383
2384 if (data.month > 1 || data.day > 1) {
2385 // Check what remains of the start year
2386 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2387 if (*im.current() >= data.month) {
2388 // Check what remains of the start month
2389 if (data.day > 1 || data.varies
2390 || static_cast<uint>(data.daysPerMonth) >= countTogo) {
2391 data.month = *im.current();
2392 days = data.dayList();
2393 for (id = days->begin(); id != days->end(); ++id) {
2394 if (*id >= data.day) {
2395 ++countGone;
2396 if (--countTogo == 0) {
2397 data.month = *im.current();
2398 data.day = *id;
2399 goto ex;
2400 }
2401 }
2402 }
2403 data.day = 1;
2404 } else {
2405 // The number of days per month is constant, so skip
2406 // the whole month.
2407 countTogo -= data.daysPerMonth;
2408 countGone += data.daysPerMonth;
2409 }
2410 }
2411 }
2412 data.month = 1;
2413 data.year += rFreq;
2414 }
2415
2416 if (data.varies) {
2417 // The number of recurrences varies from year to year.
2418 for ( ; ; ) {
2419 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2420 data.month = *im.current();
2421 days = data.dayList();
2422 int n = days->count();
2423 if (static_cast<uint>(n) >= countTogo) {
2424 // Check the last month in the recurrence
2425 for (id = days->begin(); id != days->end(); ++id) {
2426 ++countGone;
2427 if (--countTogo == 0) {
2428 data.day = *id;
2429 goto ex;
2430 }
2431 }
2432 }
2433 countTogo -= n;
2434 countGone += n;
2435 }
2436 data.year += rFreq;
2437 }
2438 } else {
2439 // The number of recurrences is the same every year,
2440 // so skip the year-by-year check.
2441 // Skip the remaining whole years, but leave at least
2442 // 1 recurrence remaining, in order to get its date.
2443 int wholeYears = (countTogo - 1) / data.count;
2444 data.year += wholeYears * rFreq;
2445 countGone += wholeYears * data.count;
2446 countTogo -= wholeYears * data.count;
2447
2448 // Check the last year in the recurrence.
2449 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2450 if (static_cast<uint>(data.daysPerMonth) >= countTogo) {
2451 // Check the last month in the recurrence
2452 data.month = *im.current();
2453 days = data.dayList();
2454 for (id = days->begin(); id != days->end(); ++id) {
2455 ++countGone;
2456 if (--countTogo == 0) {
2457 data.day = *id;
2458 goto ex;
2459 }
2460 }
2461 }
2462 countTogo -= data.daysPerMonth;
2463 countGone += data.daysPerMonth;
2464 }
2465 data.year += rFreq;
2466 }
2467ex:
2468 enddate = data.date();
2469 return countGone;
2470}
2471
2472int Recurrence::yearlyPosCalcToDate(const QDate &enddate, YearlyPosData &data) const
2473{
2474 int countGone = 0;
2475 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
2476 int endYear = enddate.year();
2477 int endMonth = enddate.month();
2478 int endDay = enddate.day();
2479 if (endDay < data.day && --endMonth == 0) {
2480 endMonth = 12;
2481 --endYear;
2482 }
2483 int endYearMonth = endYear*12 + endMonth;
2484 QValueList<int>::ConstIterator id;
2485 const QValueList<int>* days;
2486
2487 if (data.month > 1 || data.day > 1) {
2488 // Check what remains of the start year
2489 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2490 if (*im.current() >= data.month) {
2491 data.month = *im.current();
2492 if (data.yearMonth() > endYearMonth)
2493 return countGone;
2494 // Check what remains of the start month
2495 bool lastMonth = (data.yearMonth() == endYearMonth);
2496 if (lastMonth || data.day > 1 || data.varies) {
2497 days = data.dayList();
2498 if (lastMonth || data.day > 1) {
2499 for (id = days->begin(); id != days->end(); ++id) {
2500 if (*id >= data.day) {
2501 if (lastMonth && *id > endDay)
2502 return countGone;
2503 if (++countGone >= countMax)
2504 return countMax;
2505 }
2506 }
2507 } else {
2508 countGone += days->count();
2509 if (countGone >= countMax)
2510 return countMax;
2511 }
2512 data.day = 1;
2513 } else {
2514 // The number of days per month is constant, so skip
2515 // the whole month.
2516 countGone += data.daysPerMonth;
2517 if (countGone >= countMax)
2518 return countMax;
2519 }
2520 }
2521 }
2522 data.month = 1;
2523 data.year += rFreq;
2524 }
2525
2526 if (data.varies) {
2527 // The number of recurrences varies from year to year.
2528 for ( ; ; ) {
2529 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2530 data.month = *im.current();
2531 days = data.dayList();
2532 if (data.yearMonth() >= endYearMonth) {
2533 if (data.yearMonth() > endYearMonth)
2534 return countGone;
2535 // Check the last month in the recurrence
2536 for (id = days->begin(); id != days->end(); ++id) {
2537 if (*id > endDay)
2538 return countGone;
2539 if (++countGone >= countMax)
2540 return countMax;
2541 }
2542 } else {
2543 countGone += days->count();
2544 if (countGone >= countMax)
2545 return countMax;
2546 }
2547 }
2548 data.year += rFreq;
2549 }
2550 } else {
2551 // The number of recurrences is the same every year,
2552 // so skip the year-by-year check.
2553 // Skip the remaining whole years, but leave at least
2554 // 1 recurrence remaining, in order to get its date.
2555 int wholeYears = endYear - data.year;
2556 countGone += (wholeYears / rFreq) * data.count;
2557 if (countGone >= countMax)
2558 return countMax;
2559 if (wholeYears % rFreq)
2560 return countGone; // end year isn't a recurrence year
2561 data.year = endYear;
2562
2563 // Check the last year in the recurrence.
2564 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2565 data.month = *im.current();
2566 if (data.month >= endMonth) {
2567 if (data.month > endMonth)
2568 return countGone;
2569 // Check the last month in the recurrence
2570 days = data.dayList();
2571 for (id = days->begin(); id != days->end(); ++id) {
2572 if (*id > endDay)
2573 return countGone;
2574 if (++countGone >= countMax)
2575 return countMax;
2576 }
2577 } else {
2578 countGone += data.daysPerMonth;
2579 if (countGone >= countMax)
2580 return countMax;
2581 }
2582 }
2583 }
2584 return countGone;
2585}
2586
2587int Recurrence::yearlyPosCalcNextAfter(QDate &enddate, YearlyPosData &data) const
2588{
2589 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
2590 int countGone = 0;
2591 int endYear = enddate.year();
2592 int endMonth = enddate.month();
2593 int endDay = enddate.day();
2594 if (endDay < data.day && --endMonth == 0) {
2595 endMonth = 12;
2596 --endYear;
2597 }
2598 int endYearMonth = endYear*12 + endMonth;
2599 QValueList<int>::ConstIterator id;
2600 const QValueList<int>* days;
2601
2602 if (data.varies) {
2603 // The number of recurrences varies from year to year.
2604 for ( ; ; ) {
2605 // Check the next year
2606 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2607 if (*im.current() >= data.month) {
2608 // Check the next month
2609 data.month = *im.current();
2610 int ended = data.yearMonth() - endYearMonth;
2611 days = data.dayList();
2612 if (ended >= 0 || data.day > 1) {
2613 // This is the start or end month, so check each day
2614 for (id = days->begin(); id != days->end(); ++id) {
2615 if (*id >= data.day) {
2616 ++countGone;
2617 if (ended > 0 || (ended == 0 && *id > endDay)) {
2618 data.day = *id;
2619 goto ex;
2620 }
2621 if (--countTogo == 0)
2622 return 0;
2623 }
2624 }
2625 } else {
2626 // Skip the whole month
2627 uint n = days->count();
2628 if (n >= countTogo)
2629 return 0;
2630 countGone += n;
2631 }
2632 data.day = 1; // we've checked the start month now
2633 }
2634 }
2635 data.month = 1; // we've checked the start year now
2636 data.year += rFreq;
2637 }
2638 } else {
2639 // The number of recurrences is the same every year.
2640 if (data.month > 1 || data.day > 1) {
2641 // Check what remains of the start year
2642 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2643 if (*im.current() >= data.month) {
2644 // Check what remains of the start month
2645 data.month = *im.current();
2646 int ended = data.yearMonth() - endYearMonth;
2647 if (ended >= 0 || data.day > 1) {
2648 // This is the start or end month, so check each day
2649 days = data.dayList();
2650 for (id = days->begin(); id != days->end(); ++id) {
2651 if (*id >= data.day) {
2652 ++countGone;
2653 if (ended > 0 || (ended == 0 && *id > endDay)) {
2654 data.day = *id;
2655 goto ex;
2656 }
2657 if (--countTogo == 0)
2658 return 0;
2659 }
2660 }
2661 data.day = 1; // we've checked the start month now
2662 } else {
2663 // Skip the whole month.
2664 if (static_cast<uint>(data.daysPerMonth) >= countTogo)
2665 return 0;
2666 countGone += data.daysPerMonth;
2667 }
2668 }
2669 }
2670 data.year += rFreq;
2671 }
2672 // Skip the remaining whole years to at least endYear.
2673 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
2674 if ((endYear - data.year)%rFreq == 0
2675 && *rYearNums.getLast() <= endMonth)
2676 ++recurYears; // required year is after endYear
2677 if (recurYears) {
2678 int n = recurYears * data.count;
2679 if (static_cast<uint>(n) > countTogo)
2680 return 0; // reached end of recurrence
2681 countTogo -= n;
2682 countGone += n;
2683 data.year += recurYears * rFreq;
2684 }
2685
2686 // Check the last year in the recurrence
2687 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2688 data.month = *im.current();
2689 int ended = data.yearMonth() - endYearMonth;
2690 if (ended >= 0) {
2691 // This is the end month, so check each day
2692 days = data.dayList();
2693 for (id = days->begin(); id != days->end(); ++id) {
2694 ++countGone;
2695 if (ended > 0 || (ended == 0 && *id > endDay)) {
2696 data.day = *id;
2697 goto ex;
2698 }
2699 if (--countTogo == 0)
2700 return 0;
2701 }
2702 } else {
2703 // Skip the whole month.
2704 if (static_cast<uint>(data.daysPerMonth) >= countTogo)
2705 return 0;
2706 countGone += data.daysPerMonth;
2707 }
2708 }
2709 }
2710ex:
2711 enddate = data.date();
2712 return countGone;
2713}
2714
2715
2716/* Find count and, depending on 'func', the end date of an annual recurrence by day.
2717 * Reply = total number of occurrences up to 'enddate', or 0 if error.
2718 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
2719 * recurrence end date.
2720 */
2721struct Recurrence::YearlyDayData {
2722 int year; // current year
2723 int day; // current day of year 1..366
2724 bool varies; // true if day 366 recurs
2725 private:
2726 int daycount;
2727 public:
2728 YearlyDayData(const Recurrence* r, const QDate &date)
2729 : year(date.year()), day(date.dayOfYear()), varies(*r->rYearNums.getLast() == 366),
2730 daycount(r->rYearNums.count()) { }
2731 bool leapYear() const { return QDate::leapYear(year); }
2732 int dayCount() const { return daycount - (varies && !QDate::leapYear(year) ? 1 : 0); }
2733 bool isMaxDayCount() const { return !varies || QDate::leapYear(year); }
2734 QDate date() const { return QDate(year, 1, 1).addDays(day - 1); }
2735};
2736
2737int Recurrence::yearlyDayCalc(PeriodFunc func, QDate &enddate) const
2738{
2739 if (rYearNums.isEmpty())
2740 return 0;
2741 YearlyDayData data(this, mRecurStart.date());
2742 switch (func) {
2743 case END_DATE_AND_COUNT:
2744 return yearlyDayCalcEndDate(enddate, data);
2745 case COUNT_TO_DATE:
2746 return yearlyDayCalcToDate(enddate, data);
2747 case NEXT_AFTER_DATE:
2748 return yearlyDayCalcNextAfter(enddate, data);
2749 }
2750 return 0;
2751}
2752
2753int Recurrence::yearlyDayCalcEndDate(QDate &enddate, YearlyDayData &data) const
2754{
2755 uint countTogo = rDuration + mRecurExDatesCount;
2756 int countGone = 0;
2757
2758 if (data.day > 1) {
2759 // Check what remains of the start year
2760 bool leapOK = data.isMaxDayCount();
2761 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2762 int d = *it.current();
2763 if (d >= data.day && (leapOK || d < 366)) {
2764 ++countGone;
2765 if (--countTogo == 0) {
2766 data.day = d;
2767 goto ex;
2768 }
2769 }
2770 }
2771 data.day = 1;
2772 data.year += rFreq;
2773 }
2774
2775 if (data.varies) {
2776 // The number of recurrences is different in leap years,
2777 // so check year-by-year.
2778 for ( ; ; ) {
2779 uint n = data.dayCount();
2780 if (n >= countTogo)
2781 break;
2782 countTogo -= n;
2783 countGone += n;
2784 data.year += rFreq;
2785 }
2786 } else {
2787 // The number of recurrences is the same every year,
2788 // so skip the year-by-year check.
2789 // Skip the remaining whole years, but leave at least
2790 // 1 recurrence remaining, in order to get its date.
2791 int daysPerYear = rYearNums.count();
2792 int wholeYears = (countTogo - 1) / daysPerYear;
2793 data.year += wholeYears * rFreq;
2794 countGone += wholeYears * daysPerYear;
2795 countTogo -= wholeYears * daysPerYear;
2796 }
2797 if (countTogo) {
2798 // Check the last year in the recurrence
2799 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2800 ++countGone;
2801 if (--countTogo == 0) {
2802 data.day = *it.current();
2803 break;
2804 }
2805 }
2806 }
2807ex:
2808 enddate = data.date();
2809 return countGone;
2810}
2811
2812int Recurrence::yearlyDayCalcToDate(const QDate &enddate, YearlyDayData &data) const
2813{
2814 int countGone = 0;
2815 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
2816 int endYear = enddate.year();
2817 int endDay = enddate.dayOfYear();
2818
2819 if (data.day > 1) {
2820 // Check what remains of the start year
2821 bool leapOK = data.isMaxDayCount();
2822 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2823 int d = *it.current();
2824 if (d >= data.day && (leapOK || d < 366)) {
2825 if (data.year == endYear && d > endDay)
2826 return countGone;
2827 if (++countGone >= countMax)
2828 return countMax;
2829 }
2830 }
2831 data.day = 1;
2832 data.year += rFreq;
2833 }
2834
2835 if (data.varies) {
2836 // The number of recurrences is different in leap years,
2837 // so check year-by-year.
2838 while (data.year < endYear) {
2839 uint n = data.dayCount();
2840 countGone += n;
2841 if (countGone >= countMax)
2842 return countMax;
2843 data.year += rFreq;
2844 }
2845 if (data.year > endYear)
2846 return countGone;
2847 } else {
2848 // The number of recurrences is the same every year.
2849 // Skip the remaining whole years.
2850 int wholeYears = endYear - data.year;
2851 countGone += (wholeYears / rFreq) * rYearNums.count();
2852 if (countGone >= countMax)
2853 return countMax;
2854 if (wholeYears % rFreq)
2855 return countGone; // end year isn't a recurrence year
2856 data.year = endYear;
2857 }
2858
2859 if (data.year <= endYear) {
2860 // Check the last year in the recurrence
2861 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2862 if (*it.current() > endDay)
2863 return countGone;
2864 if (++countGone >= countMax)
2865 return countMax;
2866 }
2867 }
2868 return countGone;
2869}
2870
2871int Recurrence::yearlyDayCalcNextAfter(QDate &enddate, YearlyDayData &data) const
2872{
2873 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
2874 int countGone = 0;
2875 int endYear = enddate.year();
2876 int endDay = enddate.dayOfYear();
2877
2878 if (data.day > 1) {
2879 // Check what remains of the start year
2880 bool leapOK = data.isMaxDayCount();
2881 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2882 int d = *it.current();
2883 if (d >= data.day && (leapOK || d < 366)) {
2884 ++countGone;
2885 if (data.year == endYear && d > endDay) {
2886 data.day = d;
2887 goto ex;
2888 }
2889 if (--countTogo == 0)
2890 return 0;
2891 }
2892 }
2893 data.day = 1;
2894 data.year += rFreq;
2895 }
2896
2897 if (data.varies) {
2898 // The number of recurrences is different in leap years,
2899 // so check year-by-year.
2900 while (data.year <= endYear) {
2901 uint n = data.dayCount();
2902 if (data.year == endYear && *rYearNums.getLast() > endDay)
2903 break;
2904 if (n >= countTogo)
2905 break;
2906 countTogo -= n;
2907 countGone += n;
2908 data.year += rFreq;
2909 }
2910 } else {
2911 // The number of recurrences is the same every year,
2912 // so skip the year-by-year check.
2913 // Skip the remaining whole years to at least endYear.
2914 int daysPerYear = rYearNums.count();
2915 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
2916 if ((endYear - data.year)%rFreq == 0
2917 && *rYearNums.getLast() <= endDay)
2918 ++recurYears; // required year is after endYear
2919 if (recurYears) {
2920 int n = recurYears * daysPerYear;
2921 if (static_cast<uint>(n) > countTogo)
2922 return 0; // reached end of recurrence
2923 countTogo -= n;
2924 countGone += n;
2925 data.year += recurYears * rFreq;
2926 }
2927 }
2928
2929 // Check the last year in the recurrence
2930 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2931 ++countGone;
2932 int d = *it.current();
2933 if (data.year > endYear || d > endDay) {
2934 data.day = d;
2935 break;
2936 }
2937 if (--countTogo == 0)
2938 return 0;
2939 }
2940ex:
2941 enddate = data.date();
2942 return countGone;
2943}
2944
2945// Get the days in this month which recur, in numerical order.
2946// Parameters: daysInMonth = number of days in this month
2947// startDayOfWeek = day of week for first day of month.
2948void Recurrence::getMonthlyPosDays(QValueList<int> &list, int daysInMonth, int startDayOfWeek) const
2949{
2950 list.clear();
2951 int endDayOfWeek = (startDayOfWeek + daysInMonth - 2) % 7 + 1;
2952 // Go through the list, compiling a bit list of actual day numbers
2953 Q_UINT32 days = 0;
2954 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) {
2955 int weeknum = pos.current()->rPos - 1; // get 0-based week number
2956 QBitArray &rdays = pos.current()->rDays;
2957 if (pos.current()->negative) {
2958 // nth days before the end of the month
2959 for (uint i = 1; i <= 7; ++i) {
2960 if (rdays.testBit(i - 1)) {
2961 int day = daysInMonth - weeknum*7 - (endDayOfWeek - i + 7) % 7;
2962 if (day > 0)
2963 days |= 1 << (day - 1);
2964 }
2965 }
2966 } else {
2967 // nth days after the start of the month
2968 for (uint i = 1; i <= 7; ++i) {
2969 if (rdays.testBit(i - 1)) {
2970 int day = 1 + weeknum*7 + (i - startDayOfWeek + 7) % 7;
2971 if (day <= daysInMonth)
2972 days |= 1 << (day - 1);
2973 }
2974 }
2975 }
2976 }
2977 // Compile the ordered list
2978 Q_UINT32 mask = 1;
2979 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) {
2980 if (days & mask)
2981 list.append(i + 1);
2982 }
2983}
2984
2985// Get the number of days in the month which recur.
2986// Reply = -1 if the number varies from month to month.
2987int Recurrence::countMonthlyPosDays() const
2988{
2989 int count = 0;
2990 Q_UINT8 positive[5] = { 0, 0, 0, 0, 0 };
2991 Q_UINT8 negative[4] = { 0, 0, 0, 0 };
2992 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) {
2993 int weeknum = pos.current()->rPos;
2994 Q_UINT8* wk;
2995 if (pos.current()->negative) {
2996 // nth days before the end of the month
2997 if (weeknum > 4)
2998 return -1; // days in 5th week are often missing
2999 wk = &negative[4 - weeknum];
3000 } else {
3001 // nth days after the start of the month
3002 if (weeknum > 4)
3003 return -1; // days in 5th week are often missing
3004 wk = &positive[weeknum - 1];
3005 }
3006 QBitArray &rdays = pos.current()->rDays;
3007 for (uint i = 0; i < 7; ++i) {
3008 if (rdays.testBit(i)) {
3009 ++count;
3010 *wk |= (1 << i);
3011 }
3012 }
3013 }
3014 // Check for any possible days which could be duplicated by
3015 // a positive and a negative position.
3016 for (int i = 0; i < 4; ++i) {
3017 if (negative[i] & (positive[i] | positive[i+1]))
3018 return -1;
3019 }
3020 return count;
3021}
3022
3023// Get the days in this month which recur, in numerical order.
3024// Reply = true if day numbers varies from month to month.
3025bool Recurrence::getMonthlyDayDays(QValueList<int> &list, int daysInMonth) const
3026{
3027 list.clear();
3028 bool variable = false;
3029 Q_UINT32 days = 0;
3030 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) {
3031 int day = *it.current();
3032 if (day > 0) {
3033 // date in the month
3034 if (day <= daysInMonth)
3035 days |= 1 << (day - 1);
3036 if (day > 28 && day <= 31)
3037 variable = true; // this date does not appear in some months
3038 } else if (day < 0) {
3039 // days before the end of the month
3040 variable = true; // this date varies depending on the month length
3041 day = daysInMonth + day; // zero-based day of month
3042 if (day >= 0)
3043 days |= 1 << day;
3044 }
3045 }
3046 // Compile the ordered list
3047 Q_UINT32 mask = 1;
3048 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) {
3049 if (days & mask)
3050 list.append(i + 1);
3051 }
3052 return variable;
3053}
3054
3055// Get the months which recur, in numerical order, for both leap years and non-leap years.
3056// N.B. If February 29th recurs on March 1st in non-leap years, February (not March) is
3057// included in the non-leap year month list.
3058// Reply = true if February 29th also recurs.
3059bool Recurrence::getYearlyMonthMonths(int day, QValueList<int> &list, QValueList<int> &leaplist) const
3060{
3061 list.clear();
3062 leaplist.clear();
3063 bool feb29 = false;
3064 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
3065 int month = *it.current();
3066 if (month == 2) {
3067 if (day <= 28) {
3068 list.append(month); // date appears in February
3069 leaplist.append(month);
3070 }
3071 else if (day == 29) {
3072 // February 29th
3073 leaplist.append(month);
3074 switch (mFeb29YearlyType) {
3075 case rFeb28:
3076 case rMar1:
3077 list.append(2);
3078 break;
3079 case rFeb29:
3080 break;
3081 }
3082 feb29 = true;
3083 }
3084 }
3085 else if (day <= 30 || QDate(2000, month, 1).daysInMonth() == 31) {
3086 list.append(month); // date appears in every month
3087 leaplist.append(month);
3088 }
3089 }
3090 return feb29;
3091}
3092
3093/* From the recurrence day of the week list, get the earliest day in the
3094 * specified week which is >= the startDay.
3095 * Parameters: startDay = 1..7 (Monday..Sunday)
3096 * useWeekStart = true to end search at day before next rWeekStart
3097 * = false to search for a full 7 days
3098 * Reply = day of the week (1..7), or 0 if none found.
3099 */
3100int Recurrence::getFirstDayInWeek(int startDay, bool useWeekStart) const
3101{
3102 int last = ((useWeekStart ? rWeekStart : startDay) + 5)%7;
3103 for (int i = startDay - 1; ; i = (i + 1)%7) {
3104 if (rDays.testBit(i))
3105 return i + 1;
3106 if (i == last)
3107 return 0;
3108 }
3109}
3110
3111/* From the recurrence day of the week list, get the latest day in the
3112 * specified week which is <= the endDay.
3113 * Parameters: endDay = 1..7 (Monday..Sunday)
3114 * useWeekStart = true to end search at rWeekStart
3115 * = false to search for a full 7 days
3116 * Reply = day of the week (1..7), or 0 if none found.
3117 */
3118int Recurrence::getLastDayInWeek(int endDay, bool useWeekStart) const
3119{
3120 int last = useWeekStart ? rWeekStart - 1 : endDay%7;
3121 for (int i = endDay - 1; ; i = (i + 6)%7) {
3122 if (rDays.testBit(i))
3123 return i + 1;
3124 if (i == last)
3125 return 0;
3126 }
3127}
3128
3129/* From the recurrence monthly day number list or monthly day of week/week of
3130 * month list, get the earliest day in the specified month which is >= the
3131 * earliestDate.
3132 */
3133QDate Recurrence::getFirstDateInMonth(const QDate &earliestDate) const
3134{
3135 int earliestDay = earliestDate.day();
3136 int daysInMonth = earliestDate.daysInMonth();
3137 switch (recurs) {
3138 case rMonthlyDay: {
3139 int minday = daysInMonth + 1;
3140 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) {
3141 int day = *it.current();
3142 if (day < 0)
3143 day = daysInMonth + day + 1;
3144 if (day >= earliestDay && day < minday)
3145 minday = day;
3146 }
3147 if (minday <= daysInMonth)
3148 return earliestDate.addDays(minday - earliestDay);
3149 break;
3150 }
3151 case rMonthlyPos:
3152 case rYearlyPos: {
3153 QDate monthBegin(earliestDate.addDays(1 - earliestDay));
3154 QValueList<int> dayList;
3155 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek());
3156 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) {
3157 if (*id >= earliestDay)
3158 return monthBegin.addDays(*id - 1);
3159 }
3160 break;
3161 }
3162 }
3163 return QDate();
3164}
3165
3166/* From the recurrence monthly day number list or monthly day of week/week of
3167 * month list, get the latest day in the specified month which is <= the
3168 * latestDate.
3169 */
3170QDate Recurrence::getLastDateInMonth(const QDate &latestDate) const
3171{
3172 int latestDay = latestDate.day();
3173 int daysInMonth = latestDate.daysInMonth();
3174 switch (recurs) {
3175 case rMonthlyDay: {
3176 int maxday = -1;
3177 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) {
3178 int day = *it.current();
3179 if (day < 0)
3180 day = daysInMonth + day + 1;
3181 if (day <= latestDay && day > maxday)
3182 maxday = day;
3183 }
3184 if (maxday > 0)
3185 return QDate(latestDate.year(), latestDate.month(), maxday);
3186 break;
3187 }
3188 case rMonthlyPos:
3189 case rYearlyPos: {
3190 QDate monthBegin(latestDate.addDays(1 - latestDay));
3191 QValueList<int> dayList;
3192 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek());
3193 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) {
3194 if (*id <= latestDay)
3195 return monthBegin.addDays(*id - 1);
3196 }
3197 break;
3198 }
3199 }
3200 return QDate();
3201}
3202
3203/* From the recurrence yearly month list or yearly day list, get the earliest
3204 * month or day in the specified year which is >= the earliestDate.
3205 * Note that rYearNums is sorted in numerical order.
3206 */
3207QDate Recurrence::getFirstDateInYear(const QDate &earliestDate) const
3208{
3209 QPtrListIterator<int> it(rYearNums);
3210 switch (recurs) {
3211 case rYearlyMonth: {
3212 int day = recurStart().date().day();
3213 int earliestYear = earliestDate.year();
3214 int earliestMonth = earliestDate.month();
3215 int earliestDay = earliestDate.day();
3216 if (earliestDay > day) {
3217 // The earliest date is later in the month than the recurrence date,
3218 // so skip to the next month before starting to check
3219 if (++earliestMonth > 12)
3220 return QDate();
3221 }
3222 for ( ; it.current(); ++it) {
3223 int month = *it.current();
3224 if (month >= earliestMonth) {
3225 if (day <= 28 || QDate::isValid(earliestYear, month, day))
3226 return QDate(earliestYear, month, day);
3227 if (day == 29 && month == 2) {
3228 // It's a recurrence on February 29th, in a non-leap year
3229 switch (mFeb29YearlyType) {
3230 case rMar1:
3231 return QDate(earliestYear, 3, 1);
3232 case rFeb28:
3233 if (earliestDay <= 28)
3234 return QDate(earliestYear, 2, 28);
3235 break;
3236 case rFeb29:
3237 break;
3238 }
3239 }
3240 }
3241 }
3242 break;
3243 }
3244 case rYearlyPos: {
3245 QValueList<int> dayList;
3246 int earliestYear = earliestDate.year();
3247 int earliestMonth = earliestDate.month();
3248 int earliestDay = earliestDate.day();
3249 for ( ; it.current(); ++it) {
3250 int month = *it.current();
3251 if (month >= earliestMonth) {
3252 QDate monthBegin(earliestYear, month, 1);
3253 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek());
3254 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) {
3255 if (*id >= earliestDay)
3256 return monthBegin.addDays(*id - 1);
3257 }
3258 earliestDay = 1;
3259 }
3260 }
3261 break;
3262 }
3263 case rYearlyDay: {
3264 int earliestDay = earliestDate.dayOfYear();
3265 for ( ; it.current(); ++it) {
3266 int day = *it.current();
3267 if (day >= earliestDay && (day <= 365 || day <= earliestDate.daysInYear()))
3268 return earliestDate.addDays(day - earliestDay);
3269 }
3270 break;
3271 }
3272 }
3273 return QDate();
3274}
3275
3276/* From the recurrence yearly month list or yearly day list, get the latest
3277 * month or day in the specified year which is <= the latestDate.
3278 * Note that rYearNums is sorted in numerical order.
3279 */
3280QDate Recurrence::getLastDateInYear(const QDate &latestDate) const
3281{
3282 QPtrListIterator<int> it(rYearNums);
3283 switch (recurs) {
3284 case rYearlyMonth: {
3285 int day = recurStart().date().day();
3286 int latestYear = latestDate.year();
3287 int latestMonth = latestDate.month();
3288 if (latestDate.day() > day) {
3289 // The latest date is earlier in the month than the recurrence date,
3290 // so skip to the previous month before starting to check
3291 if (--latestMonth <= 0)
3292 return QDate();
3293 }
3294 for (it.toLast(); it.current(); --it) {
3295 int month = *it.current();
3296 if (month <= latestMonth) {
3297 if (day <= 28 || QDate::isValid(latestYear, month, day))
3298 return QDate(latestYear, month, day);
3299 if (day == 29 && month == 2) {
3300 // It's a recurrence on February 29th, in a non-leap year
3301 switch (mFeb29YearlyType) {
3302 case rMar1:
3303 if (latestMonth >= 3)
3304 return QDate(latestYear, 3, 1);
3305 break;
3306 case rFeb28:
3307 return QDate(latestYear, 2, 28);
3308 case rFeb29:
3309 break;
3310 }
3311 }
3312 }
3313 }
3314 break;
3315 }
3316 case rYearlyPos: {
3317 QValueList<int> dayList;
3318 int latestYear = latestDate.year();
3319 int latestMonth = latestDate.month();
3320 int latestDay = latestDate.day();
3321 for (it.toLast(); it.current(); --it) {
3322 int month = *it.current();
3323 if (month <= latestMonth) {
3324 QDate monthBegin(latestYear, month, 1);
3325 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek());
3326 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) {
3327 if (*id <= latestDay)
3328 return monthBegin.addDays(*id - 1);
3329 }
3330 latestDay = 31;
3331 }
3332 }
3333 break;
3334 }
3335 case rYearlyDay: {
3336 int latestDay = latestDate.dayOfYear();
3337 for (it.toLast(); it.current(); --it) {
3338 int day = *it.current();
3339 if (day <= latestDay)
3340 return latestDate.addDays(day - latestDay);
3341 }
3342 break;
3343 }
3344 }
3345 return QDate();
3346}
3347
3348void Recurrence::dump() const
3349{
3350 kdDebug() << "Recurrence::dump():" << endl;
3351
3352 kdDebug() << " type: " << recurs << endl;
3353
3354 kdDebug() << " rDays: " << endl;
3355 int i;
3356 for( i = 0; i < 7; ++i ) {
3357 kdDebug() << " " << i << ": "
3358 << ( rDays.testBit( i ) ? "true" : "false" ) << endl;
3359 }
3360}
diff --git a/libkcal/recurrence.h b/libkcal/recurrence.h
new file mode 100644
index 0000000..a0f6d84
--- a/dev/null
+++ b/libkcal/recurrence.h
@@ -0,0 +1,401 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (c) 2002 David Jarvie <software@astrojar.org.uk>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21*/
22#ifndef KCAL_RECURRENCE_H
23#define KCAL_RECURRENCE_H
24
25#include <qstring.h>
26#include <qbitarray.h>
27#include <qptrlist.h>
28
29namespace KCal {
30
31class Incidence;
32
33/**
34 This class represents a recurrence rule for a calendar incidence.
35*/
36class Recurrence
37{
38 public:
39 /** enumeration for describing how an event recurs, if at all. */
40 enum { rNone = 0, rMinutely = 0x001, rHourly = 0x0002, rDaily = 0x0003,
41 rWeekly = 0x0004, rMonthlyPos = 0x0005, rMonthlyDay = 0x0006,
42 rYearlyMonth = 0x0007, rYearlyDay = 0x0008, rYearlyPos = 0x0009 };
43
44 /** Enumeration for specifying what date yearly recurrences of February 29th occur
45 * in non-leap years. */
46 enum Feb29Type {
47 rMar1, // recur on March 1st (default)
48 rFeb28, // recur on February 28th
49 rFeb29 // only recur on February 29th, i.e. don't recur in non-leap years
50 };
51
52 /** structure for Recurs rMonthlyPos */
53 struct rMonthPos {
54 QBitArray rDays;
55 short rPos;
56 bool negative;
57 };
58
59 Recurrence(Incidence *parent, int compatVersion = 0);
60 Recurrence(const Recurrence&, Incidence *parent);
61 ~Recurrence();
62
63 bool operator==( const Recurrence& ) const;
64 bool operator!=( const Recurrence& r ) const { return !operator==(r); }
65
66 Incidence *parent() { return mParent; }
67
68 /** Return the start of the recurrence */
69 QDateTime recurStart() const { return mRecurStart; }
70 /** Returns the number of exception dates for the recurrence */
71 int recurExDatesCount() const { return mRecurExDatesCount; }
72 /** Set start of recurrence, as a date and time. */
73 void setRecurStart(const QDateTime &start);
74 /** Set start of recurrence, as a date with no time.
75 * Recurrence types which are sub-daily (e.g. rHourly) always have a time;
76 * the time is set to 00:00:00 in these cases. */
77 void setRecurStart(const QDate &start);
78 /** Set whether the recurrence has no time, just a date.
79 * Recurrence types which are sub-daily (e.g. rHourly) always have a time
80 * and cannot be set to float.
81 * N.B. This property is derived by default from the parent incidence,
82 * or according to whether a time is specified in setRecurStart(). */
83 void setFloats(bool f);
84 /**
85 Returns whether the recurrence has no time, just a date.
86 */
87 bool doesFloat() const {
88 return mFloats;
89 }
90
91 /** Set if recurrence is read-only or can be changed. */
92 void setRecurReadOnly(bool readOnly) { mRecurReadOnly = readOnly; }
93 bool recurReadOnly() const
94 {
95 return mRecurReadOnly;
96 }
97
98
99 /** Set number of exception dates. */
100 void setRecurExDatesCount(int count) { if (count >= 0) mRecurExDatesCount = count; }
101 /** Set the calendar file version for backwards compatibility.
102 * @var version is the KOrganizer/libkcal version, e.g. 220 for KDE 2.2.0.
103 * Specify version = 0 to cancel compatibility mode.
104 */
105 void setCompatVersion(int version = 0);
106
107 /** Returns the event's recurrence status. See the enumeration at the top
108 * of this file for possible values. */
109 ushort doesRecur() const;
110 /** Returns true if the date specified is one on which the event will
111 * recur. */
112 bool recursOnPure(const QDate &qd) const;
113 /** Returns true if the date/time specified is one at which the event will
114 * recur. Times are rounded down to the nearest minute to determine the result. */
115 bool recursAtPure(const QDateTime &) const;
116 /** Turns off recurrence for the event. */
117 void unsetRecurs();
118
119 /** Returns the date of the next recurrence, after the specified date.
120 * @var preDate the date after which to find the recurrence.
121 * @var last if non-null, *last is set to true if the next recurrence is the
122 * last recurrence, else false.
123 * Reply = date of next recurrence, or invalid date if none.
124 */
125 QDate getNextDate(const QDate& preDate, bool* last = 0) const;
126 /** Returns the date and time of the next recurrence, after the specified date/time.
127 * If the recurrence has no time, the next date after the specified date is returned.
128 * @var preDate the date/time after which to find the recurrence.
129 * @var last if non-null, *last is set to true if the next recurrence is the
130 * last recurrence, else false.
131 * Reply = date/time of next recurrence, or invalid date if none.
132 */
133 QDateTime getNextDateTime(const QDateTime& preDateTime, bool* last = 0) const;
134 /** Returns the date of the last previous recurrence, before the specified date.
135 * @var afterDate the date before which to find the recurrence.
136 * @var last if non-null, *last is set to true if the previous recurrence is the
137 * last recurrence, else false.
138 * Reply = date of previous recurrence, or invalid date if none.
139 */
140 QDate getPreviousDate(const QDate& afterDate, bool* last = 0) const;
141 /** Returns the date and time of the last previous recurrence, before the specified date/time.
142 * If a time later than 00:00:00 is specified and the recurrence has no time, 00:00:00 on
143 * the specified date is returned if that date recurs.
144 * @var afterDate the date/time before which to find the recurrence.
145 * @var last if non-null, *last is set to true if the previous recurrence is the
146 * last recurrence, else false.
147 * Reply = date/time of previous recurrence, or invalid date if none.
148 */
149 QDateTime getPreviousDateTime(const QDateTime& afterDateTime, bool* last = 0) const;
150
151 /** Returns frequency of recurrence, in terms of the recurrence time period type. */
152 int frequency() const;
153 /** Returns the total number of recurrences, including the initial occurrence. */
154 int duration() const;
155 /** Sets the total number of times the event is to occur, including both the
156 * first and last. */
157 void setDuration(int duration);
158 /** Returns the number of recurrences up to and including the date specified. */
159 int durationTo(const QDate &) const;
160 /** Returns the number of recurrences up to and including the date/time specified. */
161 int durationTo(const QDateTime &) const;
162
163 /** Returns the date of the last recurrence.
164 * An invalid date is returned if the recurrence has no end.
165 * Note: for some recurrence types, endDate() can involve significant calculation.
166 */
167 QDate endDate() const;
168 /** Returns the date and time of the last recurrence.
169 * An invalid date is returned if the recurrence has no end.
170 * Note: for some recurrence types, endDateTime() can involve significant calculation.
171 */
172 QDateTime endDateTime() const;
173 /** Returns a string representing the recurrence end date in the format
174 according to the user's locale settings. */
175 QString endDateStr(bool shortfmt=true) const;
176
177 /** Sets an event to recur minutely.
178 * @var _rFreq the frequency to recur, e.g. 2 is every other minute
179 * @var duration the number of times the event is to occur, or -1 to recur indefinitely.
180 */
181 void setMinutely(int _rFreq, int duration);
182 /** Sets an event to recur minutely.
183 * @var _rFreq the frequency to recur, e.g. 2 is every other minute
184 * @var endDateTime the ending date/time after which to stop recurring
185 */
186 void setMinutely(int _rFreq, const QDateTime &endDateTime);
187
188 /** Sets an event to recur hourly.
189 * @var _rFreq the frequency to recur, e.g. 2 is every other hour
190 * @var duration the number of times the event is to occur, or -1 to recur indefinitely.
191 */
192 void setHourly(int _rFreq, int duration);
193 /** Sets an event to recur hourly.
194 * @var _rFreq the frequency to recur, e.g. 2 is every other hour
195 * @var endDateTime the ending date/time after which to stop recurring
196 */
197 void setHourly(int _rFreq, const QDateTime &endDateTime);
198
199 /** Sets an event to recur daily.
200 * @var _rFreq the frequency to recur, e.g. 2 is every other day
201 * @var duration the number of times the event is to occur, or -1 to recur indefinitely.
202 */
203 void setDaily(int _rFreq, int duration);
204 /** Sets an event to recur daily.
205 * @var _rFreq the frequency to recur, e.g. 2 is every other day
206 * @var endDate the ending date after which to stop recurring
207 */
208 void setDaily(int _rFreq, const QDate &endDate);
209
210 /** Sets an event to recur weekly.
211 * @var _rFreq the frequency to recur, e.g. every other week etc.
212 * @var _rDays a 7 bit array indicating which days on which to recur (bit 0 = Monday).
213 * @var duration the number of times the event is to occur, or -1 to recur indefinitely.
214 * @var weekStart the first day of the week (Monday=1 .. Sunday=7, default is Monday).
215 */
216 void setWeekly(int _rFreq, const QBitArray &_rDays, int duration, int weekStart = 1);
217 /** Sets an event to recur weekly.
218 * @var _rFreq the frequency to recur, e.g. every other week etc.
219 * @var _rDays a 7 bit array indicating which days on which to recur (bit 0 = Monday).
220 * @var endDate the date on which to stop recurring.
221 * @var weekStart the first day of the week (Monday=1 .. Sunday=7, default is Monday).
222 */
223 void setWeekly(int _rFreq, const QBitArray &_rDays, const QDate &endDate, int weekStart = 1);
224 /** Returns the first day of the week. Monday=1 .. Sunday=7. */
225 int weekStart() const { return rWeekStart; }
226 /** Returns week day mask (bit 0 = Monday). */
227 const QBitArray &days() const;
228
229 /** Sets an event to recur monthly.
230 * @var type rMonthlyPos or rMonthlyDay
231 * @var _rFreq the frequency to recur, e.g. 3 for every third month.
232 * @var duration the number of times the event is to occur, or -1 to recur indefinitely.
233 */
234 void setMonthly(short type, int _rFreq, int duration);
235 /** same as above, but with ending date not number of recurrences */
236 void setMonthly(short type, int _rFreq, const QDate &endDate);
237 /** Adds a position to the recursMonthlyPos recurrence rule, if it is
238 * set.
239 * @var _rPos the position in the month for the recurrence, with valid
240 * values being 1-5 (5 weeks max in a month).
241 * @var _rDays the days for the position to recur on (bit 0 = Monday).
242 * Example: _rPos = 2, and bits 0 and 2 are set in _rDays:
243 * the rule is to repeat every 2nd Monday and Wednesday in the month.
244 */
245 void addMonthlyPos(short _rPos, const QBitArray &_rDays);
246 /** Adds a position the the recursMonthlyDay list.
247 * @var _rDay the date in the month to recur.
248 */
249 void addMonthlyDay(short _rDay);
250 /** Returns list of day positions in months. */
251 const QPtrList<rMonthPos> &monthPositions() const;
252 /** Returns list of day numbers of a month. */
253 const QPtrList<int> &monthDays() const;
254
255 /** Sets an event to recur yearly.
256 * @var type rYearlyMonth, rYearlyPos or rYearlyDay
257 * @var freq the frequency to recur, e.g. 3 for every third year.
258 * @var duration the number of times the event is to occur, or -1 to recur indefinitely.
259 */
260 void setYearly(int type, int freq, int duration);
261 /** Sets an event to recur yearly ending at \a endDate. */
262 void setYearly(int type, int freq, const QDate &endDate);
263 /** Sets an event to recur yearly on specified dates.
264 * The dates must be specified by calling addYearlyNum().
265 * @var type the way recurrences of February 29th are to be handled in non-leap years.
266 * @var freq the frequency to recur, e.g. 3 for every third year.
267 * @var duration the number of times the event is to occur, or -1 to recur indefinitely.
268 */
269 void setYearlyByDate(Feb29Type type, int freq, int duration);
270 /** Sets an event to recur yearly ending at \a endDate. */
271 void setYearlyByDate(Feb29Type type, int freq, const QDate &endDate);
272 /** Adds position of day or month in year.
273 * N.B. for recursYearlyPos, addYearlyMonthPos() must also be called
274 * to add positions within the month. */
275 void addYearlyNum(short _rNum);
276 /** Adds a position to the recursYearlyPos recurrence rule, if it is set.
277 * N.B. addYearlyNum() must also be called to add recurrence months.
278 * Parameters are the same as for addMonthlyPos().
279 */
280 void addYearlyMonthPos(short _rPos, const QBitArray &_rDays);
281 /** Returns positions of days or months in year. */
282 const QPtrList<int> &yearNums() const;
283 /** Returns list of day positions in months, for a recursYearlyPos recurrence rule. */
284 const QPtrList<rMonthPos> &yearMonthPositions() const;
285 /** Returns how yearly recurrences of February 29th are handled. */
286 Feb29Type feb29YearlyType() const { return mFeb29YearlyType; }
287 /** Sets the default method for handling yearly recurrences of February 29th. */
288 static void setFeb29YearlyTypeDefault(Feb29Type t) { mFeb29YearlyDefaultType = t; }
289 /** Returns the default method for handling yearly recurrences of February 29th. */
290 static Feb29Type setFeb29YearlyTypeDefault() { return mFeb29YearlyDefaultType; }
291
292 /**
293 Debug output.
294 */
295 void dump() const;
296 QString recurrenceText() const;
297
298 protected:
299 enum PeriodFunc { END_DATE_AND_COUNT, COUNT_TO_DATE, NEXT_AFTER_DATE };
300 struct MonthlyData; friend struct MonthlyData;
301 struct YearlyMonthData; friend struct YearlyMonthData;
302 struct YearlyPosData; friend struct YearlyPosData;
303 struct YearlyDayData; friend struct YearlyDayData;
304
305 bool recursSecondly(const QDate &, int secondFreq) const;
306 bool recursMinutelyAt(const QDateTime &dt, int minuteFreq) const;
307 bool recursDaily(const QDate &) const;
308 bool recursWeekly(const QDate &) const;
309 bool recursMonthly(const QDate &) const;
310 bool recursYearlyByMonth(const QDate &) const;
311 bool recursYearlyByPos(const QDate &) const;
312 bool recursYearlyByDay(const QDate &) const;
313
314 QDate getNextDateNoTime(const QDate& preDate, bool* last) const;
315 QDate getPreviousDateNoTime(const QDate& afterDate, bool* last) const;
316
317 void addMonthlyPos_(short _rPos, const QBitArray &_rDays);
318 void setDailySub(short type, int freq, int duration);
319 void setYearly_(short type, Feb29Type, int freq, int duration);
320 int recurCalc(PeriodFunc, QDate &enddate) const;
321 int recurCalc(PeriodFunc, QDateTime &endtime) const;
322 int secondlyCalc(PeriodFunc, QDateTime& endtime, int freq) const;
323 int dailyCalc(PeriodFunc, QDate &enddate) const;
324 int weeklyCalc(PeriodFunc, QDate &enddate) const;
325 int weeklyCalcEndDate(QDate& enddate, int daysPerWeek) const;
326 int weeklyCalcToDate(const QDate& enddate, int daysPerWeek) const;
327 int weeklyCalcNextAfter(QDate& enddate, int daysPerWeek) const;
328 int monthlyCalc(PeriodFunc, QDate &enddate) const;
329 int monthlyCalcEndDate(QDate& enddate, MonthlyData&) const;
330 int monthlyCalcToDate(const QDate& enddate, MonthlyData&) const;
331 int monthlyCalcNextAfter(QDate& enddate, MonthlyData&) const;
332 int yearlyMonthCalc(PeriodFunc, QDate &enddate) const;
333 int yearlyMonthCalcEndDate(QDate& enddate, YearlyMonthData&) const;
334 int yearlyMonthCalcToDate(const QDate& enddate, YearlyMonthData&) const;
335 int yearlyMonthCalcNextAfter(QDate& enddate, YearlyMonthData&) const;
336 int yearlyPosCalc(PeriodFunc, QDate &enddate) const;
337 int yearlyPosCalcEndDate(QDate& enddate, YearlyPosData&) const;
338 int yearlyPosCalcToDate(const QDate& enddate, YearlyPosData&) const;
339 int yearlyPosCalcNextAfter(QDate& enddate, YearlyPosData&) const;
340 int yearlyDayCalc(PeriodFunc, QDate &enddate) const;
341 int yearlyDayCalcEndDate(QDate& enddate, YearlyDayData&) const;
342 int yearlyDayCalcToDate(const QDate& enddate, YearlyDayData&) const;
343 int yearlyDayCalcNextAfter(QDate& enddate, YearlyDayData&) const;
344
345 int countMonthlyPosDays() const;
346 void getMonthlyPosDays(QValueList<int>&, int daysInMonth,
347 int startDayOfWeek) const;
348 bool getMonthlyDayDays(QValueList<int>&, int daysInMonth) const;
349 bool getYearlyMonthMonths(int day, QValueList<int>&,
350 QValueList<int> &leaplist) const;
351
352 int getFirstDayInWeek(int startDay, bool useWeekStart = true) const;
353 int getLastDayInWeek(int endDay, bool useWeekStart = true) const;
354 QDate getFirstDateInMonth(const QDate& earliestDate) const;
355 QDate getLastDateInMonth(const QDate& latestDate) const;
356 QDate getFirstDateInYear(const QDate& earliestDate) const;
357 QDate getLastDateInYear(const QDate& latestDate) const;
358
359 private:
360 // Prohibit copying
361 Recurrence(const Recurrence&);
362 Recurrence &operator=(const Recurrence&);
363
364 short recurs; // should be one of the enums.
365
366 int rWeekStart; // day which starts the week, Monday=1 .. Sunday=7
367 QBitArray rDays; // array of days during week it recurs
368
369 QPtrList<rMonthPos> rMonthPositions; // list of positions during a month
370 // on which an event recurs
371
372 QPtrList<int> rMonthDays; // list of days during a month on
373 // which the event recurs
374
375 QPtrList<int> rYearNums; // either months/days to recur on for rYearly,
376 // sorted in numerical order
377
378 int rFreq; // frequency of period
379
380 // one of the following must be specified
381 int rDuration; // num times to recur (inc. first occurrence), -1 = infinite
382 QDateTime rEndDateTime; // date/time at which to end recurrence
383
384 QDateTime mRecurStart; // date/time of first recurrence
385 bool mFloats; // the recurrence has no time, just a date
386 bool mRecurReadOnly;
387 int mRecurExDatesCount; // number of recurrences (in addition to rDuration) which are excluded
388 Feb29Type mFeb29YearlyType; // how to handle yearly recurrences of February 29th
389 static Feb29Type mFeb29YearlyDefaultType; // default value for mFeb29YearlyType
390
391 // Backwards compatibility for KDE < 3.1.
392 int mCompatVersion; // calendar file version for backwards compatibility
393 short mCompatRecurs; // original 'recurs' in old calendar format, or rNone
394 int mCompatDuration; // original 'rDuration' in old calendar format, or 0
395
396 Incidence *mParent;
397};
398
399}
400
401#endif
diff --git a/libkcal/resourcecalendar.h b/libkcal/resourcecalendar.h
new file mode 100644
index 0000000..26b3831
--- a/dev/null
+++ b/libkcal/resourcecalendar.h
@@ -0,0 +1,16 @@
1#ifndef MICRO_KCAL_RESOURCECALENDAR_H
2#define MICRO_KCAL_RESOURCECALENDAR_H
3
4namespace KCal {
5
6class ResourceCalendar
7{
8};
9
10class CalendarResourceManager
11{
12};
13
14}
15
16#endif
diff --git a/libkcal/scheduler.cpp b/libkcal/scheduler.cpp
new file mode 100644
index 0000000..253d8b7
--- a/dev/null
+++ b/libkcal/scheduler.cpp
@@ -0,0 +1,355 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <qdir.h>
22#include <qfile.h>
23#include <qtextstream.h>
24
25#include <klocale.h>
26#include <kdebug.h>
27#include <kstandarddirs.h>
28
29#include "event.h"
30#include "todo.h"
31#include "freebusy.h"
32#include "icalformat.h"
33#include "calendar.h"
34
35#include "scheduler.h"
36
37using namespace KCal;
38
39ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status)
40{
41 mIncidence = incidence;
42 mMethod = method;
43 mStatus = status;
44}
45
46QString ScheduleMessage::statusName(ScheduleMessage::Status status)
47{
48 switch (status) {
49 case PublishNew:
50 return i18n("Publish");
51 case Obsolete:
52 return i18n("Obsolete");
53 case RequestNew:
54 return i18n("New Request");
55 case RequestUpdate:
56 return i18n("Updated Request");
57 default:
58 return i18n("Unknown Status: %1").arg(QString::number(status));
59 }
60}
61
62Scheduler::Scheduler(Calendar *calendar)
63{
64 mCalendar = calendar;
65 mFormat = new ICalFormat();
66}
67
68Scheduler::~Scheduler()
69{
70 delete mFormat;
71}
72
73bool Scheduler::acceptTransaction(IncidenceBase *incidence,Method method,ScheduleMessage::Status status)
74{
75 kdDebug() << "Scheduler::acceptTransaction " << endl;
76 switch (method) {
77 case Publish:
78 return acceptPublish(incidence, status, method);
79 case Request:
80 return acceptRequest(incidence, status);
81 case Add:
82 return acceptAdd(incidence, status);
83 case Cancel:
84 return acceptCancel(incidence, status);
85 case Declinecounter:
86 return acceptDeclineCounter(incidence, status);
87 case Reply:
88 return acceptReply(incidence, status, method);
89 case Refresh:
90 return acceptRefresh(incidence, status);
91 case Counter:
92 return acceptCounter(incidence, status);
93 default:
94 deleteTransaction(incidence);
95 return false;
96 }
97 deleteTransaction(incidence);
98 return false;
99}
100
101QString Scheduler::methodName(Method method)
102{
103 switch (method) {
104 case Publish:
105 return QString::fromLatin1("Publish");
106 case Request:
107 return QString::fromLatin1("Request");
108 case Refresh:
109 return QString::fromLatin1("Refresh");
110 case Cancel:
111 return QString::fromLatin1("Cancel");
112 case Add:
113 return QString::fromLatin1("Add");
114 case Reply:
115 return QString::fromLatin1("Reply");
116 case Counter:
117 return QString::fromLatin1("Counter");
118 case Declinecounter:
119 return QString::fromLatin1("Decline Counter");
120 default:
121 return QString::fromLatin1("Unknown");
122 }
123}
124
125QString Scheduler::translatedMethodName(Method method)
126{
127 switch (method) {
128 case Publish:
129 return i18n("Publish");
130 case Request:
131 return i18n("Request");
132 case Refresh:
133 return i18n("Refresh");
134 case Cancel:
135 return i18n("Cancel");
136 case Add:
137 return i18n("Add");
138 case Reply:
139 return i18n("Reply");
140 case Counter:
141 return i18n("counter proposal","Counter");
142 case Declinecounter:
143 return i18n("decline counter proposal","Decline Counter");
144 default:
145 return i18n("Unknown");
146 }
147}
148
149bool Scheduler::deleteTransaction(IncidenceBase *)
150{
151 return true;
152}
153
154bool Scheduler::acceptPublish(IncidenceBase *incidence,ScheduleMessage::Status status, Method method)
155{
156 if(incidence->type()=="FreeBusy") {
157 return acceptFreeBusy(incidence, method);
158 }
159 switch (status) {
160 case ScheduleMessage::Unknown:
161 case ScheduleMessage::PublishNew:
162 if (!mCalendar->event(incidence->uid())) {
163 Incidence *inc = static_cast<Incidence *>(incidence);
164 mCalendar->addIncidence(inc);
165 deleteTransaction(incidence);
166 }
167 return true;
168 case ScheduleMessage::Obsolete:
169 return true;
170 default:
171 deleteTransaction(incidence);
172 return false;
173 }
174 deleteTransaction(incidence);
175 return false;
176}
177
178bool Scheduler::acceptRequest(IncidenceBase *incidence,ScheduleMessage::Status status)
179{
180 Incidence *inc = static_cast<Incidence *>(incidence);
181 if (inc->type()=="FreeBusy") {
182 // reply to this request is handled in korganizer's incomingdialog
183 return true;
184 } else {
185 Event *even = mCalendar->event(incidence->uid());
186 if (even) {
187 if ( even->revision()<=inc->revision() ) {
188 if ( even->revision()==inc->revision() &&
189 even->lastModified()>inc->lastModified()) {
190 deleteTransaction(incidence);
191 return false;
192 }
193 mCalendar->deleteEvent(even);
194 } else {
195 deleteTransaction(incidence);
196 return false;
197 }
198 } else {
199 Todo *todo = mCalendar->todo(incidence->uid());
200 if (todo) {
201 if ( todo->revision()<=inc->revision() ) {
202 if ( todo->revision()==inc->revision() &&
203 todo->lastModified()>inc->lastModified()) {
204 deleteTransaction(incidence);
205 return false;
206 }
207 mCalendar->deleteTodo(todo);
208 } else {
209 deleteTransaction(incidence);
210 return false;
211 }
212 }
213 }
214 }
215 mCalendar->addIncidence(inc);
216 deleteTransaction(incidence);
217 return true;
218}
219
220bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status status)
221{
222 deleteTransaction(incidence);
223 return false;
224}
225
226bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status status)
227{
228 bool ret = false;
229 Event *even = mCalendar->event(incidence->uid());
230 if (even) {
231 mCalendar->deleteEvent(even);
232 ret = true;
233 } else {
234 Todo *todo = mCalendar->todo(incidence->uid());
235 if (todo) {
236 mCalendar->deleteTodo(todo);
237 ret = true;
238 }
239 }
240 deleteTransaction(incidence);
241 return ret;
242}
243
244bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status status)
245{
246 deleteTransaction(incidence);
247 return false;
248}
249
250//bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
251//{
252// deleteTransaction(incidence);
253// return false;
254//}
255
256bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status status, Method method)
257{
258 if(incidence->type()=="FreeBusy") {
259 return acceptFreeBusy(incidence, method);
260 }
261 bool ret = false;
262 Event *ev = mCalendar->event(incidence->uid());
263 Todo *to = mCalendar->todo(incidence->uid());
264 if (ev || to) {
265 //get matching attendee in calendar
266 kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
267 QPtrList<Attendee> attendeesIn = incidence->attendees();
268 QPtrList<Attendee> attendeesEv;
269 if (ev) attendeesEv = ev->attendees();
270 if (to) attendeesEv = to->attendees();
271 Attendee *attIn;
272 Attendee *attEv;
273 for ( attIn = attendeesIn.first(); attIn; attIn = attendeesIn.next() ) {
274 for ( attEv = attendeesEv.first(); attEv; attEv = attendeesEv.next() ) {
275 if (attIn->email()==attEv->email()) {
276 //update attendee-info
277 kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
278 attEv->setStatus(attIn->status());
279 attEv->setRSVP(false);
280 // better to not update the sequence number with replys
281 //if (ev) ev->setRevision(ev->revision()+1);
282 //if (to) to->setRevision(to->revision()+1);
283 ret = true;
284 }
285 }
286 }
287 }
288 if (ret) deleteTransaction(incidence);
289 return ret;
290}
291
292bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status status)
293{
294 // handled in korganizer's IncomingDialog
295 deleteTransaction(incidence);
296 return false;
297}
298
299bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status status)
300{
301 deleteTransaction(incidence);
302 return false;
303}
304
305bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
306{
307 FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);
308
309 QString freeBusyDirName = locateLocal("appdata","freebusy");
310 kdDebug() << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDirName << endl;
311
312 QString from;
313 if(method == Scheduler::Publish) {
314 from = freebusy->organizer();
315 }
316 if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
317 Attendee *attendee = freebusy->attendees().first();
318 from = attendee->email();
319 }
320
321 QDir freeBusyDir(freeBusyDirName);
322 if (!freeBusyDir.exists()) {
323 kdDebug() << "Directory " << freeBusyDirName << " does not exist!" << endl;
324 kdDebug() << "Creating directory: " << freeBusyDirName << endl;
325
326 if(!freeBusyDir.mkdir(freeBusyDirName, TRUE)) {
327 kdDebug() << "Could not create directory: " << freeBusyDirName << endl;
328 return false;
329 }
330 }
331
332 QString filename(freeBusyDirName);
333 filename += "/";
334 filename += from;
335 filename += ".ifb";
336 QFile f(filename);
337
338 kdDebug() << "acceptFreeBusy: filename" << filename << endl;
339
340 freebusy->clearAttendees();
341 freebusy->setOrganizer(from);
342
343 QString messageText = mFormat->createScheduleMessage(freebusy, Publish);
344
345 if (!f.open(IO_ReadWrite)) {
346 kdDebug() << "acceptFreeBusy: Can't open:" << filename << " for writing" << endl;
347 return false;
348 }
349 QTextStream t(&f);
350 t << messageText;
351 f.close();
352
353 deleteTransaction(incidence);
354 return true;
355}
diff --git a/libkcal/scheduler.h b/libkcal/scheduler.h
new file mode 100644
index 0000000..a9f43b9
--- a/dev/null
+++ b/libkcal/scheduler.h
@@ -0,0 +1,133 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef SCHEDULER_H
21#define SCHEDULER_H
22
23// iTIP transactions base class
24
25#include <qstring.h>
26#include <qptrlist.h>
27
28namespace KCal {
29
30class IncidenceBase;
31class Event;
32class Calendar;
33class ICalFormat;
34
35/**
36 This class provides an encapsulation of a scheduling message. It associates an
37 incidence with a method and status information. This class is used by the
38 Scheduler class.
39
40 @short A Scheduling message
41*/
42class ScheduleMessage {
43 public:
44 /** Message status. */
45 enum Status { PublishNew, Obsolete, RequestNew, RequestUpdate, Unknown };
46
47 /**
48 Create a scheduling message with method as defined in Scheduler::Method
49 and a status.
50 */
51 ScheduleMessage(IncidenceBase *,int method,Status status);
52 ~ScheduleMessage() {};
53
54 /** Return event associated with this message. */
55 IncidenceBase *event() { return mIncidence; }
56 /** Return iTIP method associated with this message. */
57 int method() { return mMethod; }
58 /** Return status of this message. */
59 Status status() { return mStatus; }
60 /** Return error message if there is any. */
61 QString error() { return mError; }
62
63 /** Return a human-readable name for an ical message status. */
64 static QString statusName(Status status);
65
66 private:
67 IncidenceBase *mIncidence;
68 int mMethod;
69 Status mStatus;
70 QString mError;
71};
72
73/**
74 This class provides an encapsulation of iTIP transactions. It is an abstract
75 base class for inheritance by implementations of the iTIP scheme like iMIP or
76 iRIP.
77*/
78class Scheduler {
79 public:
80 /** iTIP methods. */
81 enum Method { Publish,Request,Refresh,Cancel,Add,Reply,Counter,
82 Declinecounter,NoMethod };
83
84 /** Create scheduler for calendar specified as argument. */
85 Scheduler(Calendar *calendar);
86 virtual ~Scheduler();
87
88 /** iTIP publish action */
89 virtual bool publish (IncidenceBase *incidence,const QString &recipients) = 0;
90 /** Perform iTIP transaction on incidence. The method is specified as the
91 method argumanet and can be any valid iTIP method. */
92 virtual bool performTransaction(IncidenceBase *incidence,Method method) = 0;
93 /** Perform iTIP transaction on incidence to specified recipient(s). The
94 method is specified as the method argumanet and can be any valid iTIP
95 method. */
96 virtual bool performTransaction(IncidenceBase *incidence,Method method,const QString &recipients) = 0;
97 /** Retrieve incoming iTIP transactions */
98 virtual QPtrList<ScheduleMessage> retrieveTransactions() = 0;
99
100 /**
101 Accept transaction. The incidence argument specifies the iCal compoennt
102 on which the transaction acts. The status is the result of processing a
103 iTIP message with the current calendar and specifies the action to be
104 taken for this incidence.
105 */
106 bool acceptTransaction(IncidenceBase *,Method method,ScheduleMessage::Status status);
107
108 /** Return a machine-readable name for a iTIP method. */
109 static QString methodName(Method);
110 /** Return a translated and human-readable name for a iTIP method. */
111 static QString translatedMethodName(Method);
112
113 virtual bool deleteTransaction(IncidenceBase *incidence);
114
115 protected:
116
117 bool acceptPublish(IncidenceBase *,ScheduleMessage::Status status, Method method);
118 bool acceptRequest(IncidenceBase *,ScheduleMessage::Status status);
119 bool acceptAdd(IncidenceBase *,ScheduleMessage::Status status);
120 bool acceptCancel(IncidenceBase *,ScheduleMessage::Status status);
121 bool acceptDeclineCounter(IncidenceBase *,ScheduleMessage::Status status);
122 bool acceptReply(IncidenceBase *,ScheduleMessage::Status status, Method method);
123 bool acceptRefresh(IncidenceBase *,ScheduleMessage::Status status);
124 bool acceptCounter(IncidenceBase *,ScheduleMessage::Status status);
125 bool acceptFreeBusy(IncidenceBase *,Method method);
126
127 Calendar *mCalendar;
128 ICalFormat *mFormat;
129};
130
131}
132
133#endif // SCHEDULER_H
diff --git a/libkcal/sharpformat.cpp b/libkcal/sharpformat.cpp
new file mode 100644
index 0000000..f83f72e
--- a/dev/null
+++ b/libkcal/sharpformat.cpp
@@ -0,0 +1,1007 @@
1/*
2 This file is part of libkcal.
3
4 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#include <qdatetime.h>
23#include <qstring.h>
24#include <qapplication.h>
25#include <qptrlist.h>
26#include <qregexp.h>
27#include <qmessagebox.h>
28#include <qclipboard.h>
29#include <qfile.h>
30#include <qtextstream.h>
31#include <qtextcodec.h>
32#include <qxml.h>
33#include <qlabel.h>
34
35#include <kdebug.h>
36#include <klocale.h>
37#include <kglobal.h>
38
39#include "calendar.h"
40#include "alarm.h"
41#include "recurrence.h"
42#include "calendarlocal.h"
43
44#include "sharpformat.h"
45
46using namespace KCal;
47
48//CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY
49// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
50
51//ARSD silentalarm = 0
52// 11 RTYP 225 no /0 dialy/ 1 weekly/ 3 month by date/ 2 month by day(pos)/ yearly
53// 12 RFRQ
54// 13 RPOS pos = 4. monday in month
55// 14 RDYS days: 1 mon/ 2 tue .. 64 sun
56// 15 REND 0 = no end/ 1 = end
57// 16 REDT rec end dt
58//ALSD
59//ALED
60//MDAY
61
62class SharpParser : public QObject
63{
64 public:
65 SharpParser( Calendar *calendar ) : mCalendar( calendar ) {
66 oldCategories = 0;
67 }
68
69 bool startElement( Calendar *existingCalendar, const QStringList & attList, QString qName )
70 {
71 int i = 1;
72 bool skip = true;
73 int max = attList.count() -2;
74 while ( i < max ) {
75 if ( !attList[i].isEmpty() ) {
76 skip = false;
77 break;
78 }
79 ++i ;
80 }
81 if ( skip )
82 return false;
83 ulong cSum = SharpFormat::getCsum(attList );
84
85 if ( qName == "Event" ) {
86 Event *event;
87 event = existingCalendar->event( attList[0].toInt() );
88 if ( event )
89 event = (Event*)event->clone();
90 else
91 event = new Event;
92 event->setZaurusId( attList[0].toInt() );
93 event->setZaurusUid( cSum );
94 event->setZaurusStat( -2 );
95
96 event->setSummary( attList[2] );
97 event->setLocation( attList[3] );
98 event->setDescription( attList[4] );
99 if ( attList[7] == "1" ) {
100 event->setDtStart( QDateTime(fromString( attList[17]+"000000", false ).date(),QTime(0,0,0 ) ));
101 event->setDtEnd( QDateTime(fromString( attList[18]+"000000", false ).date(),QTime(0,0,0 )));
102 event->setFloats( true );
103 } else {
104 event->setFloats( false );
105 event->setDtStart( fromString( attList[5] ) );
106 event->setDtEnd( fromString( attList[6] ));
107 }
108
109 QString rtype = attList[11];
110 if ( rtype != "255" ) {
111 // qDebug("recurs ");
112 QDate startDate = event->dtStart().date();
113
114 QString freqStr = attList[12];
115 int freq = freqStr.toInt();
116
117 QString hasEndDateStr = attList[15] ;
118 bool hasEndDate = hasEndDateStr == "1";
119
120 QString endDateStr = attList[16];
121 QDate endDate = fromString( endDateStr ).date();
122
123 QString weekDaysStr = attList[14];
124 uint weekDaysNum = weekDaysStr.toInt();
125
126 QBitArray weekDays( 7 );
127 int i;
128 int bb = 1;
129 for( i = 1; i <= 7; ++i ) {
130 weekDays.setBit( i - 1, ( bb & weekDaysNum ));
131 bb = 2 << (i-1);
132 //qDebug(" %d bit %d ",i-1,weekDays.at(i-1) );
133 }
134 // qDebug("next ");
135 QString posStr = attList[13];
136 int pos = posStr.toInt();
137 Recurrence *r = event->recurrence();
138
139 if ( rtype == "0" ) {
140 if ( hasEndDate ) r->setDaily( freq, endDate );
141 else r->setDaily( freq, -1 );
142 } else if ( rtype == "1" ) {
143 if ( hasEndDate ) r->setWeekly( freq, weekDays, endDate );
144 else r->setWeekly( freq, weekDays, -1 );
145 } else if ( rtype == "3" ) {
146 if ( hasEndDate )
147 r->setMonthly( Recurrence::rMonthlyDay, freq, endDate );
148 else
149 r->setMonthly( Recurrence::rMonthlyDay, freq, -1 );
150 r->addMonthlyDay( startDate.day() );
151 } else if ( rtype == "2" ) {
152 if ( hasEndDate )
153 r->setMonthly( Recurrence::rMonthlyPos, freq, endDate );
154 else
155 r->setMonthly( Recurrence::rMonthlyPos, freq, -1 );
156 QBitArray days( 7 );
157 days.fill( false );
158 days.setBit( startDate.dayOfWeek() - 1 );
159 r->addMonthlyPos( pos, days );
160 } else if ( rtype == "4" ) {
161 if ( hasEndDate )
162 r->setYearly( Recurrence::rYearlyMonth, freq, endDate );
163 else
164 r->setYearly( Recurrence::rYearlyMonth, freq, -1 );
165 r->addYearlyNum( startDate.month() );
166 }
167 }
168
169 QString categoryList = attList[1] ;
170 event->setCategories( lookupCategories( categoryList ) );
171
172 // strange 0 semms to mean: alarm enabled
173 if ( attList[8] == "0" ) {
174 Alarm *alarm;
175 if ( event->alarms().count() > 0 )
176 alarm = event->alarms().first();
177 else {
178 alarm = new Alarm( event );
179 event->addAlarm( alarm );
180 }
181 alarm->setType( Alarm::Audio );
182 alarm->setEnabled( true );
183 int alarmOffset = attList[9].toInt();
184 alarm->setStartOffset( alarmOffset * -60 );
185 }
186
187 mCalendar->addEvent( event);
188 } else if ( qName == "Todo" ) {
189 Todo *todo;
190
191 todo = existingCalendar->todo( attList[0].toInt() );
192 if (todo )
193 todo = (Todo*)todo->clone();
194 else
195 todo = new Todo;
196
197//CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1
198// 0 1 2 3 4 5 6 7 8
199//1,,,,,1,4,Loch zumachen,""
200//3,Privat,20040317T000000,20040318T000000,20040319T000000,0,5,Call bbb,"notes123 bbb gggg ""bb "" "
201//2,"Familie,Freunde,Holiday",20040318T000000,20040324T000000,20040317T000000,1,2,tod2,notes
202
203 todo->setZaurusId( attList[0].toInt() );
204 todo->setZaurusUid( cSum );
205 todo->setZaurusStat( -2 );
206
207 todo->setSummary( attList[7] );
208 todo->setDescription( attList[8]);
209
210 int priority = attList[6].toInt();
211 if ( priority == 0 ) priority = 3;
212 todo->setPriority( priority );
213
214 QString categoryList = attList[1];
215 todo->setCategories( lookupCategories( categoryList ) );
216
217
218
219 QString hasDateStr = attList[3]; // due
220 if ( !hasDateStr.isEmpty() ) {
221 if ( hasDateStr.right(6) == "000000" ) {
222 todo->setDtDue( QDateTime(fromString( hasDateStr, false ).date(), QTime(0,0,0 )) );
223 todo->setFloats( true );
224 }
225 else {
226 todo->setDtDue( fromString( hasDateStr ) );
227 todo->setFloats( false );
228 }
229
230 todo->setHasDueDate( true );
231 }
232 hasDateStr = attList[2];//start
233 if ( !hasDateStr.isEmpty() ) {
234
235 todo->setDtStart( fromString( hasDateStr ) );
236 todo->setHasStartDate( true);
237 } else
238 todo->setHasStartDate( false );
239 hasDateStr = attList[4];//completed
240 if ( !hasDateStr.isEmpty() ) {
241 todo->setCompleted(fromString( hasDateStr ) );
242 }
243 QString completedStr = attList[5];
244 if ( completedStr == "0" )
245 todo->setCompleted( true );
246 else
247 todo->setCompleted( false );
248 mCalendar->addTodo( todo );
249
250 } else if ( qName == "Category" ) {
251 /*
252 QString id = attributes.value( "id" );
253 QString name = attributes.value( "name" );
254 setCategory( id, name );
255 */
256 }
257 //qDebug("end ");
258 return true;
259 }
260
261
262 void setCategoriesList ( QStringList * c )
263 {
264 oldCategories = c;
265 }
266
267 QDateTime fromString ( QString s, bool useTz = true ) {
268 QDateTime dt;
269 int y,m,t,h,min,sec;
270 y = s.mid(0,4).toInt();
271 m = s.mid(4,2).toInt();
272 t = s.mid(6,2).toInt();
273 h = s.mid(9,2).toInt();
274 min = s.mid(11,2).toInt();
275 sec = s.mid(13,2).toInt();
276 dt = QDateTime(QDate(y,m,t), QTime(h,min,sec));
277 int offset = KGlobal::locale()->localTimeOffset( dt );
278 if ( useTz )
279 dt = dt.addSecs ( offset*60);
280 return dt;
281
282 }
283 protected:
284 QDateTime toDateTime( const QString &value )
285 {
286 QDateTime dt;
287 dt.setTime_t( value.toUInt() );
288
289 return dt;
290 }
291
292 QStringList lookupCategories( const QString &categoryList )
293 {
294 QStringList categoryIds = QStringList::split( ";", categoryList );
295 QStringList categories;
296 QStringList::ConstIterator it;
297 for( it = categoryIds.begin(); it != categoryIds.end(); ++it ) {
298 QString cate = category( *it );
299 if ( oldCategories ) {
300 if ( ! oldCategories->contains( cate ) )
301 oldCategories->append( cate );
302 }
303 categories.append(cate );
304 }
305 return categories;
306 }
307
308 private:
309 Calendar *mCalendar;
310 QStringList * oldCategories;
311 static QString category( const QString &id )
312 {
313 QMap<QString,QString>::ConstIterator it = mCategoriesMap.find( id );
314 if ( it == mCategoriesMap.end() ) return id;
315 else return *it;
316 }
317
318 static void setCategory( const QString &id, const QString &name )
319 {
320 mCategoriesMap.insert( id, name );
321 }
322
323 static QMap<QString,QString> mCategoriesMap;
324};
325
326QMap<QString,QString> SharpParser::mCategoriesMap;
327
328SharpFormat::SharpFormat()
329{
330 mCategories = 0;
331}
332
333SharpFormat::~SharpFormat()
334{
335}
336ulong SharpFormat::getCsum( const QStringList & attList)
337{
338 int max = attList.count() -1;
339 ulong cSum = 0;
340 int j,k,i;
341 int add;
342 for ( i = 1; i < max ; ++i ) {
343 QString s = attList[i];
344 if ( ! s.isEmpty() ){
345 j = s.length();
346 for ( k = 0; k < j; ++k ) {
347 int mul = k +1;
348 add = s[k].unicode ();
349 if ( k < 16 )
350 mul = mul * mul;
351 add = add * mul *i*i*i;
352 cSum += add;
353 }
354 }
355 }
356 return cSum;
357
358}
359#include <stdlib.h>
360#define DEBUGMODE false
361bool SharpFormat::load( Calendar *calendar, Calendar *existngCal )
362{
363
364
365 bool debug = DEBUGMODE;
366 //debug = true;
367 QString text;
368 QString codec = "utf8";
369 QLabel status ( i18n("Reading events ..."), 0 );
370
371 int w = status.sizeHint().width()+20 ;
372 if ( w < 200 ) w = 200;
373 int h = status.sizeHint().height()+20 ;
374 int dw = QApplication::desktop()->width();
375 int dh = QApplication::desktop()->height();
376 status.setCaption(i18n("Reading DTM Data") );
377 status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
378 status.show();
379 status.raise();
380 qApp->processEvents();
381 QString fileName;
382 if ( ! debug ) {
383 fileName = "/tmp/kopitempout";
384 QString command ="db2file datebook -r -c "+ codec + " > " + fileName;
385 system ( command.latin1() );
386 } else {
387 fileName = "/tmp/events.txt";
388
389 }
390 QFile file( fileName );
391 if (!file.open( IO_ReadOnly ) ) {
392 return false;
393
394 }
395 QTextStream ts( &file );
396 ts.setCodec( QTextCodec::codecForName("utf8") );
397 text = ts.read();
398 file.close();
399 status.setText( i18n("Processing events ...") );
400 status.raise();
401 qApp->processEvents();
402 fromString2Cal( calendar, existngCal, text, "Event" );
403 status.setText( i18n("Reading todos ...") );
404 qApp->processEvents();
405 if ( ! debug ) {
406 fileName = "/tmp/kopitempout";
407 QString command = "db2file todo -r -c " + codec+ " > " + fileName;
408 system ( command.latin1() );
409 } else {
410 fileName = "/tmp/todo.txt";
411 }
412 file.setName( fileName );
413 if (!file.open( IO_ReadOnly ) ) {
414 return false;
415
416 }
417 ts.setDevice( &file );
418 text = ts.read();
419 file.close();
420
421 status.setText( i18n("Processing todos ...") );
422 status.raise();
423 qApp->processEvents();
424 fromString2Cal( calendar, existngCal, text, "Todo" );
425 return true;
426}
427int SharpFormat::getNumFromRecord( QString answer, Incidence* inc )
428{
429 int retval = -1;
430 QStringList templist;
431 QString tempString;
432 int start = 0;
433 int len = answer.length();
434 int end = answer.find ("\n",start)+1;
435 bool ok = true;
436 start = end;
437 int ccc = 0;
438 while ( start > 0 ) {
439 templist.clear();
440 ok = true;
441 int loopCount = 0;
442 while ( ok ) {
443 ++loopCount;
444 if ( loopCount > 25 ) {
445 qDebug("KO: Error in while loop");
446 ok = false;
447 start = 0;
448 break;
449 }
450 if ( ok )
451 tempString = getPart( answer, ok, start );
452 if ( start >= len || start == 0 ) {
453 start = 0;
454 ok = false;
455 }
456 if ( tempString.right(1) =="\n" )
457 tempString = tempString.left( tempString.length()-1);
458
459 templist.append( tempString );
460 }
461 ++ccc;
462 if ( ccc == 2 && loopCount < 25 ) {
463 start = 0;
464 bool ok;
465 int newnum = templist[0].toInt( &ok );
466 if ( ok && newnum > 0) {
467 retval = newnum;
468 inc->setZaurusId( newnum );
469 inc->setZaurusUid( getCsum( templist ) );
470 inc->setZaurusStat( -4 );
471 }
472 }
473 }
474 //qDebug("getNumFromRecord returning : %d ", retval);
475 return retval;
476}
477bool SharpFormat::save( Calendar *calendar)
478{
479
480 QLabel status ( i18n("Processing/adding events ..."), 0 );
481 int w = status.sizeHint().width()+20 ;
482 if ( w < 200 ) w = 200;
483 int h = status.sizeHint().height()+20 ;
484 int dw = QApplication::desktop()->width();
485 int dh = QApplication::desktop()->height();
486 status.setCaption(i18n("Writing DTM Data") );
487 status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
488 status.show();
489 status.raise();
490 qApp->processEvents();
491 bool debug = DEBUGMODE;
492 QString codec = "utf8";
493 QString answer;
494 QString ePrefix = "CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY\n";
495 QString tPrefix = "CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1\n";
496 QString command;
497 QPtrList<Event> er = calendar->rawEvents();
498 Event* ev = er.first();
499 QString fileName = "/tmp/kopitempout";
500 int i = 0;
501 QString changeString = ePrefix;
502 QString deleteString = ePrefix;
503 bool deleteEnt = false;
504 bool changeEnt = false;
505 QString message = i18n("Processing event # ");
506 int procCount = 0;
507 while ( ev ) {
508 //qDebug("i %d ", ++i);
509 if ( ev->zaurusStat() != -2 ) {
510 status.setText ( message + QString::number ( ++procCount ) );
511 qApp->processEvents();
512 QString eString = getEventString( ev );
513 if ( ev->zaurusStat() == -3 ) { // delete
514 // deleting empty strings does not work.
515 // we write first and x and then delete the record with the x
516 eString = eString.replace( QRegExp(",\"\""),",\"x\"" );
517 changeString += eString + "\n";
518 deleteString += eString + "\n";
519 deleteEnt = true;
520 changeEnt = true;
521 }
522 else if ( ev->zaurusId() == -1 ) { // add new
523 command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName;
524 system ( command.utf8() );
525 QFile file( fileName );
526 if (!file.open( IO_ReadOnly ) ) {
527 return false;
528
529 }
530 QTextStream ts( &file );
531 ts.setCodec( QTextCodec::codecForName("utf8") );
532 answer = ts.read();
533 file.close();
534 //qDebug("answer \n%s ", answer.latin1());
535 getNumFromRecord( answer, ev ) ;
536
537 }
538 else { // change existing
539 //qDebug("canging %d %d",ev->zaurusStat() ,ev->zaurusId() );
540 //command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName;
541 changeString += eString + "\n";
542 changeEnt = true;
543
544 }
545 }
546 ev = er.next();
547 }
548 status.setText ( i18n("Changing events ...") );
549 qApp->processEvents();
550 //qDebug("changing... ");
551 if ( changeEnt ) {
552 QFile file( fileName );
553 if (!file.open( IO_WriteOnly ) ) {
554 return false;
555
556 }
557 QTextStream ts( &file );
558 ts.setCodec( QTextCodec::codecForName("utf8") );
559 ts << changeString ;
560 file.close();
561 command = "db2file datebook -w -g -c " + codec+ " < "+ fileName;
562 system ( command.latin1() );
563 //qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1());
564
565 }
566 status.setText ( i18n("Deleting events ...") );
567 qApp->processEvents();
568 //qDebug("deleting... ");
569 if ( deleteEnt ) {
570 QFile file( fileName );
571 if (!file.open( IO_WriteOnly ) ) {
572 return false;
573
574 }
575 QTextStream ts( &file );
576 ts.setCodec( QTextCodec::codecForName("utf8") );
577 ts << deleteString;
578 file.close();
579 command = "db2file datebook -d -c " + codec+ " < "+ fileName;
580 system ( command.latin1() );
581 // qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1());
582 }
583
584
585 changeString = tPrefix;
586 deleteString = tPrefix;
587 status.setText ( i18n("Processing todos ...") );
588 qApp->processEvents();
589 QPtrList<Todo> tl = calendar->rawTodos();
590 Todo* to = tl.first();
591 i = 0;
592 message = i18n("Processing todo # ");
593 procCount = 0;
594 while ( to ) {
595 if ( to->zaurusStat() != -2 ) {
596 status.setText ( message + QString::number ( ++procCount ) );
597 qApp->processEvents();
598 QString eString = getTodoString( to );
599 if ( to->zaurusStat() == -3 ) { // delete
600 // deleting empty strings does not work.
601 // we write first and x and then delete the record with the x
602 eString = eString.replace( QRegExp(",\"\""),",\"x\"" );
603 changeString += eString + "\n";
604 deleteString += eString + "\n";
605 deleteEnt = true;
606 changeEnt = true;
607 }
608 else if ( to->zaurusId() == -1 ) { // add new
609 command = "(echo \"" + tPrefix + eString + "\" ) | db2file todo -w -g -c " + codec+ " > "+ fileName;
610 system ( command.utf8() );
611 QFile file( fileName );
612 if (!file.open( IO_ReadOnly ) ) {
613 return false;
614
615 }
616 QTextStream ts( &file );
617 ts.setCodec( QTextCodec::codecForName("utf8") );
618 answer = ts.read();
619 file.close();
620 //qDebug("answer \n%s ", answer.latin1());
621 getNumFromRecord( answer, to ) ;
622
623 }
624 else { // change existing
625 //qDebug("canging %d %d",to->zaurusStat() ,to->zaurusId() );
626 //command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName;
627 changeString += eString + "\n";
628 changeEnt = true;
629
630 }
631 }
632
633 to = tl.next();
634 }
635 status.setText ( i18n("Changing todos ...") );
636 qApp->processEvents();
637 //qDebug("changing... ");
638 if ( changeEnt ) {
639 QFile file( fileName );
640 if (!file.open( IO_WriteOnly ) ) {
641 return false;
642
643 }
644 QTextStream ts( &file );
645 ts.setCodec( QTextCodec::codecForName("utf8") );
646 ts << changeString ;
647 file.close();
648 command = "db2file todo -w -g -c " + codec+ " < "+ fileName;
649 system ( command.latin1() );
650 //qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1());
651
652 }
653 status.setText ( i18n("Deleting todos ...") );
654 qApp->processEvents();
655 //qDebug("deleting... ");
656 if ( deleteEnt ) {
657 QFile file( fileName );
658 if (!file.open( IO_WriteOnly ) ) {
659 return false;
660
661 }
662 QTextStream ts( &file );
663 ts.setCodec( QTextCodec::codecForName("utf8") );
664 ts << deleteString;
665 file.close();
666 command = "db2file todo -d -c " + codec+ " < "+ fileName;
667 system ( command.latin1() );
668 // qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1());
669 }
670
671 return true;
672}
673QString SharpFormat::dtToString( const QDateTime& dti, bool useTZ )
674{
675 QString datestr;
676 QString timestr;
677 int offset = KGlobal::locale()->localTimeOffset( dti );
678 QDateTime dt;
679 if (useTZ)
680 dt = dti.addSecs ( -(offset*60));
681 else
682 dt = dti;
683 if(dt.date().isValid()){
684 const QDate& date = dt.date();
685 datestr.sprintf("%04d%02d%02d",
686 date.year(), date.month(), date.day());
687 }
688 if(dt.time().isValid()){
689 const QTime& time = dt.time();
690 timestr.sprintf("T%02d%02d%02d",
691 time.hour(), time.minute(), time.second());
692 }
693 return datestr + timestr;
694}
695QString SharpFormat::getEventString( Event* event )
696{
697 QStringList list;
698 list.append( QString::number(event->zaurusId() ) );
699 list.append( event->categories().join(",") );
700 if ( !event->summary().isEmpty() )
701 list.append( event->summary() );
702 else
703 list.append("" );
704 if ( !event->location().isEmpty() )
705 list.append( event->location() );
706 else
707 list.append("" );
708 if ( !event->description().isEmpty() )
709 list.append( event->description() );
710 else
711 list.append( "" );
712 if ( event->doesFloat () ) {
713 list.append( dtToString( QDateTime(event->dtStart().date(), QTime(0,0,0)), false ));
714 list.append( dtToString( QDateTime(event->dtEnd().date(),QTime(23,59,59)), false )); //6
715 list.append( "1" );
716
717 }
718 else {
719 list.append( dtToString( event->dtStart()) );
720 list.append( dtToString( event->dtEnd()) ); //6
721 list.append( "0" );
722 }
723 bool noAlarm = true;
724 if ( event->alarms().count() > 0 ) {
725 Alarm * al = event->alarms().first();
726 if ( al->enabled() ) {
727 noAlarm = false;
728 list.append( "0" ); // yes, 0 == alarm
729 list.append( QString::number( al->startOffset().asSeconds()/(-60) ) );
730 if ( al->type() == Alarm::Audio )
731 list.append( "1" ); // type audio
732 else
733 list.append( "0" ); // type silent
734 }
735 }
736 if ( noAlarm ) {
737 list.append( "1" ); // yes, 1 == no alarm
738 list.append( "0" ); // no alarm offset
739 list.append( "1" ); // type
740 }
741 // next is: 11
742 // next is: 11-16 are recurrence
743 Recurrence* rec = event->recurrence();
744
745 bool writeEndDate = false;
746 switch ( rec->doesRecur() )
747 {
748 case Recurrence::rDaily: // 0
749 list.append( "0" );
750 list.append( QString::number( rec->frequency() ));//12
751 list.append( "0" );
752 list.append( "0" );
753 writeEndDate = true;
754 break;
755 case Recurrence::rWeekly:// 1
756 list.append( "1" );
757 list.append( QString::number( rec->frequency()) );//12
758 list.append( "0" );
759 {
760 int days = 0;
761 QBitArray weekDays = rec->days();
762 int i;
763 for( i = 1; i <= 7; ++i ) {
764 if ( weekDays[i-1] ) {
765 days += 1 << (i-1);
766 }
767 }
768 list.append( QString::number( days ) );
769 }
770 //pending weekdays
771 writeEndDate = true;
772
773 break;
774 case Recurrence::rMonthlyPos:// 2
775 list.append( "2" );
776 list.append( QString::number( rec->frequency()) );//12
777
778 writeEndDate = true;
779 {
780 int count = 1;
781 QPtrList<Recurrence::rMonthPos> rmp;
782 rmp = rec->monthPositions();
783 if ( rmp.first()->negative )
784 count = 5 - rmp.first()->rPos - 1;
785 else
786 count = rmp.first()->rPos - 1;
787 list.append( QString::number( count ) );
788
789 }
790
791 list.append( "0" );
792 break;
793 case Recurrence::rMonthlyDay:// 3
794 list.append( "3" );
795 list.append( QString::number( rec->frequency()) );//12
796 list.append( "0" );
797 list.append( "0" );
798 writeEndDate = true;
799 break;
800 case Recurrence::rYearlyMonth://4
801 list.append( "4" );
802 list.append( QString::number( rec->frequency()) );//12
803 list.append( "0" );
804 list.append( "0" );
805 writeEndDate = true;
806 break;
807
808 default:
809 list.append( "255" );
810 list.append( QString() );
811 list.append( "0" );
812 list.append( QString() );
813 list.append( "0" );
814 list.append( "20991231T000000" );
815 break;
816 }
817 if ( writeEndDate ) {
818
819 if ( rec->endDate().isValid() ) { // 15 + 16
820 list.append( "1" );
821 list.append( dtToString( rec->endDate()) );
822 } else {
823 list.append( "0" );
824 list.append( "20991231T000000" );
825 }
826
827 }
828 if ( event->doesFloat () ) {
829 list.append( dtToString( event->dtStart(), false ).left( 8 ));
830 list.append( dtToString( event->dtEnd(), false ).left( 8 )); //6
831
832 }
833 else {
834 list.append( QString() );
835 list.append( QString() );
836
837 }
838 if (event->dtStart().date() == event->dtEnd().date() )
839 list.append( "0" );
840 else
841 list.append( "1" );
842
843
844 for(QStringList::Iterator it=list.begin();
845 it!=list.end(); ++it){
846 QString& s = (*it);
847 s.replace(QRegExp("\""), "\"\"");
848 if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){
849 s.prepend('\"');
850 s.append('\"');
851 } else if(s.isEmpty() && !s.isNull()){
852 s = "\"\"";
853 }
854 }
855 return list.join(",");
856
857
858}
859QString SharpFormat::getTodoString( Todo* todo )
860{
861 QStringList list;
862 list.append( QString::number( todo->zaurusId() ) );
863 list.append( todo->categories().join(",") );
864
865 if ( todo->hasStartDate() ) {
866 list.append( dtToString( todo->dtStart()) );
867 } else
868 list.append( QString() );
869
870 if ( todo->hasDueDate() ) {
871 QTime tim;
872 if ( todo->doesFloat()) {
873 list.append( dtToString( QDateTime(todo->dtDue().date(),QTime( 0,0,0 )), false)) ;
874 } else {
875 list.append( dtToString(todo->dtDue() ) );
876 }
877 } else
878 list.append( QString() );
879
880 if ( todo->isCompleted() ) {
881 list.append( dtToString( todo->completed()) );
882 list.append( "0" ); // yes 0 == completed
883 } else {
884 list.append( dtToString( todo->completed()) );
885 list.append( "1" );
886 }
887 list.append( QString::number( todo->priority() ));
888 if( ! todo->summary().isEmpty() )
889 list.append( todo->summary() );
890 else
891 list.append( "" );
892 if (! todo->description().isEmpty() )
893 list.append( todo->description() );
894 else
895 list.append( "" );
896 for(QStringList::Iterator it=list.begin();
897 it!=list.end(); ++it){
898 QString& s = (*it);
899 s.replace(QRegExp("\""), "\"\"");
900 if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){
901 s.prepend('\"');
902 s.append('\"');
903 } else if(s.isEmpty() && !s.isNull()){
904 s = "\"\"";
905 }
906 }
907 return list.join(",");
908}
909QString SharpFormat::getPart( const QString & text, bool &ok, int &start )
910{
911 //qDebug("start %d ", start);
912
913 QString retval ="";
914 if ( text.at(start) == '"' ) {
915 if ( text.mid( start,2) == "\"\"" && !( text.mid( start+2,1) == "\"")) {
916 start = start +2;
917 if ( text.mid( start,1) == "," ) {
918 start += 1;
919 }
920 retval = "";
921 if ( text.mid( start,1) == "\n" ) {
922 start += 1;
923 ok = false;
924 }
925 return retval;
926 }
927 int hk = start+1;
928 hk = text.find ('"',hk);
929 while ( text.at(hk+1) == '"' )
930 hk = text.find ('"',hk+2);
931 retval = text.mid( start+1, hk-start-1);
932 start = hk+1;
933 retval.replace( QRegExp("\"\""), "\"");
934 if ( text.mid( start,1) == "," ) {
935 start += 1;
936 }
937 if ( text.mid( start,1) == "\n" ) {
938 start += 1;
939 ok = false;
940 }
941 //qDebug("retval***%s*** ",retval.latin1() );
942 return retval;
943
944 } else {
945 int nl = text.find ("\n",start);
946 int kom = text.find (',',start);
947 if ( kom < nl ) {
948 // qDebug("kom < nl %d ", kom);
949 retval = text.mid(start, kom-start);
950 start = kom+1;
951 return retval;
952 } else {
953 if ( nl == kom ) {
954 // qDebug(" nl == kom ");
955 start = 0;
956 ok = false;
957 return "0";
958 }
959 // qDebug(" nl < kom ", nl);
960 retval = text.mid( start, nl-start);
961 ok = false;
962 start = nl+1;
963 return retval;
964 }
965 }
966}
967bool SharpFormat::fromString( Calendar *calendar, const QString & text)
968{
969 return false;
970}
971bool SharpFormat::fromString2Cal( Calendar *calendar,Calendar *existingCalendar, const QString & text, const QString & type)
972{
973 // qDebug("test %s ", text.latin1());
974 QStringList templist;
975 QString tempString;
976 int start = 0;
977 int len = text.length();
978 int end = text.find ("\n",start)+1;
979 bool ok = true;
980 start = end;
981 SharpParser handler( calendar );
982 handler.setCategoriesList( mCategories );
983 while ( start > 0 ) {
984 templist.clear();
985 ok = true;
986 while ( ok ) {
987 tempString = getPart( text, ok, start );
988 if ( start >= len || start == 0 ) {
989 start = 0;
990 ok = false;
991 }
992 if ( tempString.right(1) =="\n" )
993 tempString = tempString.left( tempString.length()-1);
994 //if ( ok )
995 templist.append( tempString );
996 //qDebug("%d ---%s---", templist.count(),tempString.latin1() );
997 }
998 handler.startElement( existingCalendar, templist, type );
999 }
1000
1001 return false;
1002}
1003
1004QString SharpFormat::toString( Calendar * )
1005{
1006 return QString::null;
1007}
diff --git a/libkcal/sharpformat.h b/libkcal/sharpformat.h
new file mode 100644
index 0000000..0b13862
--- a/dev/null
+++ b/libkcal/sharpformat.h
@@ -0,0 +1,61 @@
1/*
2 This file is part of libkcal.
3
4 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21#ifndef SHARPFORMAT_H
22#define SHARPAFORMAT_H
23
24#include <qstring.h>
25
26#include "scheduler.h"
27
28#include "calformat.h"
29
30namespace KCal {
31
32/**
33 This class implements the calendar format used by Sharp.
34*/
35class SharpFormat : public QObject {
36 public:
37 /** Create new iCalendar format. */
38 SharpFormat();
39 virtual ~SharpFormat();
40
41 bool load( Calendar * ,Calendar *);
42 bool save( Calendar * );
43 void setCategoriesList ( QStringList * cat ){ mCategories = cat; }
44 bool fromString2Cal( Calendar *, Calendar *, const QString & , const QString & );
45 bool fromString( Calendar *, const QString & );
46 QString toString( Calendar * );
47 static ulong getCsum( const QStringList & );
48
49 private:
50 QString getEventString( Event* );
51 QString getTodoString( Todo* );
52 QString dtToString( const QDateTime& dt, bool useTZ = true );
53
54 QStringList *mCategories;
55 int getNumFromRecord( QString answer,Incidence* inc ) ;
56 QString getPart( const QString & text, bool &ok, int &start );
57};
58
59}
60
61#endif
diff --git a/libkcal/todo.cpp b/libkcal/todo.cpp
new file mode 100644
index 0000000..0c1e3e4
--- a/dev/null
+++ b/libkcal/todo.cpp
@@ -0,0 +1,316 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <kglobal.h>
22#include <klocale.h>
23#include <kdebug.h>
24
25#include "todo.h"
26
27using namespace KCal;
28
29Todo::Todo(): Incidence()
30{
31// mStatus = TENTATIVE;
32
33 mHasDueDate = false;
34 setHasStartDate( false );
35 mCompleted = getEvenTime(QDateTime::currentDateTime());
36 mHasCompletedDate = false;
37 mPercentComplete = 0;
38}
39
40Todo::Todo(const Todo &t) : Incidence(t)
41{
42 mDtDue = t.mDtDue;
43 mHasDueDate = t.mHasDueDate;
44 mCompleted = t.mCompleted;
45 mHasCompletedDate = t.mHasCompletedDate;
46 mPercentComplete = t.mPercentComplete;
47}
48
49Todo::~Todo()
50{
51
52}
53
54Incidence *Todo::clone()
55{
56 return new Todo(*this);
57}
58
59
60bool KCal::operator==( const Todo& t1, const Todo& t2 )
61{
62
63 bool ret = operator==( (const Incidence&)t1, (const Incidence&)t2 );
64 if ( ! ret )
65 return false;
66 if ( t1.hasDueDate() == t2.hasDueDate() ) {
67 if ( t1.hasDueDate() ) {
68 if ( t1.doesFloat() == t2.doesFloat() ) {
69 if ( t1.doesFloat() ) {
70 if ( t1.dtDue().date() != t2.dtDue().date() )
71 return false;
72 } else
73 if ( t1.dtDue() != t2.dtDue() )
74 return false;
75 } else
76 return false;// float !=
77 }
78
79 } else
80 return false;
81 if ( t1.percentComplete() != t2.percentComplete() )
82 return false;
83 if ( t1.isCompleted() ) {
84 if ( t1.hasCompletedDate() == t2.hasCompletedDate() ) {
85 if ( t1.hasCompletedDate() ) {
86 if ( t1.completed() != t2.completed() )
87 return false;
88 }
89
90 } else
91 return false;
92 }
93 return true;
94
95}
96
97void Todo::setDtDue(const QDateTime &dtDue)
98{
99 //int diffsecs = mDtDue.secsTo(dtDue);
100
101 /*if (mReadOnly) return;
102 const QPtrList<Alarm>& alarms = alarms();
103 for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next()) {
104 if (alarm->enabled()) {
105 alarm->setTime(alarm->time().addSecs(diffsecs));
106 }
107 }*/
108 mDtDue = getEvenTime(dtDue);
109
110 //kdDebug(5800) << "setDtDue says date is " << mDtDue.toString() << endl;
111
112 /*const QPtrList<Alarm>& alarms = alarms();
113 for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next())
114 alarm->setAlarmStart(mDtDue);*/
115
116 updated();
117}
118
119QDateTime Todo::dtDue() const
120{
121 return mDtDue;
122}
123
124QString Todo::dtDueTimeStr() const
125{
126 return KGlobal::locale()->formatTime(mDtDue.time());
127}
128
129QString Todo::dtDueDateStr(bool shortfmt) const
130{
131 return KGlobal::locale()->formatDate(mDtDue.date(),shortfmt);
132}
133
134QString Todo::dtDueStr(bool shortfmt) const
135{
136 return KGlobal::locale()->formatDateTime(mDtDue, shortfmt);
137}
138
139bool Todo::hasDueDate() const
140{
141 return mHasDueDate;
142}
143
144void Todo::setHasDueDate(bool f)
145{
146 if (mReadOnly) return;
147 mHasDueDate = f;
148 updated();
149}
150
151
152#if 0
153void Todo::setStatus(const QString &statStr)
154{
155 if (mReadOnly) return;
156 QString ss(statStr.upper());
157
158 if (ss == "X-ACTION")
159 mStatus = NEEDS_ACTION;
160 else if (ss == "NEEDS ACTION")
161 mStatus = NEEDS_ACTION;
162 else if (ss == "ACCEPTED")
163 mStatus = ACCEPTED;
164 else if (ss == "SENT")
165 mStatus = SENT;
166 else if (ss == "TENTATIVE")
167 mStatus = TENTATIVE;
168 else if (ss == "CONFIRMED")
169 mStatus = CONFIRMED;
170 else if (ss == "DECLINED")
171 mStatus = DECLINED;
172 else if (ss == "COMPLETED")
173 mStatus = COMPLETED;
174 else if (ss == "DELEGATED")
175 mStatus = DELEGATED;
176
177 updated();
178}
179
180void Todo::setStatus(int status)
181{
182 if (mReadOnly) return;
183 mStatus = status;
184 updated();
185}
186
187int Todo::status() const
188{
189 return mStatus;
190}
191
192QString Todo::statusStr() const
193{
194 switch(mStatus) {
195 case NEEDS_ACTION:
196 return QString("NEEDS ACTION");
197 break;
198 case ACCEPTED:
199 return QString("ACCEPTED");
200 break;
201 case SENT:
202 return QString("SENT");
203 break;
204 case TENTATIVE:
205 return QString("TENTATIVE");
206 break;
207 case CONFIRMED:
208 return QString("CONFIRMED");
209 break;
210 case DECLINED:
211 return QString("DECLINED");
212 break;
213 case COMPLETED:
214 return QString("COMPLETED");
215 break;
216 case DELEGATED:
217 return QString("DELEGATED");
218 break;
219 }
220 return QString("");
221}
222#endif
223
224bool Todo::isCompleted() const
225{
226 if (mPercentComplete == 100) return true;
227 else return false;
228}
229
230void Todo::setCompleted(bool completed)
231{
232 if (completed) mPercentComplete = 100;
233 else mPercentComplete = 0;
234 updated();
235}
236
237QDateTime Todo::completed() const
238{
239 return mCompleted;
240}
241
242QString Todo::completedStr() const
243{
244 return KGlobal::locale()->formatDateTime(mCompleted);
245}
246
247void Todo::setCompleted(const QDateTime &completed)
248{
249 mHasCompletedDate = true;
250 mPercentComplete = 100;
251 mCompleted = getEvenTime(completed);
252 updated();
253}
254
255bool Todo::hasCompletedDate() const
256{
257 return mHasCompletedDate;
258}
259
260int Todo::percentComplete() const
261{
262 return mPercentComplete;
263}
264
265void Todo::setPercentComplete(int v)
266{
267 mPercentComplete = v;
268 updated();
269}
270QDateTime Todo::getNextAlarmDateTime( bool * ok, int * offset ) const
271{
272 if ( isCompleted() || ! hasDueDate() || cancelled() ) {
273 *ok = false;
274 return QDateTime ();
275 }
276 QDateTime incidenceStart;
277 incidenceStart = dtDue();
278 bool enabled = false;
279 Alarm* alarm;
280 int off;
281 QDateTime alarmStart = QDateTime::currentDateTime().addDays( 3650 );;
282 // if ( QDateTime::currentDateTime() > incidenceStart ){
283// *ok = false;
284// return incidenceStart;
285// }
286 for (QPtrListIterator<Alarm> it(mAlarms); (alarm = it.current()) != 0; ++it) {
287 if (alarm->enabled()) {
288 if ( alarm->hasTime () ) {
289 if ( alarm->time() < alarmStart ) {
290 alarmStart = alarm->time();
291 enabled = true;
292 off = alarmStart.secsTo( incidenceStart );
293 }
294
295 } else {
296 int secs = alarm->startOffset().asSeconds();
297 if ( incidenceStart.addSecs( secs ) < alarmStart ) {
298 alarmStart = incidenceStart.addSecs( secs );
299 enabled = true;
300 off = -secs;
301 }
302 }
303 }
304 }
305 if ( enabled ) {
306 if ( alarmStart > QDateTime::currentDateTime() ) {
307 *ok = true;
308 * offset = off;
309 return alarmStart;
310 }
311 }
312 *ok = false;
313 return QDateTime ();
314
315}
316
diff --git a/libkcal/todo.h b/libkcal/todo.h
new file mode 100644
index 0000000..9aa92f8
--- a/dev/null
+++ b/libkcal/todo.h
@@ -0,0 +1,121 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20#ifndef TODO_H
21#define TODO_H
22//
23// Todo component, representing a VTODO object
24//
25
26#include "incidence.h"
27
28namespace KCal {
29
30/**
31 This class provides a Todo in the sense of RFC2445.
32*/
33class Todo : public Incidence
34{
35 public:
36 Todo();
37 Todo(const Todo &);
38 ~Todo();
39 typedef ListBase<Todo> List;
40 QCString type() const { return "Todo"; }
41
42 /** Return an exact copy of this todo. */
43 Incidence *clone();
44 QDateTime getNextAlarmDateTime( bool * ok, int * offset ) const;
45
46 /** for setting the todo's due date/time with a QDateTime. */
47 void setDtDue(const QDateTime &dtDue);
48 /** returns an event's Due date/time as a QDateTime. */
49 QDateTime dtDue() const;
50 /** returns an event's due time as a string formatted according to the
51 users locale settings */
52 QString dtDueTimeStr() const;
53 /** returns an event's due date as a string formatted according to the
54 users locale settings */
55 QString dtDueDateStr(bool shortfmt=true) const;
56 /** returns an event's due date and time as a string formatted according
57 to the users locale settings */
58 QString dtDueStr(bool shortfmt=true) const;
59
60 /** returns TRUE or FALSE depending on whether the todo has a due date */
61 bool hasDueDate() const;
62 /** sets the event's hasDueDate value. */
63 void setHasDueDate(bool f);
64
65
66 /** sets the event's status to the string specified. The string
67 * must be a recognized value for the status field, i.e. a string
68 * equivalent of the possible status enumerations previously described. */
69// void setStatus(const QString &statStr);
70 /** sets the event's status to the value specified. See the enumeration
71 * above for possible values. */
72// void setStatus(int);
73 /** return the event's status. */
74// int status() const;
75 /** return the event's status in string format. */
76// QString statusStr() const;
77
78 /** return, if this todo is completed */
79 bool isCompleted() const;
80 /** set completed state of this todo */
81 void setCompleted(bool);
82
83 /**
84 Return how many percent of the task are completed. Returns a value
85 between 0 and 100.
86 */
87 int percentComplete() const;
88 /**
89 Set how many percent of the task are completed. Valid values are in the
90 range from 0 to 100.
91 */
92 void setPercentComplete(int);
93
94 /** return date and time when todo was completed */
95 QDateTime completed() const;
96 QString completedStr() const;
97 /** set date and time of completion */
98 void setCompleted(const QDateTime &completed);
99
100 /** Return true, if todo has a date associated with completion */
101 bool hasCompletedDate() const;
102
103 private:
104 bool accept(Visitor &v) { return v.visit(this); }
105
106 QDateTime mDtDue; // due date of todo
107
108 bool mHasDueDate; // if todo has associated due date
109
110// int mStatus; // confirmed/delegated/tentative/etc
111
112 QDateTime mCompleted;
113 bool mHasCompletedDate;
114
115 int mPercentComplete;
116};
117
118 bool operator==( const Todo&, const Todo& );
119}
120
121#endif
diff --git a/libkcal/vcaldrag.cpp b/libkcal/vcaldrag.cpp
new file mode 100644
index 0000000..f01f332
--- a/dev/null
+++ b/libkcal/vcaldrag.cpp
@@ -0,0 +1,54 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#include "vcaldrag.h"
23
24#include "vcalformat.h"
25
26using namespace KCal;
27
28VCalDrag::VCalDrag( Calendar *cal, QWidget *parent, const char *name )
29 : QStoredDrag( "text/x-vCalendar", parent, name )
30{
31 VCalFormat format;
32 setEncodedData( format.toString( cal ).utf8() );
33}
34
35bool VCalDrag::canDecode( QMimeSource *me )
36{
37 return me->provides( "text/x-vCalendar" );
38}
39
40bool VCalDrag::decode( QMimeSource *de, Calendar *cal )
41{
42 bool success = false;
43
44 QByteArray payload = de->encodedData( "text/x-vCalendar" );
45 if ( payload.size() ) {
46 QString txt = QString::fromUtf8( payload.data() );
47
48 VCalFormat format;
49 success = format.fromString( cal, txt );
50 }
51
52 return success;
53}
54
diff --git a/libkcal/vcaldrag.h b/libkcal/vcaldrag.h
new file mode 100644
index 0000000..3048124
--- a/dev/null
+++ b/libkcal/vcaldrag.h
@@ -0,0 +1,47 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#ifndef VCALDRAG_H
23#define VCALDRAG_H
24
25#include <qdragobject.h>
26
27
28namespace KCal {
29
30class Calendar;
31
32/** vCalendar drag&drop class. */
33class VCalDrag : public QStoredDrag {
34 public:
35 /** Create a drag&drop object for vCalendar component \a vcal. */
36 VCalDrag( Calendar *vcal, QWidget *parent = 0, const char *name = 0 );
37 ~VCalDrag() {};
38
39 /** Return, if drag&drop object can be decode to vCalendar. */
40 static bool canDecode( QMimeSource * );
41 /** Decode drag&drop object to vCalendar component \a vcal. */
42 static bool decode( QMimeSource *e, Calendar *cal );
43};
44
45}
46
47#endif
diff --git a/libkcal/vcalformat.cpp b/libkcal/vcalformat.cpp
new file mode 100644
index 0000000..59030d5
--- a/dev/null
+++ b/libkcal/vcalformat.cpp
@@ -0,0 +1,1678 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brwon
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#include <qapplication.h>
23#include <qdatetime.h>
24#include <qstring.h>
25#include <qptrlist.h>
26#include <qregexp.h>
27#include <qclipboard.h>
28#include <qdialog.h>
29#include <qfile.h>
30
31#include <kdebug.h>
32#include <kmessagebox.h>
33#include <kiconloader.h>
34#include <klocale.h>
35
36#include "vcc.h"
37#include "vobject.h"
38
39#include "vcaldrag.h"
40#include "calendar.h"
41
42#include "vcalformat.h"
43
44using namespace KCal;
45
46VCalFormat::VCalFormat()
47{
48}
49
50VCalFormat::~VCalFormat()
51{
52}
53
54bool VCalFormat::load(Calendar *calendar, const QString &fileName)
55{
56 mCalendar = calendar;
57
58 clearException();
59
60 kdDebug(5800) << "VCalFormat::load() " << fileName << endl;
61
62 VObject *vcal = 0;
63
64 // this is not necessarily only 1 vcal. Could be many vcals, or include
65 // a vcard...
66 vcal = Parse_MIME_FromFileName(const_cast<char *>(QFile::encodeName(fileName).data()));
67
68 if (!vcal) {
69 setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
70 return FALSE;
71 }
72
73 // any other top-level calendar stuff should be added/initialized here
74
75 // put all vobjects into their proper places
76 populate(vcal);
77
78 // clean up from vcal API stuff
79 cleanVObjects(vcal);
80 cleanStrTbl();
81
82 return true;
83}
84
85
86bool VCalFormat::save(Calendar *calendar, const QString &fileName)
87{
88 mCalendar = calendar;
89
90 QString tmpStr;
91 VObject *vcal, *vo;
92
93 kdDebug(5800) << "VCalFormat::save(): " << fileName << endl;
94
95 vcal = newVObject(VCCalProp);
96
97 // addPropValue(vcal,VCLocationProp, "0.0");
98 addPropValue(vcal,VCProdIdProp, productId());
99 tmpStr = mCalendar->getTimeZoneStr();
100 //qDebug("mCalendar->getTimeZoneStr() %s",tmpStr.latin1() );
101 addPropValue(vcal,VCTimeZoneProp, tmpStr.local8Bit());
102 addPropValue(vcal,VCVersionProp, _VCAL_VERSION);
103
104 // TODO STUFF
105 QPtrList<Todo> todoList = mCalendar->rawTodos();
106 QPtrListIterator<Todo> qlt(todoList);
107 for (; qlt.current(); ++qlt) {
108 vo = eventToVTodo(qlt.current());
109 addVObjectProp(vcal, vo);
110 }
111
112 // EVENT STUFF
113 QPtrList<Event> events = mCalendar->rawEvents();
114 Event *ev;
115 for(ev=events.first();ev;ev=events.next()) {
116 vo = eventToVEvent(ev);
117 addVObjectProp(vcal, vo);
118 }
119
120 writeVObjectToFile(QFile::encodeName(fileName).data() ,vcal);
121 cleanVObjects(vcal);
122 cleanStrTbl();
123
124 if (QFile::exists(fileName)) {
125 kdDebug(5800) << "No error" << endl;
126 return true;
127 } else {
128 kdDebug(5800) << "Error" << endl;
129 return false; // error
130 }
131}
132
133bool VCalFormat::fromString( Calendar *calendar, const QString &text )
134{
135 // TODO: Factor out VCalFormat::fromString()
136
137 QCString data = text.utf8();
138
139 if ( !data.size() ) return false;
140
141 VObject *vcal = Parse_MIME( data.data(), data.size());
142 if ( !vcal ) return false;
143
144 VObjectIterator i;
145 VObject *curvo;
146 initPropIterator( &i, vcal );
147
148 // we only take the first object. TODO: parse all incidences.
149 do {
150 curvo = nextVObject( &i );
151 } while ( strcmp( vObjectName( curvo ), VCEventProp ) &&
152 strcmp( vObjectName( curvo ), VCTodoProp ) );
153
154 if ( strcmp( vObjectName( curvo ), VCEventProp ) == 0 ) {
155 Event *event = VEventToEvent( curvo );
156 calendar->addEvent( event );
157 } else {
158 kdDebug(5800) << "VCalFormat::fromString(): Unknown object type." << endl;
159 deleteVObject( vcal );
160 return false;
161 }
162
163 deleteVObject( vcal );
164
165 return true;
166}
167
168QString VCalFormat::toString( Calendar *calendar )
169{
170 // TODO: Factor out VCalFormat::asString()
171
172 VObject *vcal = newVObject(VCCalProp);
173
174 addPropValue( vcal, VCProdIdProp, CalFormat::productId() );
175 QString tmpStr = mCalendar->getTimeZoneStr();
176 addPropValue( vcal, VCTimeZoneProp, tmpStr.local8Bit() );
177 addPropValue( vcal, VCVersionProp, _VCAL_VERSION );
178
179 // TODO: Use all data.
180 QPtrList<Event> events = calendar->events();
181 Event *event = events.first();
182 if ( !event ) return QString::null;
183
184 VObject *vevent = eventToVEvent( event );
185
186 addVObjectProp( vcal, vevent );
187
188 char *buf = writeMemVObject( 0, 0, vcal );
189
190 QString result( buf );
191
192 cleanVObject( vcal );
193
194 return result;
195}
196
197VObject *VCalFormat::eventToVTodo(const Todo *anEvent)
198{
199 VObject *vtodo;
200 QString tmpStr;
201 QStringList tmpStrList;
202
203 vtodo = newVObject(VCTodoProp);
204
205 // due date
206 if (anEvent->hasDueDate()) {
207 tmpStr = qDateTimeToISO(anEvent->dtDue(),
208 !anEvent->doesFloat());
209 addPropValue(vtodo, VCDueProp, tmpStr.local8Bit());
210 }
211
212 // start date
213 if (anEvent->hasStartDate()) {
214 tmpStr = qDateTimeToISO(anEvent->dtStart(),
215 !anEvent->doesFloat());
216 addPropValue(vtodo, VCDTstartProp, tmpStr.local8Bit());
217 }
218
219 // creation date
220 tmpStr = qDateTimeToISO(anEvent->created());
221 addPropValue(vtodo, VCDCreatedProp, tmpStr.local8Bit());
222
223 // unique id
224 addPropValue(vtodo, VCUniqueStringProp,
225 anEvent->uid().local8Bit());
226
227 // revision
228 tmpStr.sprintf("%i", anEvent->revision());
229 addPropValue(vtodo, VCSequenceProp, tmpStr.local8Bit());
230
231 // last modification date
232 tmpStr = qDateTimeToISO(anEvent->lastModified());
233 addPropValue(vtodo, VCLastModifiedProp, tmpStr.local8Bit());
234
235 // organizer stuff
236 tmpStr = "MAILTO:" + anEvent->organizer();
237 addPropValue(vtodo, ICOrganizerProp, tmpStr.local8Bit());
238
239 // attendees
240 if (anEvent->attendeeCount() != 0) {
241 QPtrList<Attendee> al = anEvent->attendees();
242 QPtrListIterator<Attendee> ai(al);
243 Attendee *curAttendee;
244
245 for (; ai.current(); ++ai) {
246 curAttendee = ai.current();
247 if (!curAttendee->email().isEmpty() &&
248 !curAttendee->name().isEmpty())
249 tmpStr = "MAILTO:" + curAttendee->name() + " <" +
250 curAttendee->email() + ">";
251 else if (curAttendee->name().isEmpty())
252 tmpStr = "MAILTO: " + curAttendee->email();
253 else if (curAttendee->email().isEmpty())
254 tmpStr = "MAILTO: " + curAttendee->name();
255 else if (curAttendee->name().isEmpty() &&
256 curAttendee->email().isEmpty())
257 kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl;
258 VObject *aProp = addPropValue(vtodo, VCAttendeeProp, tmpStr.local8Bit());
259 addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE");
260 addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status()));
261 }
262 }
263
264 // description BL:
265 if (!anEvent->description().isEmpty()) {
266 VObject *d = addPropValue(vtodo, VCDescriptionProp,
267 anEvent->description().local8Bit());
268 if (anEvent->description().find('\n') != -1)
269 addProp(d, VCQuotedPrintableProp);
270 }
271
272 // summary
273 if (!anEvent->summary().isEmpty())
274 addPropValue(vtodo, VCSummaryProp, anEvent->summary().local8Bit());
275
276 if (!anEvent->location().isEmpty())
277 addPropValue(vtodo, VCLocationProp, anEvent->location().local8Bit());
278
279 // completed
280 // status
281 // backward compatibility, KOrganizer used to interpret only these two values
282 addPropValue(vtodo, VCStatusProp, anEvent->isCompleted() ? "COMPLETED" :
283 "NEEDS_ACTION");
284 // completion date
285 if (anEvent->hasCompletedDate()) {
286 tmpStr = qDateTimeToISO(anEvent->completed());
287 addPropValue(vtodo, VCCompletedProp, tmpStr.local8Bit());
288 }
289
290 // priority
291 tmpStr.sprintf("%i",anEvent->priority());
292 addPropValue(vtodo, VCPriorityProp, tmpStr.local8Bit());
293
294 // related event
295 if (anEvent->relatedTo()) {
296 addPropValue(vtodo, VCRelatedToProp,
297 anEvent->relatedTo()->uid().local8Bit());
298 }
299
300 // categories
301 tmpStrList = anEvent->categories();
302 tmpStr = "";
303 QString catStr;
304 for ( QStringList::Iterator it = tmpStrList.begin();
305 it != tmpStrList.end();
306 ++it ) {
307 catStr = *it;
308 if (catStr[0] == ' ')
309 tmpStr += catStr.mid(1);
310 else
311 tmpStr += catStr;
312 // this must be a ';' character as the vCalendar specification requires!
313 // vcc.y has been hacked to translate the ';' to a ',' when the vcal is
314 // read in.
315 tmpStr += ";";
316 }
317 if (!tmpStr.isEmpty()) {
318 tmpStr.truncate(tmpStr.length()-1);
319 addPropValue(vtodo, VCCategoriesProp, tmpStr.local8Bit());
320 }
321
322 // alarm stuff
323 kdDebug(5800) << "vcalformat::eventToVTodo was called" << endl;
324 QPtrList<Alarm> alarms = anEvent->alarms();
325 Alarm* alarm;
326 for (alarm = alarms.first(); alarm; alarm = alarms.next()) {
327 if (alarm->enabled()) {
328 VObject *a = addProp(vtodo, VCDAlarmProp);
329 tmpStr = qDateTimeToISO(alarm->time());
330 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
331 addPropValue(a, VCRepeatCountProp, "1");
332 addPropValue(a, VCDisplayStringProp, "beep!");
333 if (alarm->type() == Alarm::Audio) {
334 a = addProp(vtodo, VCAAlarmProp);
335 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
336 addPropValue(a, VCRepeatCountProp, "1");
337 addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile()));
338 }
339 else if (alarm->type() == Alarm::Procedure) {
340 a = addProp(vtodo, VCPAlarmProp);
341 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
342 addPropValue(a, VCRepeatCountProp, "1");
343 addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile()));
344 }
345 }
346 }
347
348 if (anEvent->pilotId()) {
349 // pilot sync stuff
350 tmpStr.sprintf("%i",anEvent->pilotId());
351 addPropValue(vtodo, KPilotIdProp, tmpStr.local8Bit());
352 tmpStr.sprintf("%i",anEvent->syncStatus());
353 addPropValue(vtodo, KPilotStatusProp, tmpStr.local8Bit());
354 }
355
356 return vtodo;
357}
358
359VObject* VCalFormat::eventToVEvent(const Event *anEvent)
360{
361 VObject *vevent;
362 QString tmpStr;
363 QStringList tmpStrList;
364
365 vevent = newVObject(VCEventProp);
366
367 // start and end time
368 tmpStr = qDateTimeToISO(anEvent->dtStart(),
369 !anEvent->doesFloat());
370 addPropValue(vevent, VCDTstartProp, tmpStr.local8Bit());
371
372 // events that have time associated but take up no time should
373 // not have both DTSTART and DTEND.
374 if (anEvent->dtStart() != anEvent->dtEnd()) {
375 tmpStr = qDateTimeToISO(anEvent->dtEnd(),
376 !anEvent->doesFloat());
377 addPropValue(vevent, VCDTendProp, tmpStr.local8Bit());
378 }
379
380 // creation date
381 tmpStr = qDateTimeToISO(anEvent->created());
382 addPropValue(vevent, VCDCreatedProp, tmpStr.local8Bit());
383
384 // unique id
385 addPropValue(vevent, VCUniqueStringProp,
386 anEvent->uid().local8Bit());
387
388 // revision
389 tmpStr.sprintf("%i", anEvent->revision());
390 addPropValue(vevent, VCSequenceProp, tmpStr.local8Bit());
391
392 // last modification date
393 tmpStr = qDateTimeToISO(anEvent->lastModified());
394 addPropValue(vevent, VCLastModifiedProp, tmpStr.local8Bit());
395
396 // attendee and organizer stuff
397 tmpStr = "MAILTO:" + anEvent->organizer();
398 addPropValue(vevent, ICOrganizerProp, tmpStr.local8Bit());
399
400 if (anEvent->attendeeCount() != 0) {
401 QPtrList<Attendee> al = anEvent->attendees();
402 QPtrListIterator<Attendee> ai(al);
403 Attendee *curAttendee;
404
405 // TODO: Put this functionality into Attendee class
406 for (; ai.current(); ++ai) {
407 curAttendee = ai.current();
408 if (!curAttendee->email().isEmpty() &&
409 !curAttendee->name().isEmpty())
410 tmpStr = "MAILTO:" + curAttendee->name() + " <" +
411 curAttendee->email() + ">";
412 else if (curAttendee->name().isEmpty())
413 tmpStr = "MAILTO: " + curAttendee->email();
414 else if (curAttendee->email().isEmpty())
415 tmpStr = "MAILTO: " + curAttendee->name();
416 else if (curAttendee->name().isEmpty() &&
417 curAttendee->email().isEmpty())
418 kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl;
419 VObject *aProp = addPropValue(vevent, VCAttendeeProp, tmpStr.local8Bit());
420 addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE");;
421 addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status()));
422 }
423 }
424
425 // recurrence rule stuff
426 if (anEvent->recurrence()->doesRecur()) {
427 // some more variables
428 QPtrList<Recurrence::rMonthPos> tmpPositions;
429 QPtrList<int> tmpDays;
430 int *tmpDay;
431 Recurrence::rMonthPos *tmpPos;
432 QString tmpStr2;
433 int i;
434
435 switch(anEvent->recurrence()->doesRecur()) {
436 case Recurrence::rDaily:
437 tmpStr.sprintf("D%i ",anEvent->recurrence()->frequency());
438// if (anEvent->rDuration > 0)
439 //tmpStr += "#";
440 break;
441 case Recurrence::rWeekly:
442 tmpStr.sprintf("W%i ",anEvent->recurrence()->frequency());
443 for (i = 0; i < 7; i++) {
444 if (anEvent->recurrence()->days().testBit(i))
445 tmpStr += dayFromNum(i);
446 }
447 break;
448 case Recurrence::rMonthlyPos:
449 tmpStr.sprintf("MP%i ", anEvent->recurrence()->frequency());
450 // write out all rMonthPos's
451 tmpPositions = anEvent->recurrence()->monthPositions();
452 for (tmpPos = tmpPositions.first();
453 tmpPos;
454 tmpPos = tmpPositions.next()) {
455
456 tmpStr2.sprintf("%i", tmpPos->rPos);
457 if (tmpPos->negative)
458 tmpStr2 += "- ";
459 else
460 tmpStr2 += "+ ";
461 tmpStr += tmpStr2;
462 for (i = 0; i < 7; i++) {
463 if (tmpPos->rDays.testBit(i))
464 tmpStr += dayFromNum(i);
465 }
466 } // loop for all rMonthPos's
467 break;
468 case Recurrence::rMonthlyDay:
469 tmpStr.sprintf("MD%i ", anEvent->recurrence()->frequency());
470 // write out all rMonthDays;
471 tmpDays = anEvent->recurrence()->monthDays();
472 for (tmpDay = tmpDays.first();
473 tmpDay;
474 tmpDay = tmpDays.next()) {
475 tmpStr2.sprintf("%i ", *tmpDay);
476 tmpStr += tmpStr2;
477 }
478 break;
479 case Recurrence::rYearlyMonth:
480 tmpStr.sprintf("YM%i ", anEvent->recurrence()->frequency());
481 // write out all the rYearNums;
482 tmpDays = anEvent->recurrence()->yearNums();
483 for (tmpDay = tmpDays.first();
484 tmpDay;
485 tmpDay = tmpDays.next()) {
486 tmpStr2.sprintf("%i ", *tmpDay);
487 tmpStr += tmpStr2;
488 }
489 break;
490 case Recurrence::rYearlyDay:
491 tmpStr.sprintf("YD%i ", anEvent->recurrence()->frequency());
492 // write out all the rYearNums;
493 tmpDays = anEvent->recurrence()->yearNums();
494 for (tmpDay = tmpDays.first();
495 tmpDay;
496 tmpDay = tmpDays.next()) {
497 tmpStr2.sprintf("%i ", *tmpDay);
498 tmpStr += tmpStr2;
499 }
500 break;
501 default:
502 kdDebug(5800) << "ERROR, it should never get here in eventToVEvent!" << endl;
503 break;
504 } // switch
505
506 if (anEvent->recurrence()->duration() > 0) {
507 tmpStr2.sprintf("#%i",anEvent->recurrence()->duration());
508 tmpStr += tmpStr2;
509 } else if (anEvent->recurrence()->duration() == -1) {
510 tmpStr += "#0"; // defined as repeat forever
511 } else {
512 tmpStr += qDateTimeToISO(anEvent->recurrence()->endDate(), FALSE);
513 }
514 addPropValue(vevent,VCRRuleProp, tmpStr.local8Bit());
515
516 } // event repeats
517
518 // exceptions to recurrence
519 DateList dateList = anEvent->exDates();
520 DateList::ConstIterator it;
521 QString tmpStr2;
522
523 for (it = dateList.begin(); it != dateList.end(); ++it) {
524 tmpStr = qDateToISO(*it) + ";";
525 tmpStr2 += tmpStr;
526 }
527 if (!tmpStr2.isEmpty()) {
528 tmpStr2.truncate(tmpStr2.length()-1);
529 addPropValue(vevent, VCExDateProp, tmpStr2.local8Bit());
530 }
531
532 // description
533 if (!anEvent->description().isEmpty()) {
534 VObject *d = addPropValue(vevent, VCDescriptionProp,
535 anEvent->description().local8Bit());
536 if (anEvent->description().find('\n') != -1)
537 addProp(d, VCQuotedPrintableProp);
538 }
539
540 // summary
541 if (!anEvent->summary().isEmpty())
542 addPropValue(vevent, VCSummaryProp, anEvent->summary().local8Bit());
543
544 if (!anEvent->location().isEmpty())
545 addPropValue(vevent, VCLocationProp, anEvent->location().local8Bit());
546
547 // status
548// TODO: define Event status
549// addPropValue(vevent, VCStatusProp, anEvent->statusStr().local8Bit());
550
551 // secrecy
552 const char *text = 0;
553 switch (anEvent->secrecy()) {
554 case Incidence::SecrecyPublic:
555 text = "PUBLIC";
556 break;
557 case Incidence::SecrecyPrivate:
558 text = "PRIVATE";
559 break;
560 case Incidence::SecrecyConfidential:
561 text = "CONFIDENTIAL";
562 break;
563 }
564 if (text) {
565 addPropValue(vevent, VCClassProp, text);
566 }
567
568 // categories
569 tmpStrList = anEvent->categories();
570 tmpStr = "";
571 QString catStr;
572 for ( QStringList::Iterator it = tmpStrList.begin();
573 it != tmpStrList.end();
574 ++it ) {
575 catStr = *it;
576 if (catStr[0] == ' ')
577 tmpStr += catStr.mid(1);
578 else
579 tmpStr += catStr;
580 // this must be a ';' character as the vCalendar specification requires!
581 // vcc.y has been hacked to translate the ';' to a ',' when the vcal is
582 // read in.
583 tmpStr += ";";
584 }
585 if (!tmpStr.isEmpty()) {
586 tmpStr.truncate(tmpStr.length()-1);
587 addPropValue(vevent, VCCategoriesProp, tmpStr.local8Bit());
588 }
589
590 // attachments
591 // TODO: handle binary attachments!
592 QPtrList<Attachment> attachments = anEvent->attachments();
593 for ( Attachment *at = attachments.first(); at; at = attachments.next() )
594 addPropValue(vevent, VCAttachProp, at->uri().local8Bit());
595
596 // resources
597 tmpStrList = anEvent->resources();
598 tmpStr = tmpStrList.join(";");
599 if (!tmpStr.isEmpty())
600 addPropValue(vevent, VCResourcesProp, tmpStr.local8Bit());
601
602 // alarm stuff
603 QPtrList<Alarm> alarms = anEvent->alarms();
604 Alarm* alarm;
605 for (alarm = alarms.first(); alarm; alarm = alarms.next()) {
606 if (alarm->enabled()) {
607 VObject *a = addProp(vevent, VCDAlarmProp);
608 tmpStr = qDateTimeToISO(alarm->time());
609 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
610 addPropValue(a, VCRepeatCountProp, "1");
611 addPropValue(a, VCDisplayStringProp, "beep!");
612 if (alarm->type() == Alarm::Audio) {
613 a = addProp(vevent, VCAAlarmProp);
614 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
615 addPropValue(a, VCRepeatCountProp, "1");
616 addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile()));
617 }
618 if (alarm->type() == Alarm::Procedure) {
619 a = addProp(vevent, VCPAlarmProp);
620 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
621 addPropValue(a, VCRepeatCountProp, "1");
622 addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile()));
623 }
624 }
625 }
626
627 // priority
628 tmpStr.sprintf("%i",anEvent->priority());
629 addPropValue(vevent, VCPriorityProp, tmpStr.local8Bit());
630
631 // transparency
632 tmpStr.sprintf("%i",anEvent->transparency());
633 addPropValue(vevent, VCTranspProp, tmpStr.local8Bit());
634
635 // related event
636 if (anEvent->relatedTo()) {
637 addPropValue(vevent, VCRelatedToProp,
638 anEvent->relatedTo()->uid().local8Bit());
639 }
640
641 if (anEvent->pilotId()) {
642 // pilot sync stuff
643 tmpStr.sprintf("%i",anEvent->pilotId());
644 addPropValue(vevent, KPilotIdProp, tmpStr.local8Bit());
645 tmpStr.sprintf("%i",anEvent->syncStatus());
646 addPropValue(vevent, KPilotStatusProp, tmpStr.local8Bit());
647 }
648
649 return vevent;
650}
651
652Todo *VCalFormat::VTodoToEvent(VObject *vtodo)
653{
654 VObject *vo;
655 VObjectIterator voi;
656 char *s;
657
658 Todo *anEvent = new Todo;
659
660 // creation date
661 if ((vo = isAPropertyOf(vtodo, VCDCreatedProp)) != 0) {
662 anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
663 deleteStr(s);
664 }
665
666 // unique id
667 vo = isAPropertyOf(vtodo, VCUniqueStringProp);
668 // while the UID property is preferred, it is not required. We'll use the
669 // default Event UID if none is given.
670 if (vo) {
671 anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo)));
672 deleteStr(s);
673 }
674
675 // last modification date
676 if ((vo = isAPropertyOf(vtodo, VCLastModifiedProp)) != 0) {
677 anEvent->setLastModified(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
678 deleteStr(s);
679 }
680 else
681 anEvent->setLastModified(QDateTime(QDate::currentDate(),
682 QTime::currentTime()));
683
684 // organizer
685 // if our extension property for the event's ORGANIZER exists, add it.
686 if ((vo = isAPropertyOf(vtodo, ICOrganizerProp)) != 0) {
687 anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo)));
688 deleteStr(s);
689 } else {
690 anEvent->setOrganizer(mCalendar->getEmail());
691 }
692
693 // attendees.
694 initPropIterator(&voi, vtodo);
695 while (moreIteration(&voi)) {
696 vo = nextVObject(&voi);
697 if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) {
698 Attendee *a;
699 VObject *vp;
700 s = fakeCString(vObjectUStringZValue(vo));
701 QString tmpStr = QString::fromLocal8Bit(s);
702 deleteStr(s);
703 tmpStr = tmpStr.simplifyWhiteSpace();
704 int emailPos1, emailPos2;
705 if ((emailPos1 = tmpStr.find('<')) > 0) {
706 // both email address and name
707 emailPos2 = tmpStr.findRev('>');
708 a = new Attendee(tmpStr.left(emailPos1 - 1),
709 tmpStr.mid(emailPos1 + 1,
710 emailPos2 - (emailPos1 + 1)));
711 } else if (tmpStr.find('@') > 0) {
712 // just an email address
713 a = new Attendee(0, tmpStr);
714 } else {
715 // just a name
716 QString email = tmpStr.replace( QRegExp(" "), "." );
717 a = new Attendee(tmpStr,email);
718 }
719
720 // is there an RSVP property?
721 if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0)
722 a->setRSVP(vObjectStringZValue(vp));
723 // is there a status property?
724 if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0)
725 a->setStatus(readStatus(vObjectStringZValue(vp)));
726 // add the attendee
727 anEvent->addAttendee(a);
728 }
729 }
730
731 // description for todo
732 if ((vo = isAPropertyOf(vtodo, VCDescriptionProp)) != 0) {
733 s = fakeCString(vObjectUStringZValue(vo));
734 anEvent->setDescription(QString::fromLocal8Bit(s));
735 deleteStr(s);
736 }
737
738 // summary
739 if ((vo = isAPropertyOf(vtodo, VCSummaryProp))) {
740 s = fakeCString(vObjectUStringZValue(vo));
741 anEvent->setSummary(QString::fromLocal8Bit(s));
742 deleteStr(s);
743 }
744 if ((vo = isAPropertyOf(vtodo, VCLocationProp))) {
745 s = fakeCString(vObjectUStringZValue(vo));
746 anEvent->setLocation(QString::fromLocal8Bit(s));
747 deleteStr(s);
748 }
749
750
751 // completed
752 // was: status
753 if ((vo = isAPropertyOf(vtodo, VCStatusProp)) != 0) {
754 s = fakeCString(vObjectUStringZValue(vo));
755 if (strcmp(s,"COMPLETED") == 0) {
756 anEvent->setCompleted(true);
757 } else {
758 anEvent->setCompleted(false);
759 }
760 deleteStr(s);
761 }
762 else
763 anEvent->setCompleted(false);
764
765 // completion date
766 if ((vo = isAPropertyOf(vtodo, VCCompletedProp)) != 0) {
767 anEvent->setCompleted(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
768 deleteStr(s);
769 }
770
771 // priority
772 if ((vo = isAPropertyOf(vtodo, VCPriorityProp))) {
773 anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo))));
774 deleteStr(s);
775 }
776
777 // due date
778 if ((vo = isAPropertyOf(vtodo, VCDueProp)) != 0) {
779 anEvent->setDtDue(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
780 deleteStr(s);
781 anEvent->setHasDueDate(true);
782 } else {
783 anEvent->setHasDueDate(false);
784 }
785
786 // start time
787 if ((vo = isAPropertyOf(vtodo, VCDTstartProp)) != 0) {
788 anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
789 // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl;
790 deleteStr(s);
791 anEvent->setHasStartDate(true);
792 } else {
793 anEvent->setHasStartDate(false);
794 }
795
796 /* alarm stuff */
797 //kdDebug(5800) << "vcalformat::VTodoToEvent called" << endl;
798 if ((vo = isAPropertyOf(vtodo, VCDAlarmProp))) {
799 Alarm* alarm = anEvent->newAlarm();
800 VObject *a;
801 if ((a = isAPropertyOf(vo, VCRunTimeProp))) {
802 alarm->setTime(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(a))));
803 deleteStr(s);
804 }
805 alarm->setEnabled(true);
806 if ((vo = isAPropertyOf(vtodo, VCPAlarmProp))) {
807 if ((a = isAPropertyOf(vo, VCProcedureNameProp))) {
808 s = fakeCString(vObjectUStringZValue(a));
809 alarm->setProcedureAlarm(QFile::decodeName(s));
810 deleteStr(s);
811 }
812 }
813 if ((vo = isAPropertyOf(vtodo, VCAAlarmProp))) {
814 if ((a = isAPropertyOf(vo, VCAudioContentProp))) {
815 s = fakeCString(vObjectUStringZValue(a));
816 alarm->setAudioAlarm(QFile::decodeName(s));
817 deleteStr(s);
818 }
819 }
820 }
821
822 // related todo
823 if ((vo = isAPropertyOf(vtodo, VCRelatedToProp)) != 0) {
824 anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo)));
825 deleteStr(s);
826 mTodosRelate.append(anEvent);
827 }
828
829 // categories
830 QStringList tmpStrList;
831 int index1 = 0;
832 int index2 = 0;
833 if ((vo = isAPropertyOf(vtodo, VCCategoriesProp)) != 0) {
834 s = fakeCString(vObjectUStringZValue(vo));
835 QString categories = QString::fromLocal8Bit(s);
836 deleteStr(s);
837 //const char* category;
838 QString category;
839 while ((index2 = categories.find(',', index1)) != -1) {
840 //category = (const char *) categories.mid(index1, (index2 - index1));
841 category = categories.mid(index1, (index2 - index1));
842 tmpStrList.append(category);
843 index1 = index2+1;
844 }
845 // get last category
846 category = categories.mid(index1, (categories.length()-index1));
847 tmpStrList.append(category);
848 anEvent->setCategories(tmpStrList);
849 }
850
851 /* PILOT SYNC STUFF */
852 if ((vo = isAPropertyOf(vtodo, KPilotIdProp))) {
853 anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo))));
854 deleteStr(s);
855 }
856 else
857 anEvent->setPilotId(0);
858
859 if ((vo = isAPropertyOf(vtodo, KPilotStatusProp))) {
860 anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo))));
861 deleteStr(s);
862 }
863 else
864 anEvent->setSyncStatus(Event::SYNCMOD);
865
866 return anEvent;
867}
868
869Event* VCalFormat::VEventToEvent(VObject *vevent)
870{
871 VObject *vo;
872 VObjectIterator voi;
873 char *s;
874
875 Event *anEvent = new Event;
876
877 // creation date
878 if ((vo = isAPropertyOf(vevent, VCDCreatedProp)) != 0) {
879 anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
880 deleteStr(s);
881 }
882
883 // unique id
884 vo = isAPropertyOf(vevent, VCUniqueStringProp);
885 // while the UID property is preferred, it is not required. We'll use the
886 // default Event UID if none is given.
887 if (vo) {
888 anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo)));
889 deleteStr(s);
890 }
891
892 // revision
893 // again NSCAL doesn't give us much to work with, so we improvise...
894 if ((vo = isAPropertyOf(vevent, VCSequenceProp)) != 0) {
895 anEvent->setRevision(atoi(s = fakeCString(vObjectUStringZValue(vo))));
896 deleteStr(s);
897 }
898 else
899 anEvent->setRevision(0);
900
901 // last modification date
902 if ((vo = isAPropertyOf(vevent, VCLastModifiedProp)) != 0) {
903 anEvent->setLastModified(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
904 deleteStr(s);
905 }
906 else
907 anEvent->setLastModified(QDateTime(QDate::currentDate(),
908 QTime::currentTime()));
909
910 // organizer
911 // if our extension property for the event's ORGANIZER exists, add it.
912 if ((vo = isAPropertyOf(vevent, ICOrganizerProp)) != 0) {
913 anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo)));
914 deleteStr(s);
915 } else {
916 anEvent->setOrganizer(mCalendar->getEmail());
917 }
918
919 // deal with attendees.
920 initPropIterator(&voi, vevent);
921 while (moreIteration(&voi)) {
922 vo = nextVObject(&voi);
923 if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) {
924 Attendee *a;
925 VObject *vp;
926 s = fakeCString(vObjectUStringZValue(vo));
927 QString tmpStr = QString::fromLocal8Bit(s);
928 deleteStr(s);
929 tmpStr = tmpStr.simplifyWhiteSpace();
930 int emailPos1, emailPos2;
931 if ((emailPos1 = tmpStr.find('<')) > 0) {
932 // both email address and name
933 emailPos2 = tmpStr.findRev('>');
934 a = new Attendee(tmpStr.left(emailPos1 - 1),
935 tmpStr.mid(emailPos1 + 1,
936 emailPos2 - (emailPos1 + 1)));
937 } else if (tmpStr.find('@') > 0) {
938 // just an email address
939 a = new Attendee(0, tmpStr);
940 } else {
941 // just a name
942 QString email = tmpStr.replace( QRegExp(" "), "." );
943 a = new Attendee(tmpStr,email);
944 }
945
946 // is there an RSVP property?
947 if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0)
948 a->setRSVP(vObjectStringZValue(vp));
949 // is there a status property?
950 if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0)
951 a->setStatus(readStatus(vObjectStringZValue(vp)));
952 // add the attendee
953 anEvent->addAttendee(a);
954 }
955 }
956
957 // This isn't strictly true. An event that doesn't have a start time
958 // or an end time doesn't "float", it has an anchor in time but it doesn't
959 // "take up" any time.
960 /*if ((isAPropertyOf(vevent, VCDTstartProp) == 0) ||
961 (isAPropertyOf(vevent, VCDTendProp) == 0)) {
962 anEvent->setFloats(TRUE);
963 } else {
964 }*/
965
966 anEvent->setFloats(FALSE);
967
968 // start time
969 if ((vo = isAPropertyOf(vevent, VCDTstartProp)) != 0) {
970 anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
971 // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl;
972 deleteStr(s);
973 if (anEvent->dtStart().time().isNull())
974 anEvent->setFloats(TRUE);
975 }
976
977 // stop time
978 if ((vo = isAPropertyOf(vevent, VCDTendProp)) != 0) {
979 anEvent->setDtEnd(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
980 deleteStr(s);
981 if (anEvent->dtEnd().time().isNull())
982 anEvent->setFloats(TRUE);
983 }
984
985 // at this point, there should be at least a start or end time.
986 // fix up for events that take up no time but have a time associated
987 if (!(vo = isAPropertyOf(vevent, VCDTstartProp)))
988 anEvent->setDtStart(anEvent->dtEnd());
989 if (!(vo = isAPropertyOf(vevent, VCDTendProp)))
990 anEvent->setDtEnd(anEvent->dtStart());
991
992 ///////////////////////////////////////////////////////////////////////////
993
994 // repeat stuff
995 if ((vo = isAPropertyOf(vevent, VCRRuleProp)) != 0) {
996 QString tmpStr = (s = fakeCString(vObjectUStringZValue(vo)));
997 deleteStr(s);
998 tmpStr.simplifyWhiteSpace();
999 tmpStr = tmpStr.upper();
1000
1001 /********************************* DAILY ******************************/
1002 if (tmpStr.left(1) == "D") {
1003 int index = tmpStr.find(' ');
1004 int rFreq = tmpStr.mid(1, (index-1)).toInt();
1005 index = tmpStr.findRev(' ') + 1; // advance to last field
1006 if (tmpStr.mid(index,1) == "#") index++;
1007 if (tmpStr.find('T', index) != -1) {
1008 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1009 anEvent->recurrence()->setDaily(rFreq, rEndDate);
1010 } else {
1011 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1012 if (rDuration == 0) // VEvents set this to 0 forever, we use -1
1013 anEvent->recurrence()->setDaily(rFreq, -1);
1014 else
1015 anEvent->recurrence()->setDaily(rFreq, rDuration);
1016 }
1017 }
1018 /********************************* WEEKLY ******************************/
1019 else if (tmpStr.left(1) == "W") {
1020 int index = tmpStr.find(' ');
1021 int last = tmpStr.findRev(' ') + 1;
1022 int rFreq = tmpStr.mid(1, (index-1)).toInt();
1023 index += 1; // advance to beginning of stuff after freq
1024 QBitArray qba(7);
1025 QString dayStr;
1026 if( index == last ) {
1027 // e.g. W1 #0
1028 qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1);
1029 }
1030 else {
1031 // e.g. W1 SU #0
1032 while (index < last) {
1033 dayStr = tmpStr.mid(index, 3);
1034 int dayNum = numFromDay(dayStr);
1035 qba.setBit(dayNum);
1036 index += 3; // advance to next day, or possibly "#"
1037 }
1038 }
1039 index = last; if (tmpStr.mid(index,1) == "#") index++;
1040 if (tmpStr.find('T', index) != -1) {
1041 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1042 anEvent->recurrence()->setWeekly(rFreq, qba, rEndDate);
1043 } else {
1044 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1045 if (rDuration == 0)
1046 anEvent->recurrence()->setWeekly(rFreq, qba, -1);
1047 else
1048 anEvent->recurrence()->setWeekly(rFreq, qba, rDuration);
1049 }
1050 }
1051 /**************************** MONTHLY-BY-POS ***************************/
1052 else if (tmpStr.left(2) == "MP") {
1053 int index = tmpStr.find(' ');
1054 int last = tmpStr.findRev(' ') + 1;
1055 int rFreq = tmpStr.mid(2, (index-1)).toInt();
1056 index += 1; // advance to beginning of stuff after freq
1057 QBitArray qba(7);
1058 short tmpPos;
1059 if( index == last ) {
1060 // e.g. MP1 #0
1061 tmpPos = anEvent->dtStart().date().day()/7 + 1;
1062 if( tmpPos == 5 )
1063 tmpPos = -1;
1064 qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1);
1065 anEvent->recurrence()->addMonthlyPos(tmpPos, qba);
1066 }
1067 else {
1068 // e.g. MP1 1+ SU #0
1069 while (index < last) {
1070 tmpPos = tmpStr.mid(index,1).toShort();
1071 index += 1;
1072 if (tmpStr.mid(index,1) == "-")
1073 // convert tmpPos to negative
1074 tmpPos = 0 - tmpPos;
1075 index += 2; // advance to day(s)
1076 while (numFromDay(tmpStr.mid(index,3)) >= 0) {
1077 int dayNum = numFromDay(tmpStr.mid(index,3));
1078 qba.setBit(dayNum);
1079 index += 3; // advance to next day, or possibly pos or "#"
1080 }
1081 anEvent->recurrence()->addMonthlyPos(tmpPos, qba);
1082 qba.detach();
1083 qba.fill(FALSE); // clear out
1084 } // while != "#"
1085 }
1086 index = last; if (tmpStr.mid(index,1) == "#") index++;
1087 if (tmpStr.find('T', index) != -1) {
1088 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length() -
1089 index))).date();
1090 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rEndDate);
1091 } else {
1092 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1093 if (rDuration == 0)
1094 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, -1);
1095 else
1096 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rDuration);
1097 }
1098 }
1099
1100 /**************************** MONTHLY-BY-DAY ***************************/
1101 else if (tmpStr.left(2) == "MD") {
1102 int index = tmpStr.find(' ');
1103 int last = tmpStr.findRev(' ') + 1;
1104 int rFreq = tmpStr.mid(2, (index-1)).toInt();
1105 index += 1;
1106 short tmpDay;
1107 if( index == last ) {
1108 // e.g. MD1 #0
1109 tmpDay = anEvent->dtStart().date().day();
1110 anEvent->recurrence()->addMonthlyDay(tmpDay);
1111 }
1112 else {
1113 // e.g. MD1 3 #0
1114 while (index < last) {
1115 int index2 = tmpStr.find(' ', index);
1116 tmpDay = tmpStr.mid(index, (index2-index)).toShort();
1117 index = index2-1;
1118 if (tmpStr.mid(index, 1) == "-")
1119 tmpDay = 0 - tmpDay;
1120 index += 2; // advance the index;
1121 anEvent->recurrence()->addMonthlyDay(tmpDay);
1122 } // while != #
1123 }
1124 index = last; if (tmpStr.mid(index,1) == "#") index++;
1125 if (tmpStr.find('T', index) != -1) {
1126 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1127 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rEndDate);
1128 } else {
1129 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1130 if (rDuration == 0)
1131 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, -1);
1132 else
1133 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rDuration);
1134 }
1135 }
1136
1137 /*********************** YEARLY-BY-MONTH *******************************/
1138 else if (tmpStr.left(2) == "YM") {
1139 int index = tmpStr.find(' ');
1140 int last = tmpStr.findRev(' ') + 1;
1141 int rFreq = tmpStr.mid(2, (index-1)).toInt();
1142 index += 1;
1143 short tmpMonth;
1144 if( index == last ) {
1145 // e.g. YM1 #0
1146 tmpMonth = anEvent->dtStart().date().month();
1147 anEvent->recurrence()->addYearlyNum(tmpMonth);
1148 }
1149 else {
1150 // e.g. YM1 3 #0
1151 while (index < last) {
1152 int index2 = tmpStr.find(' ', index);
1153 tmpMonth = tmpStr.mid(index, (index2-index)).toShort();
1154 index = index2+1;
1155 anEvent->recurrence()->addYearlyNum(tmpMonth);
1156 } // while != #
1157 }
1158 index = last; if (tmpStr.mid(index,1) == "#") index++;
1159 if (tmpStr.find('T', index) != -1) {
1160 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1161 anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rEndDate);
1162 } else {
1163 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1164 if (rDuration == 0)
1165 anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, -1);
1166 else
1167 anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rDuration);
1168 }
1169 }
1170
1171 /*********************** YEARLY-BY-DAY *********************************/
1172 else if (tmpStr.left(2) == "YD") {
1173 int index = tmpStr.find(' ');
1174 int last = tmpStr.findRev(' ') + 1;
1175 int rFreq = tmpStr.mid(2, (index-1)).toInt();
1176 index += 1;
1177 short tmpDay;
1178 if( index == last ) {
1179 // e.g. YD1 #0
1180 tmpDay = anEvent->dtStart().date().dayOfYear();
1181 anEvent->recurrence()->addYearlyNum(tmpDay);
1182 }
1183 else {
1184 // e.g. YD1 123 #0
1185 while (index < last) {
1186 int index2 = tmpStr.find(' ', index);
1187 tmpDay = tmpStr.mid(index, (index2-index)).toShort();
1188 index = index2+1;
1189 anEvent->recurrence()->addYearlyNum(tmpDay);
1190 } // while != #
1191 }
1192 index = last; if (tmpStr.mid(index,1) == "#") index++;
1193 if (tmpStr.find('T', index) != -1) {
1194 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1195 anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rEndDate);
1196 } else {
1197 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1198 if (rDuration == 0)
1199 anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, -1);
1200 else
1201 anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rDuration);
1202 }
1203 } else {
1204 kdDebug(5800) << "we don't understand this type of recurrence!" << endl;
1205 } // if
1206 } // repeats
1207
1208
1209 // recurrence exceptions
1210 if ((vo = isAPropertyOf(vevent, VCExDateProp)) != 0) {
1211 s = fakeCString(vObjectUStringZValue(vo));
1212 QStringList exDates = QStringList::split(",",s);
1213 QStringList::ConstIterator it;
1214 for(it = exDates.begin(); it != exDates.end(); ++it ) {
1215 anEvent->addExDate(ISOToQDate(*it));
1216 }
1217 deleteStr(s);
1218 }
1219
1220 // summary
1221 if ((vo = isAPropertyOf(vevent, VCSummaryProp))) {
1222 s = fakeCString(vObjectUStringZValue(vo));
1223 anEvent->setSummary(QString::fromLocal8Bit(s));
1224 deleteStr(s);
1225 }
1226 if ((vo = isAPropertyOf(vevent, VCLocationProp))) {
1227 s = fakeCString(vObjectUStringZValue(vo));
1228 anEvent->setLocation(QString::fromLocal8Bit(s));
1229 deleteStr(s);
1230 }
1231
1232 // description
1233 if ((vo = isAPropertyOf(vevent, VCDescriptionProp)) != 0) {
1234 s = fakeCString(vObjectUStringZValue(vo));
1235 if (!anEvent->description().isEmpty()) {
1236 anEvent->setDescription(anEvent->description() + "\n" +
1237 QString::fromLocal8Bit(s));
1238 } else {
1239 anEvent->setDescription(QString::fromLocal8Bit(s));
1240 }
1241 deleteStr(s);
1242 }
1243
1244 // some stupid vCal exporters ignore the standard and use Description
1245 // instead of Summary for the default field. Correct for this.
1246 if (anEvent->summary().isEmpty() &&
1247 !(anEvent->description().isEmpty())) {
1248 QString tmpStr = anEvent->description().simplifyWhiteSpace();
1249 anEvent->setDescription("");
1250 anEvent->setSummary(tmpStr);
1251 }
1252
1253#if 0
1254 // status
1255 if ((vo = isAPropertyOf(vevent, VCStatusProp)) != 0) {
1256 QString tmpStr(s = fakeCString(vObjectUStringZValue(vo)));
1257 deleteStr(s);
1258// TODO: Define Event status
1259// anEvent->setStatus(tmpStr);
1260 }
1261 else
1262// anEvent->setStatus("NEEDS ACTION");
1263#endif
1264
1265 // secrecy
1266 int secrecy = Incidence::SecrecyPublic;
1267 if ((vo = isAPropertyOf(vevent, VCClassProp)) != 0) {
1268 s = fakeCString(vObjectUStringZValue(vo));
1269 if (strcmp(s,"PRIVATE") == 0) {
1270 secrecy = Incidence::SecrecyPrivate;
1271 } else if (strcmp(s,"CONFIDENTIAL") == 0) {
1272 secrecy = Incidence::SecrecyConfidential;
1273 }
1274 deleteStr(s);
1275 }
1276 anEvent->setSecrecy(secrecy);
1277
1278 // categories
1279 QStringList tmpStrList;
1280 int index1 = 0;
1281 int index2 = 0;
1282 if ((vo = isAPropertyOf(vevent, VCCategoriesProp)) != 0) {
1283 s = fakeCString(vObjectUStringZValue(vo));
1284 QString categories = QString::fromLocal8Bit(s);
1285 deleteStr(s);
1286 //const char* category;
1287 QString category;
1288 while ((index2 = categories.find(',', index1)) != -1) {
1289 //category = (const char *) categories.mid(index1, (index2 - index1));
1290 category = categories.mid(index1, (index2 - index1));
1291 tmpStrList.append(category);
1292 index1 = index2+1;
1293 }
1294 // get last category
1295 category = categories.mid(index1, (categories.length()-index1));
1296 tmpStrList.append(category);
1297 anEvent->setCategories(tmpStrList);
1298 }
1299
1300 // attachments
1301 tmpStrList.clear();
1302 initPropIterator(&voi, vevent);
1303 while (moreIteration(&voi)) {
1304 vo = nextVObject(&voi);
1305 if (strcmp(vObjectName(vo), VCAttachProp) == 0) {
1306 s = fakeCString(vObjectUStringZValue(vo));
1307 anEvent->addAttachment(new Attachment(QString(s)));
1308 deleteStr(s);
1309 }
1310 }
1311
1312 // resources
1313 if ((vo = isAPropertyOf(vevent, VCResourcesProp)) != 0) {
1314 QString resources = (s = fakeCString(vObjectUStringZValue(vo)));
1315 deleteStr(s);
1316 tmpStrList.clear();
1317 index1 = 0;
1318 index2 = 0;
1319 QString resource;
1320 while ((index2 = resources.find(';', index1)) != -1) {
1321 resource = resources.mid(index1, (index2 - index1));
1322 tmpStrList.append(resource);
1323 index1 = index2;
1324 }
1325 anEvent->setResources(tmpStrList);
1326 }
1327
1328 /* alarm stuff */
1329 if ((vo = isAPropertyOf(vevent, VCDAlarmProp))) {
1330 Alarm* alarm = anEvent->newAlarm();
1331 VObject *a;
1332 if ((a = isAPropertyOf(vo, VCRunTimeProp))) {
1333 alarm->setTime(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(a))));
1334 deleteStr(s);
1335 }
1336 alarm->setEnabled(true);
1337 if ((vo = isAPropertyOf(vevent, VCPAlarmProp))) {
1338 if ((a = isAPropertyOf(vo, VCProcedureNameProp))) {
1339 s = fakeCString(vObjectUStringZValue(a));
1340 alarm->setProcedureAlarm(QFile::decodeName(s));
1341 deleteStr(s);
1342 }
1343 }
1344 if ((vo = isAPropertyOf(vevent, VCAAlarmProp))) {
1345 if ((a = isAPropertyOf(vo, VCAudioContentProp))) {
1346 s = fakeCString(vObjectUStringZValue(a));
1347 alarm->setAudioAlarm(QFile::decodeName(s));
1348 deleteStr(s);
1349 }
1350 }
1351 }
1352
1353 // priority
1354 if ((vo = isAPropertyOf(vevent, VCPriorityProp))) {
1355 anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo))));
1356 deleteStr(s);
1357 }
1358
1359 // transparency
1360 if ((vo = isAPropertyOf(vevent, VCTranspProp)) != 0) {
1361 int i = atoi(s = fakeCString(vObjectUStringZValue(vo)));
1362 anEvent->setTransparency( i == 1 ? Event::Transparent : Event::Opaque );
1363 deleteStr(s);
1364 }
1365
1366 // related event
1367 if ((vo = isAPropertyOf(vevent, VCRelatedToProp)) != 0) {
1368 anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo)));
1369 deleteStr(s);
1370 mEventsRelate.append(anEvent);
1371 }
1372
1373 /* PILOT SYNC STUFF */
1374 if ((vo = isAPropertyOf(vevent, KPilotIdProp))) {
1375 anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo))));
1376 deleteStr(s);
1377 }
1378 else
1379 anEvent->setPilotId(0);
1380
1381 if ((vo = isAPropertyOf(vevent, KPilotStatusProp))) {
1382 anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo))));
1383 deleteStr(s);
1384 }
1385 else
1386 anEvent->setSyncStatus(Event::SYNCMOD);
1387
1388 return anEvent;
1389}
1390
1391
1392QString VCalFormat::qDateToISO(const QDate &qd)
1393{
1394 QString tmpStr;
1395
1396 ASSERT(qd.isValid());
1397
1398 tmpStr.sprintf("%.2d%.2d%.2d",
1399 qd.year(), qd.month(), qd.day());
1400 return tmpStr;
1401
1402}
1403
1404QString VCalFormat::qDateTimeToISO(const QDateTime &qdt, bool zulu)
1405{
1406 QString tmpStr;
1407
1408 ASSERT(qdt.date().isValid());
1409 ASSERT(qdt.time().isValid());
1410 if (zulu) {
1411 QDateTime tmpDT(qdt);
1412 tmpDT = tmpDT.addSecs(60*(-mCalendar->getTimeZone())); // correct to GMT.
1413 tmpStr.sprintf("%.2d%.2d%.2dT%.2d%.2d%.2dZ",
1414 tmpDT.date().year(), tmpDT.date().month(),
1415 tmpDT.date().day(), tmpDT.time().hour(),
1416 tmpDT.time().minute(), tmpDT.time().second());
1417 } else {
1418 tmpStr.sprintf("%.2d%.2d%.2dT%.2d%.2d%.2d",
1419 qdt.date().year(), qdt.date().month(),
1420 qdt.date().day(), qdt.time().hour(),
1421 qdt.time().minute(), qdt.time().second());
1422 }
1423 return tmpStr;
1424}
1425
1426QDateTime VCalFormat::ISOToQDateTime(const QString & dtStr)
1427{
1428 QDate tmpDate;
1429 QTime tmpTime;
1430 QString tmpStr;
1431 int year, month, day, hour, minute, second;
1432
1433 tmpStr = dtStr;
1434 year = tmpStr.left(4).toInt();
1435 month = tmpStr.mid(4,2).toInt();
1436 day = tmpStr.mid(6,2).toInt();
1437 hour = tmpStr.mid(9,2).toInt();
1438 minute = tmpStr.mid(11,2).toInt();
1439 second = tmpStr.mid(13,2).toInt();
1440 tmpDate.setYMD(year, month, day);
1441 tmpTime.setHMS(hour, minute, second);
1442
1443 ASSERT(tmpDate.isValid());
1444 ASSERT(tmpTime.isValid());
1445 QDateTime tmpDT(tmpDate, tmpTime);
1446 // correct for GMT if string is in Zulu format
1447 if (dtStr.at(dtStr.length()-1) == 'Z')
1448 tmpDT = tmpDT.addSecs(60*mCalendar->getTimeZone());
1449 return tmpDT;
1450}
1451
1452QDate VCalFormat::ISOToQDate(const QString &dateStr)
1453{
1454 int year, month, day;
1455
1456 year = dateStr.left(4).toInt();
1457 month = dateStr.mid(4,2).toInt();
1458 day = dateStr.mid(6,2).toInt();
1459
1460 return(QDate(year, month, day));
1461}
1462
1463// take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
1464// and break it down from it's tree-like format into the dictionary format
1465// that is used internally in the VCalFormat.
1466void VCalFormat::populate(VObject *vcal)
1467{
1468 // this function will populate the caldict dictionary and other event
1469 // lists. It turns vevents into Events and then inserts them.
1470
1471 VObjectIterator i;
1472 VObject *curVO, *curVOProp;
1473 Event *anEvent;
1474
1475 if ((curVO = isAPropertyOf(vcal, ICMethodProp)) != 0) {
1476 char *methodType = 0;
1477 methodType = fakeCString(vObjectUStringZValue(curVO));
1478 kdDebug() << "This calendar is an iTIP transaction of type '"
1479 << methodType << "'" << endl;
1480 delete methodType;
1481 }
1482
1483 // warn the user that we might have trouble reading non-known calendar.
1484 if ((curVO = isAPropertyOf(vcal, VCProdIdProp)) != 0) {
1485 char *s = fakeCString(vObjectUStringZValue(curVO));
1486 if (strcmp(productId().local8Bit(), s) != 0)
1487 kdDebug() << "This vCalendar file was not created by KOrganizer "
1488 "or any other product we support. Loading anyway..." << endl;
1489 mLoadedProductId = s;
1490 deleteStr(s);
1491 }
1492
1493 // warn the user we might have trouble reading this unknown version.
1494 if ((curVO = isAPropertyOf(vcal, VCVersionProp)) != 0) {
1495 char *s = fakeCString(vObjectUStringZValue(curVO));
1496 if (strcmp(_VCAL_VERSION, s) != 0)
1497 kdDebug() << "This vCalendar file has version " << s
1498 << "We only support " << _VCAL_VERSION << endl;
1499 deleteStr(s);
1500 }
1501
1502 // set the time zone
1503 if ((curVO = isAPropertyOf(vcal, VCTimeZoneProp)) != 0) {
1504 char *s = fakeCString(vObjectUStringZValue(curVO));
1505 mCalendar->setTimeZone(s);
1506 deleteStr(s);
1507 }
1508
1509
1510 // Store all events with a relatedTo property in a list for post-processing
1511 mEventsRelate.clear();
1512 mTodosRelate.clear();
1513
1514 initPropIterator(&i, vcal);
1515
1516 // go through all the vobjects in the vcal
1517 while (moreIteration(&i)) {
1518 curVO = nextVObject(&i);
1519
1520 /************************************************************************/
1521
1522 // now, check to see that the object is an event or todo.
1523 if (strcmp(vObjectName(curVO), VCEventProp) == 0) {
1524
1525 if ((curVOProp = isAPropertyOf(curVO, KPilotStatusProp)) != 0) {
1526 char *s;
1527 s = fakeCString(vObjectUStringZValue(curVOProp));
1528 // check to see if event was deleted by the kpilot conduit
1529 if (atoi(s) == Event::SYNCDEL) {
1530 deleteStr(s);
1531 kdDebug(5800) << "skipping pilot-deleted event" << endl;
1532 goto SKIP;
1533 }
1534 deleteStr(s);
1535 }
1536
1537 // this code checks to see if we are trying to read in an event
1538 // that we already find to be in the calendar. If we find this
1539 // to be the case, we skip the event.
1540 if ((curVOProp = isAPropertyOf(curVO, VCUniqueStringProp)) != 0) {
1541 char *s = fakeCString(vObjectUStringZValue(curVOProp));
1542 QString tmpStr(s);
1543 deleteStr(s);
1544
1545 if (mCalendar->event(tmpStr)) {
1546 goto SKIP;
1547 }
1548 if (mCalendar->todo(tmpStr)) {
1549 goto SKIP;
1550 }
1551 }
1552
1553 if ((!(curVOProp = isAPropertyOf(curVO, VCDTstartProp))) &&
1554 (!(curVOProp = isAPropertyOf(curVO, VCDTendProp)))) {
1555 kdDebug(5800) << "found a VEvent with no DTSTART and no DTEND! Skipping..." << endl;
1556 goto SKIP;
1557 }
1558
1559 anEvent = VEventToEvent(curVO);
1560 // we now use addEvent instead of insertEvent so that the
1561 // signal/slot get connected.
1562 if (anEvent) {
1563 if ( !anEvent->dtStart().isValid() || !anEvent->dtEnd().isValid() ) {
1564 kdDebug() << "VCalFormat::populate(): Event has invalid dates."
1565 << endl;
1566 } else {
1567 mCalendar->addEvent(anEvent);
1568 }
1569 } else {
1570 // some sort of error must have occurred while in translation.
1571 goto SKIP;
1572 }
1573 } else if (strcmp(vObjectName(curVO), VCTodoProp) == 0) {
1574 Todo *aTodo = VTodoToEvent(curVO);
1575 mCalendar->addTodo(aTodo);
1576 } else if ((strcmp(vObjectName(curVO), VCVersionProp) == 0) ||
1577 (strcmp(vObjectName(curVO), VCProdIdProp) == 0) ||
1578 (strcmp(vObjectName(curVO), VCTimeZoneProp) == 0)) {
1579 // do nothing, we know these properties and we want to skip them.
1580 // we have either already processed them or are ignoring them.
1581 ;
1582 } else {
1583 kdDebug(5800) << "Ignoring unknown vObject \"" << vObjectName(curVO) << "\"" << endl;
1584 }
1585 SKIP:
1586 ;
1587 } // while
1588
1589 // Post-Process list of events with relations, put Event objects in relation
1590 Event *ev;
1591 for ( ev=mEventsRelate.first(); ev != 0; ev=mEventsRelate.next() ) {
1592 ev->setRelatedTo(mCalendar->event(ev->relatedToUid()));
1593 }
1594 Todo *todo;
1595 for ( todo=mTodosRelate.first(); todo != 0; todo=mTodosRelate.next() ) {
1596 todo->setRelatedTo(mCalendar->todo(todo->relatedToUid()));
1597 }
1598}
1599
1600const char *VCalFormat::dayFromNum(int day)
1601{
1602 const char *days[7] = { "MO ", "TU ", "WE ", "TH ", "FR ", "SA ", "SU " };
1603
1604 return days[day];
1605}
1606
1607int VCalFormat::numFromDay(const QString &day)
1608{
1609 if (day == "MO ") return 0;
1610 if (day == "TU ") return 1;
1611 if (day == "WE ") return 2;
1612 if (day == "TH ") return 3;
1613 if (day == "FR ") return 4;
1614 if (day == "SA ") return 5;
1615 if (day == "SU ") return 6;
1616
1617 return -1; // something bad happened. :)
1618}
1619
1620Attendee::PartStat VCalFormat::readStatus(const char *s) const
1621{
1622 QString statStr = s;
1623 statStr = statStr.upper();
1624 Attendee::PartStat status;
1625
1626 if (statStr == "X-ACTION")
1627 status = Attendee::NeedsAction;
1628 else if (statStr == "NEEDS ACTION")
1629 status = Attendee::NeedsAction;
1630 else if (statStr== "ACCEPTED")
1631 status = Attendee::Accepted;
1632 else if (statStr== "SENT")
1633 status = Attendee::NeedsAction;
1634 else if (statStr== "TENTATIVE")
1635 status = Attendee::Tentative;
1636 else if (statStr== "CONFIRMED")
1637 status = Attendee::Accepted;
1638 else if (statStr== "DECLINED")
1639 status = Attendee::Declined;
1640 else if (statStr== "COMPLETED")
1641 status = Attendee::Completed;
1642 else if (statStr== "DELEGATED")
1643 status = Attendee::Delegated;
1644 else {
1645 kdDebug(5800) << "error setting attendee mStatus, unknown mStatus!" << endl;
1646 status = Attendee::NeedsAction;
1647 }
1648
1649 return status;
1650}
1651
1652QCString VCalFormat::writeStatus(Attendee::PartStat status) const
1653{
1654 switch(status) {
1655 default:
1656 case Attendee::NeedsAction:
1657 return "NEEDS ACTION";
1658 break;
1659 case Attendee::Accepted:
1660 return "ACCEPTED";
1661 break;
1662 case Attendee::Declined:
1663 return "DECLINED";
1664 break;
1665 case Attendee::Tentative:
1666 return "TENTATIVE";
1667 break;
1668 case Attendee::Delegated:
1669 return "DELEGATED";
1670 break;
1671 case Attendee::Completed:
1672 return "COMPLETED";
1673 break;
1674 case Attendee::InProcess:
1675 return "NEEDS ACTION";
1676 break;
1677 }
1678}
diff --git a/libkcal/vcalformat.h b/libkcal/vcalformat.h
new file mode 100644
index 0000000..d4cecbc
--- a/dev/null
+++ b/libkcal/vcalformat.h
@@ -0,0 +1,108 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#ifndef _VCALFORMAT_H
23#define _VCALFORMAT_H
24
25#include "calformat.h"
26
27#define _VCAL_VERSION "1.0"
28
29class VObject;
30
31namespace KCal {
32
33/**
34 This class implements the vCalendar format. It provides methods for
35 loading/saving/converting vCalendar format data into the internal KOrganizer
36 representation as Calendar and Events.
37
38 @short vCalendar format implementation
39*/
40class VCalFormat : public CalFormat {
41 public:
42 VCalFormat();
43 virtual ~VCalFormat();
44
45 /** loads a calendar on disk in vCalendar format into the current calendar.
46 * any information already present is lost. Returns TRUE if successful,
47 * else returns FALSE.
48 * @param fileName the name of the calendar on disk.
49 */
50 bool load(Calendar *,const QString &fileName);
51 /** writes out the calendar to disk in vCalendar format. Returns true if
52 * successful and false on error.
53 * @param fileName the name of the file
54 */
55 bool save(Calendar *,const QString &fileName);
56
57 /**
58 Parse string and populate calendar with that information.
59 */
60 bool fromString( Calendar *, const QString & );
61 /**
62 Return calendar information as string.
63 */
64 QString toString( Calendar * );
65
66 protected:
67 /** translates a VObject of the TODO type into a Event */
68 Todo *VTodoToEvent(VObject *vtodo);
69 /** translates a VObject into a Event and returns a pointer to it. */
70 Event *VEventToEvent(VObject *vevent);
71 /** translate a Event into a VTodo-type VObject and return pointer */
72 VObject *eventToVTodo(const Todo *anEvent);
73 /** translate a Event into a VObject and returns a pointer to it. */
74 VObject* eventToVEvent(const Event *anEvent);
75
76 /** takes a QDate and returns a string in the format YYYYMMDDTHHMMSS */
77 QString qDateToISO(const QDate &);
78 /** takes a QDateTime and returns a string in format YYYYMMDDTHHMMSS */
79 QString qDateTimeToISO(const QDateTime &, bool zulu=TRUE);
80 /** takes a string in the format YYYYMMDDTHHMMSS and returns a
81 * valid QDateTime. */
82 QDateTime ISOToQDateTime(const QString & dtStr);
83 /** takes a string in the format YYYYMMDD and returns a
84 * valid QDate. */
85 QDate ISOToQDate(const QString & dtStr);
86 /** takes a vCalendar tree of VObjects, and puts all of them that have
87 * the "event" property into the dictionary, todos in the todo-list, etc. */
88 void populate(VObject *vcal);
89
90 /** takes a number 0 - 6 and returns the two letter string of that day,
91 * i.e. MO, TU, WE, etc. */
92 const char *dayFromNum(int day);
93 /** the reverse of the above function. */
94 int numFromDay(const QString &day);
95
96 Attendee::PartStat readStatus(const char *s) const;
97 QCString writeStatus(Attendee::PartStat status) const;
98
99 private:
100 Calendar *mCalendar;
101
102 QPtrList<Event> mEventsRelate; // events with relations
103 QPtrList<Todo> mTodosRelate; // todos with relations
104};
105
106}
107
108#endif
diff --git a/libkcal/versit/port.h b/libkcal/versit/port.h
new file mode 100644
index 0000000..afc16dd
--- a/dev/null
+++ b/libkcal/versit/port.h
@@ -0,0 +1,75 @@
1/***************************************************************************
2(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
3Business Machines Corporation and Siemens Rolm Communications Inc.
4
5For purposes of this license notice, the term Licensors shall mean,
6collectively, Apple Computer, Inc., AT&T Corp., International
7Business Machines Corporation and Siemens Rolm Communications Inc.
8The term Licensor shall mean any of the Licensors.
9
10Subject to acceptance of the following conditions, permission is hereby
11granted by Licensors without the need for written agreement and without
12license or royalty fees, to use, copy, modify and distribute this
13software for any purpose.
14
15The above copyright notice and the following four paragraphs must be
16reproduced in all copies of this software and any software including
17this software.
18
19THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
20ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
21MODIFICATIONS.
22
23IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
24INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
25OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26DAMAGE.
27
28EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
29INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
30IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31PURPOSE.
32
33The software is provided with RESTRICTED RIGHTS. Use, duplication, or
34disclosure by the government are subject to restrictions set forth in
35DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
36
37***************************************************************************/
38
39#ifndef __PORT_H__
40#define __PORT_H__ 1
41
42#if defined(__CPLUSPLUS__) || defined(__cplusplus)
43extern "C" {
44#endif
45
46#define vCardClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCard"
47#define vCalendarClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCalendar"
48
49/* The above strings vCardClipboardFormat and vCalendarClipboardFormat
50are globally unique IDs which can be used to generate clipboard format
51ID's as per the requirements of a specific platform. For example, in
52Windows they are used as the parameter in a call to RegisterClipboardFormat.
53For example:
54
55 CLIPFORMAT foo = RegisterClipboardFormat(vCardClipboardFormat);
56
57*/
58
59#define vCardMimeType "text/x-vCard"
60#define vCalendarMimeType "text/x-vCalendar"
61
62#ifndef FALSE
63#define FALSE 0
64#endif
65#ifndef TRUE
66#define TRUE 1
67#endif
68
69#define Parse_Debug(t)
70
71#if defined(__CPLUSPLUS__) || defined(__cplusplus)
72}
73#endif
74
75#endif /* __PORT_H__ */
diff --git a/libkcal/versit/vcc.c b/libkcal/versit/vcc.c
new file mode 100644
index 0000000..350cac3
--- a/dev/null
+++ b/libkcal/versit/vcc.c
@@ -0,0 +1,2162 @@
1
2/* A Bison parser, made from ./vcc.y
3 by GNU Bison version 1.28 */
4
5#define YYBISON 1 /* Identify Bison output. */
6
7#ifdef _WIN32_
8#define strcasecmp _stricmp
9#endif
10
11 #define EQ257
12 #define COLON258
13 #define DOT259
14 #define SEMICOLON260
15 #define SPACE261
16 #define HTAB262
17 #define LINESEP263
18 #define NEWLINE264
19 #define BEGIN_VCARD265
20 #define END_VCARD266
21 #define BEGIN_VCAL267
22 #define END_VCAL268
23 #define BEGIN_VEVENT269
24 #define END_VEVENT270
25 #define BEGIN_VTODO271
26 #define END_VTODO272
27 #define ID273
28 #define STRING274
29
30#line 1 "./vcc.y"
31
32
33/***************************************************************************
34(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
35Business Machines Corporation and Siemens Rolm Communications Inc.
36
37For purposes of this license notice, the term Licensors shall mean,
38collectively, Apple Computer, Inc., AT&T Corp., International
39Business Machines Corporation and Siemens Rolm Communications Inc.
40The term Licensor shall mean any of the Licensors.
41
42Subject to acceptance of the following conditions, permission is hereby
43granted by Licensors without the need for written agreement and without
44license or royalty fees, to use, copy, modify and distribute this
45software for any purpose.
46
47The above copyright notice and the following four paragraphs must be
48reproduced in all copies of this software and any software including
49this software.
50
51THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
52ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
53MODIFICATIONS.
54
55IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
56INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
57OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
58DAMAGE.
59
60EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
61INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
62IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
63PURPOSE.
64
65The software is provided with RESTRICTED RIGHTS. Use, duplication, or
66disclosure by the government are subject to restrictions set forth in
67DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
68
69***************************************************************************/
70
71/*
72 * src: vcc.c
73 * doc: Parser for vCard and vCalendar. Note that this code is
74 * generated by a yacc parser generator. Generally it should not
75 * be edited by hand. The real source is vcc.y. The #line directives
76 * can be commented out here to make it easier to trace through
77 * in a debugger. However, if a bug is found it should
78 * be fixed in vcc.y and this file regenerated.
79 */
80
81
82/* debugging utilities */
83#if __DEBUG
84#define DBG_(x) printf x
85#else
86#define DBG_(x)
87#endif
88
89/**** External Functions ****/
90
91/* assign local name to parser variables and functions so that
92 we can use more than one yacc based parser.
93*/
94
95#define yyparse mime_parse
96#define yylex mime_lex
97#define yyerror mime_error
98#define yychar mime_char
99/* #define p_yyval p_mime_val */
100#undef yyval
101#define yyval mime_yyval
102/* #define p_yylval p_mime_lval */
103#undef yylval
104#define yylval mime_yylval
105#define yydebug mime_debug
106#define yynerrs mime_nerrs
107#define yyerrflag mime_errflag
108#define yyss mime_ss
109#define yyssp mime_ssp
110#define yyvs mime_vs
111#define yyvsp mime_vsp
112#define yylhs mime_lhs
113#define yylen mime_len
114#define yydefred mime_defred
115#define yydgoto mime_dgoto
116#define yysindex mime_sindex
117#define yyrindex mime_rindex
118#define yygindex mime_gindex
119#define yytable mime_table
120#define yycheck mime_check
121#define yyname mime_name
122#define yyrule mime_rule
123#undef YYPREFIX
124#define YYPREFIX "mime_"
125
126
127#ifndef _NO_LINE_FOLDING
128#define _SUPPORT_LINE_FOLDING 1
129#endif
130
131#include <string.h>
132#ifndef __FreeBSD__
133#include <malloc.h>
134#endif
135#include <stdio.h>
136#include <stdlib.h>
137#include <ctype.h>
138#include "vcc.h"
139
140/* The following is a hack that I hope will get things compiling
141 * on SunOS 4.1.x systems
142 */
143#ifndef SEEK_SET
144#define SEEK_SET 0 /* Seek from beginning of file. */
145#define SEEK_CUR 1 /* Seek from current position. */
146#define SEEK_END 2 /* Seek from end of file. */
147#endif
148
149/**** Types, Constants ****/
150
151 #define YYDEBUG 0/* 1 to compile in some debugging code */
152 #define MAXTOKEN 256/* maximum token (line) length */
153 #define YYSTACKSIZE 1000/* ~unref ? */
154 #define MAXLEVEL 10/* max # of nested objects parseable */
155 /* (includes outermost) */
156
157
158/**** Global Variables ****/
159int mime_lineNum, mime_numErrors; /* yyerror() can use these */
160static VObject* vObjList;
161static VObject *curProp;
162static VObject *curObj;
163static VObject* ObjStack[MAXLEVEL];
164static int ObjStackTop;
165
166
167/* A helpful utility for the rest of the app. */
168#if __CPLUSPLUS__
169extern "C" {
170#endif
171
172 /* static void Parse_Debug(const char *s);*/
173 static void yyerror(char *s);
174
175#if __CPLUSPLUS__
176 };
177#endif
178
179int yyparse();
180static int yylex();
181enum LexMode {
182 L_NORMAL,
183 L_VCARD,
184 L_VCAL,
185 L_VEVENT,
186 L_VTODO,
187 L_VALUES,
188 L_BASE64,
189 L_QUOTED_PRINTABLE
190 };
191
192/**** Private Forward Declarations ****/
193static int pushVObject(const char *prop);
194static VObject* popVObject();
195char* lexDataFromBase64();
196static void lexPopMode(int top);
197static int lexWithinMode(enum LexMode mode);
198static void lexPushMode(enum LexMode mode);
199static void enterProps(const char *s);
200static void enterAttr(const char *s1, const char *s2);
201/* static void enterValues(const char *value); */
202static void appendValue(const char *value);
203static void mime_error_(char *s);
204
205
206#line 181 "./vcc.y"
207typedef union {
208 char *str;
209 VObject *vobj;
210 } YYSTYPE;
211#include <stdio.h>
212
213#ifndef __cplusplus
214#ifndef __STDC__
215#define const
216#endif
217#endif
218
219
220
221 #define YYFINAL 62
222 #define YYFLAG -32768
223 #define YYNTBASE21
224
225#define YYTRANSLATE(x) ((unsigned)(x) <= 274 ? yytranslate[x] : 51)
226
227static const char yytranslate[] = { 0,
228 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
229 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
230 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
231 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
232 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
233 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
234 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
235 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
236 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
237 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
238 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
239 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
240 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
241 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
242 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
243 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
244 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
245 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
246 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
247 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
248 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
249 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
250 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
251 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
252 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
253 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
254 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
255 17, 18, 19, 20
256};
257
258#if YYDEBUG != 0
259static const short yyprhs[] = { 0,
260 0, 2, 3, 7, 9, 11, 13, 14, 19, 20,
261 24, 27, 29, 30, 36, 38, 39, 43, 45, 48,
262 50, 53, 55, 59, 61, 62, 67, 69, 71, 72,
263 73, 78, 79, 83, 86, 88, 90, 92, 94, 95,
264 100, 101, 105, 106, 111, 112
265};
266
267static const short yyrhs[] = { 22,
268 0, 0, 24, 23, 22, 0, 24, 0, 25, 0,
269 40, 0, 0, 11, 26, 28, 12, 0, 0, 11,
270 27, 12, 0, 29, 28, 0, 29, 0, 0, 31,
271 4, 30, 37, 9, 0, 1, 0, 0, 36, 32,
272 33, 0, 36, 0, 34, 33, 0, 34, 0, 6,
273 35, 0, 36, 0, 36, 3, 36, 0, 19, 0,
274 0, 39, 6, 38, 37, 0, 39, 0, 20, 0,
275 0, 0, 13, 41, 43, 14, 0, 0, 13, 42,
276 14, 0, 44, 43, 0, 44, 0, 45, 0, 48,
277 0, 28, 0, 0, 15, 46, 28, 16, 0, 0,
278 15, 47, 16, 0, 0, 17, 49, 28, 18, 0,
279 0, 17, 50, 18, 0
280};
281
282#endif
283
284#if YYDEBUG != 0
285static const short yyrline[] = { 0,
286 209, 212, 215, 215, 219, 220, 223, 229, 234, 240,
287 246, 247, 250, 254, 260, 263, 268, 268, 274, 275,
288 278, 281, 285, 292, 295, 296, 296, 300, 301, 305,
289 309, 311, 314, 317, 318, 321, 323, 324, 327, 334,
290 339, 345, 351, 358, 363, 369
291};
292#endif
293
294
295#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
296
297static const char * const yytname[] = { "$","error","$undefined.","EQ","COLON",
298"DOT","SEMICOLON","SPACE","HTAB","LINESEP","NEWLINE","BEGIN_VCARD","END_VCARD",
299"BEGIN_VCAL","END_VCAL","BEGIN_VEVENT","END_VEVENT","BEGIN_VTODO","END_VTODO",
300"ID","STRING","mime","vobjects","@1","vobject","vcard","@2","@3","items","item",
301"@4","prop","@5","attr_params","attr_param","attr","name","values","@6","value",
302"vcal","@7","@8","calitems","calitem","eventitem","@9","@10","todoitem","@11",
303"@12", NULL
304};
305#endif
306
307static const short yyr1[] = { 0,
308 21, 23, 22, 22, 24, 24, 26, 25, 27, 25,
309 28, 28, 30, 29, 29, 32, 31, 31, 33, 33,
310 34, 35, 35, 36, 38, 37, 37, 39, 39, 41,
311 40, 42, 40, 43, 43, 44, 44, 44, 46, 45,
312 47, 45, 49, 48, 50, 48
313};
314
315static const short yyr2[] = { 0,
316 1, 0, 3, 1, 1, 1, 0, 4, 0, 3,
317 2, 1, 0, 5, 1, 0, 3, 1, 2, 1,
318 2, 1, 3, 1, 0, 4, 1, 1, 0, 0,
319 4, 0, 3, 2, 1, 1, 1, 1, 0, 4,
320 0, 3, 0, 4, 0, 3
321};
322
323static const short yydefact[] = { 0,
324 7, 30, 1, 2, 5, 6, 0, 0, 0, 0,
325 0, 15, 24, 0, 0, 0, 16, 10, 39, 43,
326 38, 0, 0, 36, 37, 33, 3, 8, 11, 13,
327 0, 0, 0, 0, 0, 31, 34, 29, 0, 17,
328 20, 0, 42, 0, 46, 28, 0, 27, 21, 22,
329 19, 40, 44, 14, 25, 0, 29, 23, 26, 0,
330 0, 0
331};
332
333static const short yydefgoto[] = { 60,
334 3, 11, 4, 5, 7, 8, 21, 15, 38, 16,
335 31, 40, 41, 49, 17, 47, 57, 48, 6, 9,
336 10, 22, 23, 24, 32, 33, 25, 34, 35
337};
338
339static const short yypact[] = { -9,
340 -6, -5,-32768, 7,-32768,-32768, 2, -1, 19, 15,
341 -9,-32768,-32768, 1, 0, 26, 27,-32768, 16, 17,
342-32768, 23, 9,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
343 33, 2, 24, 2, 25,-32768,-32768, 13, 22,-32768,
344 33, 28,-32768, 29,-32768,-32768, 36, 40,-32768, 39,
345-32768,-32768,-32768,-32768,-32768, 22, 13,-32768,-32768, 48,
346 49,-32768
347};
348
349static const short yypgoto[] = {-32768,
350 41,-32768,-32768,-32768,-32768,-32768, -7,-32768,-32768,-32768,
351-32768, 10,-32768,-32768, -34, -4,-32768,-32768,-32768,-32768,
352-32768, 31,-32768,-32768,-32768,-32768,-32768,-32768,-32768
353};
354
355
356 #define YYLAST 54
357
358
359static const short yytable[] = { 14,
360 12, 1, 12, 2, 50, -9, -4, 29, -32, 12,
361 18, -12, 28, -12, -12, -12, -12, -12, 13, 12,
362 13, 58, -35, 19, 42, 20, 44, 13, 26, 30,
363 -18, -41, 46, 19, -45, 20, 36, 13, 39, 43,
364 13, 56, 45, 52, 54, 55, 53, 61, 62, 0,
365 51, 27, 59, 37
366};
367
368static const short yycheck[] = { 7,
369 1, 11, 1, 13, 39, 12, 0, 15, 14, 1,
370 12, 12, 12, 14, 15, 16, 17, 18, 19, 1,
371 19, 56, 14, 15, 32, 17, 34, 19, 14, 4,
372 4, 16, 20, 15, 18, 17, 14, 19, 6, 16,
373 19, 3, 18, 16, 9, 6, 18, 0, 0, -1,
374 41, 11, 57, 23
375};
376/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
377#line 3 "/usr/share/bison.simple"
378/* This file comes from bison-1.28. */
379
380/* Skeleton output parser for bison,
381 Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
382
383 This program is free software; you can redistribute it and/or modify
384 it under the terms of the GNU General Public License as published by
385 the Free Software Foundation; either version 2, or (at your option)
386 any later version.
387
388 This program is distributed in the hope that it will be useful,
389 but WITHOUT ANY WARRANTY; without even the implied warranty of
390 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
391 GNU General Public License for more details.
392
393 You should have received a copy of the GNU General Public License
394 along with this program; if not, write to the Free Software
395 Foundation, Inc., 59 Temple Place - Suite 330,
396 Boston, MA 02111-1307, USA. */
397
398/* As a special exception, when this file is copied by Bison into a
399 Bison output file, you may use that output file without restriction.
400 This special exception was added by the Free Software Foundation
401 in version 1.24 of Bison. */
402
403/* This is the parser code that is written into each bison parser
404 when the %semantic_parser declaration is not specified in the grammar.
405 It was written by Richard Stallman by simplifying the hairy parser
406 used when %semantic_parser is specified. */
407
408#ifndef YYSTACK_USE_ALLOCA
409#ifdef alloca
410#define YYSTACK_USE_ALLOCA
411#else /* alloca not defined */
412#ifdef __GNUC__
413#define YYSTACK_USE_ALLOCA
414#define alloca __builtin_alloca
415#else /* not GNU C. */
416#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
417#define YYSTACK_USE_ALLOCA
418#include <alloca.h>
419#else /* not sparc */
420/* We think this test detects Watcom and Microsoft C. */
421/* This used to test MSDOS, but that is a bad idea
422 since that symbol is in the user namespace. */
423#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
424#if 0 /* No need for malloc.h, which pollutes the namespace;
425 instead, just don't use alloca. */
426#include <malloc.h>
427#endif
428#else /* not MSDOS, or __TURBOC__ */
429#if defined(_AIX)
430/* I don't know what this was needed for, but it pollutes the namespace.
431 So I turned it off. rms, 2 May 1997. */
432/* #include <malloc.h> */
433 #pragma alloca
434#define YYSTACK_USE_ALLOCA
435#else /* not MSDOS, or __TURBOC__, or _AIX */
436#if 0
437#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
438 and on HPUX 10. Eventually we can turn this on. */
439#define YYSTACK_USE_ALLOCA
440#define alloca __builtin_alloca
441#endif /* __hpux */
442#endif
443#endif /* not _AIX */
444#endif /* not MSDOS, or __TURBOC__ */
445#endif /* not sparc */
446#endif /* not GNU C */
447#endif /* alloca not defined */
448#endif /* YYSTACK_USE_ALLOCA not defined */
449
450#ifdef YYSTACK_USE_ALLOCA
451#define YYSTACK_ALLOC alloca
452#else
453#define YYSTACK_ALLOC malloc
454#endif
455
456/* Note: there must be only one dollar sign in this file.
457 It is replaced by the list of actions, each action
458 as one case of the switch. */
459
460 #define yyerrok (yyerrstatus = 0)
461 #define yyclearin(yychar = YYEMPTY)
462 #define YYEMPTY -2
463 #define YYEOF 0
464 #define YYACCEPTgoto yyacceptlab
465 #define YYABORT goto yyabortlab
466 #define YYERROR goto yyerrlab1
467/* Like YYERROR except do call yyerror.
468 This remains here temporarily to ease the
469 transition to the new meaning of YYERROR, for GCC.
470 Once GCC version 2 has supplanted version 1, this can go. */
471 #define YYFAIL goto yyerrlab
472#define YYRECOVERING() (!!yyerrstatus)
473#define YYBACKUP(token, value) \
474 do \
475 if (yychar == YYEMPTY && yylen == 1) \
476 { yychar = (token), yylval = (value); \
477 yychar1 = YYTRANSLATE (yychar); \
478 YYPOPSTACK; \
479 goto yybackup; \
480 } \
481 else \
482 { yyerror ("syntax error: cannot back up"); YYERROR; }\
483while (0)
484
485 #define YYTERROR1
486 #define YYERRCODE256
487
488#ifndef YYPURE
489 #define YYLEX yylex()
490#endif
491
492#ifdef YYPURE
493#ifdef YYLSP_NEEDED
494#ifdef YYLEX_PARAM
495 #define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
496#else
497 #define YYLEX yylex(&yylval, &yylloc)
498#endif
499#else /* not YYLSP_NEEDED */
500#ifdef YYLEX_PARAM
501 #define YYLEX yylex(&yylval, YYLEX_PARAM)
502#else
503 #define YYLEX yylex(&yylval)
504#endif
505#endif /* not YYLSP_NEEDED */
506#endif
507
508/* If nonreentrant, generate the variables here */
509
510#ifndef YYPURE
511
512 int yychar; /* the lookahead symbol */
513 YYSTYPE yylval; /* the semantic value of the */
514 /* lookahead symbol */
515
516#ifdef YYLSP_NEEDED
517 YYLTYPE yylloc; /* location data for the lookahead*/
518 /* symbol */
519#endif
520
521 int yynerrs; /* number of parse errors so far */
522#endif /* not YYPURE */
523
524#if YYDEBUG != 0
525 int yydebug; /* nonzero means print parse trace*/
526/* Since this is uninitialized, it does not stop multiple parsers
527 from coexisting. */
528#endif
529
530 /* YYINITDEPTH indicates the initial size of the parser's stacks*/
531
532 #ifndefYYINITDEPTH
533#define YYINITDEPTH 200
534#endif
535
536/* YYMAXDEPTH is the maximum size the stacks can grow to
537 (effective only if the built-in stack extension method is used). */
538
539#if YYMAXDEPTH == 0
540#undef YYMAXDEPTH
541#endif
542
543#ifndef YYMAXDEPTH
544#define YYMAXDEPTH 10000
545#endif
546
547/* Define __yy_memcpy. Note that the size argument
548 should be passed with type unsigned int, because that is what the non-GCC
549 definitions require. With GCC, __builtin_memcpy takes an arg
550 of type size_t, but it can handle unsigned int. */
551
552 #if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
553 #define __yy_memcpy(TO,FROM,COUNT)__builtin_memcpy(TO,FROM,COUNT)
554 #else /* not GNU C or C++ */
555#ifndef __cplusplus
556
557/* This is the most reliable way to avoid incompatibilities
558 in available built-in functions on various systems. */
559static void
560__yy_memcpy (to, from, count)
561 char *to;
562 char *from;
563 unsigned int count;
564{
565 register char *f = from;
566 register char *t = to;
567 register int i = count;
568
569 while (i-- > 0)
570 *t++ = *f++;
571}
572
573#else /* __cplusplus */
574
575/* This is the most reliable way to avoid incompatibilities
576 in available built-in functions on various systems. */
577static void
578__yy_memcpy (char *to, char *from, unsigned int count)
579{
580 register char *t = to;
581 register char *f = from;
582 register int i = count;
583
584 while (i-- > 0)
585 *t++ = *f++;
586}
587
588#endif
589#endif
590
591#line 217 "/usr/share/bison.simple"
592
593/* The user can define YYPARSE_PARAM as the name of an argument to be passed
594 into yyparse. The argument should have type void *.
595 It should actually point to an object.
596 Grammar actions can access the variable by casting it
597 to the proper pointer type. */
598
599#ifdef YYPARSE_PARAM
600#ifdef __cplusplus
601#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
602#define YYPARSE_PARAM_DECL
603#else /* not __cplusplus */
604#define YYPARSE_PARAM_ARG YYPARSE_PARAM
605#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
606#endif /* not __cplusplus */
607#else /* not YYPARSE_PARAM */
608#define YYPARSE_PARAM_ARG
609#define YYPARSE_PARAM_DECL
610#endif /* not YYPARSE_PARAM */
611
612/* Prevent warning if -Wstrict-prototypes. */
613#if defined (__GNUC__) && ! defined (__cplusplus)
614#ifdef YYPARSE_PARAM
615int yyparse (void *);
616#else
617int yyparse (void);
618#endif
619#endif
620
621int
622yyparse(YYPARSE_PARAM_ARG)
623 YYPARSE_PARAM_DECL
624{
625 register int yystate;
626 register int yyn;
627 register short *yyssp;
628 register YYSTYPE *yyvsp;
629 int yyerrstatus;/* number of tokens to shift before error messages enabled */
630 int yychar1 = 0; /* lookahead token as an internal (translated) token number */
631
632 short yyssa[YYINITDEPTH]; /* the state stack */
633 YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
634
635 short *yyss = yyssa; /* refer to the stacks thru separate pointers */
636 YYSTYPE *yyvs = yyvsa;/* to allow yyoverflow to reallocate them elsewhere */
637
638#ifdef YYLSP_NEEDED
639 YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
640 YYLTYPE *yyls = yylsa;
641 YYLTYPE *yylsp;
642
643#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
644#else
645#define YYPOPSTACK (yyvsp--, yyssp--)
646#endif
647
648 int yystacksize = YYINITDEPTH;
649 int yyfree_stacks = 0;
650
651#ifdef YYPURE
652 int yychar;
653 YYSTYPE yylval;
654 int yynerrs;
655#ifdef YYLSP_NEEDED
656 YYLTYPE yylloc;
657#endif
658#endif
659
660 YYSTYPE yyval; /* the variable used to return */
661 /* semantic values from the action*/
662 /* routines */
663
664 int yylen;
665
666#if YYDEBUG != 0
667 if (yydebug)
668 fprintf(stderr, "Starting parse\n");
669#endif
670
671 yystate = 0;
672 yyerrstatus = 0;
673 yynerrs = 0;
674 yychar = YYEMPTY; /* Cause a token to be read. */
675
676 /* Initialize stack pointers.
677 Waste one element of value and location stack
678 so that they stay on the same level as the state stack.
679 The wasted elements are never initialized. */
680
681 yyssp = yyss - 1;
682 yyvsp = yyvs;
683#ifdef YYLSP_NEEDED
684 yylsp = yyls;
685#endif
686
687/* Push a new state, which is found in yystate . */
688/* In all cases, when you get here, the value and location stacks
689 have just been pushed. so pushing a state here evens the stacks. */
690yynewstate:
691
692 *++yyssp = yystate;
693
694 if (yyssp >= yyss + yystacksize - 1)
695 {
696 /* Give user a chance to reallocate the stack */
697 /* Use copies of these so that the &'s don't force the real ones into memory. */
698 YYSTYPE *yyvs1 = yyvs;
699 short *yyss1 = yyss;
700#ifdef YYLSP_NEEDED
701 YYLTYPE *yyls1 = yyls;
702#endif
703
704 /* Get the current used size of the three stacks, in elements. */
705 int size = yyssp - yyss + 1;
706
707#ifdef yyoverflow
708 /* Each stack pointer address is followed by the size of
709 the data in use in that stack, in bytes. */
710#ifdef YYLSP_NEEDED
711 /* This used to be a conditional around just the two extra args,
712 but that might be undefined if yyoverflow is a macro. */
713 yyoverflow("parser stack overflow",
714 &yyss1, size * sizeof (*yyssp),
715 &yyvs1, size * sizeof (*yyvsp),
716 &yyls1, size * sizeof (*yylsp),
717 &yystacksize);
718#else
719 yyoverflow("parser stack overflow",
720 &yyss1, size * sizeof (*yyssp),
721 &yyvs1, size * sizeof (*yyvsp),
722 &yystacksize);
723#endif
724
725 yyss = yyss1; yyvs = yyvs1;
726#ifdef YYLSP_NEEDED
727 yyls = yyls1;
728#endif
729#else /* no yyoverflow */
730 /* Extend the stack our own way. */
731 if (yystacksize >= YYMAXDEPTH)
732 {
733 yyerror("parser stack overflow");
734 if (yyfree_stacks)
735 {
736 free (yyss);
737 free (yyvs);
738#ifdef YYLSP_NEEDED
739 free (yyls);
740#endif
741 }
742 return 2;
743 }
744 yystacksize *= 2;
745 if (yystacksize > YYMAXDEPTH)
746 yystacksize = YYMAXDEPTH;
747#ifndef YYSTACK_USE_ALLOCA
748 yyfree_stacks = 1;
749#endif
750 yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
751 __yy_memcpy ((char *)yyss, (char *)yyss1,
752 size * (unsigned int) sizeof (*yyssp));
753 yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
754 __yy_memcpy ((char *)yyvs, (char *)yyvs1,
755 size * (unsigned int) sizeof (*yyvsp));
756#ifdef YYLSP_NEEDED
757 yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
758 __yy_memcpy ((char *)yyls, (char *)yyls1,
759 size * (unsigned int) sizeof (*yylsp));
760#endif
761#endif /* no yyoverflow */
762
763 yyssp = yyss + size - 1;
764 yyvsp = yyvs + size - 1;
765#ifdef YYLSP_NEEDED
766 yylsp = yyls + size - 1;
767#endif
768
769#if YYDEBUG != 0
770 if (yydebug)
771 fprintf(stderr, "Stack size increased to %d\n", yystacksize);
772#endif
773
774 if (yyssp >= yyss + yystacksize - 1)
775 YYABORT;
776 }
777
778#if YYDEBUG != 0
779 if (yydebug)
780 fprintf(stderr, "Entering state %d\n", yystate);
781#endif
782
783 goto yybackup;
784 yybackup:
785
786/* Do appropriate processing given the current state. */
787/* Read a lookahead token if we need one and don't already have one. */
788/* yyresume: */
789
790 /* First try to decide what to do without reference to lookahead token. */
791
792 yyn = yypact[yystate];
793 if (yyn == YYFLAG)
794 goto yydefault;
795
796 /* Not known => get a lookahead token if don't already have one. */
797
798 /* yychar is either YYEMPTY or YYEOF
799 or a valid token in external form. */
800
801 if (yychar == YYEMPTY)
802 {
803#if YYDEBUG != 0
804 if (yydebug)
805 fprintf(stderr, "Reading a token: ");
806#endif
807 yychar = YYLEX;
808 }
809
810 /* Convert token to internal form (in yychar1) for indexing tables with */
811
812 if (yychar <= 0) /* This means end of input. */
813 {
814 yychar1 = 0;
815 yychar = YYEOF; /* Don't call YYLEX any more */
816
817#if YYDEBUG != 0
818 if (yydebug)
819 fprintf(stderr, "Now at end of input.\n");
820#endif
821 }
822 else
823 {
824 yychar1 = YYTRANSLATE(yychar);
825
826#if YYDEBUG != 0
827 if (yydebug)
828 {
829 fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
830 /* Give the individual parser a way to print the precise meaning
831 of a token, for further debugging info. */
832#ifdef YYPRINT
833 YYPRINT (stderr, yychar, yylval);
834#endif
835 fprintf (stderr, ")\n");
836 }
837#endif
838 }
839
840 yyn += yychar1;
841 if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
842 goto yydefault;
843
844 yyn = yytable[yyn];
845
846 /* yyn is what to do for this token type in this state.
847 Negative => reduce, -yyn is rule number.
848 Positive => shift, yyn is new state.
849 New state is final state => don't bother to shift,
850 just return success.
851 0, or most negative number => error. */
852
853 if (yyn < 0)
854 {
855 if (yyn == YYFLAG)
856 goto yyerrlab;
857 yyn = -yyn;
858 goto yyreduce;
859 }
860 else if (yyn == 0)
861 goto yyerrlab;
862
863 if (yyn == YYFINAL)
864 YYACCEPT;
865
866 /* Shift the lookahead token. */
867
868#if YYDEBUG != 0
869 if (yydebug)
870 fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
871#endif
872
873 /* Discard the token being shifted unless it is eof. */
874 if (yychar != YYEOF)
875 yychar = YYEMPTY;
876
877 *++yyvsp = yylval;
878#ifdef YYLSP_NEEDED
879 *++yylsp = yylloc;
880#endif
881
882 /* count tokens shifted since error; after three, turn off error status. */
883 if (yyerrstatus) yyerrstatus--;
884
885 yystate = yyn;
886 goto yynewstate;
887
888/* Do the default action for the current state. */
889yydefault:
890
891 yyn = yydefact[yystate];
892 if (yyn == 0)
893 goto yyerrlab;
894
895/* Do a reduction. yyn is the number of a rule to reduce with. */
896yyreduce:
897 yylen = yyr2[yyn];
898 if (yylen > 0)
899 yyval = yyvsp[1-yylen]; /* implement default value of the action */
900
901#if YYDEBUG != 0
902 if (yydebug)
903 {
904 int i;
905
906 fprintf (stderr, "Reducing via rule %d (line %d), ",
907 yyn, yyrline[yyn]);
908
909 /* Print the symbols being reduced, and their result. */
910 for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
911 fprintf (stderr, "%s ", yytname[yyrhs[i]]);
912 fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
913 }
914#endif
915
916
917 switch (yyn) {
918
919case 2:
920#line 213 "./vcc.y"
921{ addList(&vObjList, yyvsp[0].vobj); curObj = 0; ;
922 break;}
923case 4:
924#line 216 "./vcc.y"
925{ addList(&vObjList, yyvsp[0].vobj); curObj = 0; ;
926 break;}
927case 7:
928#line 225 "./vcc.y"
929{
930 lexPushMode(L_VCARD);
931 if (!pushVObject(VCCardProp)) YYERROR;
932 ;
933 break;}
934case 8:
935#line 230 "./vcc.y"
936{
937 lexPopMode(0);
938 yyval.vobj = popVObject();
939 ;
940 break;}
941case 9:
942#line 235 "./vcc.y"
943{
944 lexPushMode(L_VCARD);
945 if (!pushVObject(VCCardProp)) YYERROR;
946 ;
947 break;}
948case 10:
949#line 240 "./vcc.y"
950{
951 lexPopMode(0);
952 yyval.vobj = popVObject();
953 ;
954 break;}
955case 13:
956#line 251 "./vcc.y"
957{
958 lexPushMode(L_VALUES);
959 ;
960 break;}
961case 14:
962#line 255 "./vcc.y"
963{
964 if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
965 lexPopMode(0);
966 lexPopMode(0);
967 ;
968 break;}
969case 16:
970#line 264 "./vcc.y"
971{
972 enterProps(yyvsp[0].str);
973 ;
974 break;}
975case 18:
976#line 269 "./vcc.y"
977{
978 enterProps(yyvsp[0].str);
979 ;
980 break;}
981case 22:
982#line 282 "./vcc.y"
983{
984 enterAttr(yyvsp[0].str,0);
985 ;
986 break;}
987case 23:
988#line 286 "./vcc.y"
989{
990 enterAttr(yyvsp[-2].str,yyvsp[0].str);
991
992 ;
993 break;}
994case 25:
995#line 295 "./vcc.y"
996{ appendValue(yyvsp[-1].str); ;
997 break;}
998case 27:
999#line 297 "./vcc.y"
1000{ appendValue(yyvsp[0].str); ;
1001 break;}
1002case 29:
1003#line 302 "./vcc.y"
1004{ yyval.str = 0; ;
1005 break;}
1006case 30:
1007#line 307 "./vcc.y"
1008{ if (!pushVObject(VCCalProp)) YYERROR; ;
1009 break;}
1010case 31:
1011#line 310 "./vcc.y"
1012{ yyval.vobj = popVObject(); ;
1013 break;}
1014case 32:
1015#line 312 "./vcc.y"
1016{ if (!pushVObject(VCCalProp)) YYERROR; ;
1017 break;}
1018case 33:
1019#line 314 "./vcc.y"
1020{ yyval.vobj = popVObject(); ;
1021 break;}
1022case 39:
1023#line 329 "./vcc.y"
1024{
1025 lexPushMode(L_VEVENT);
1026 if (!pushVObject(VCEventProp)) YYERROR;
1027 ;
1028 break;}
1029case 40:
1030#line 335 "./vcc.y"
1031{
1032 lexPopMode(0);
1033 popVObject();
1034 ;
1035 break;}
1036case 41:
1037#line 340 "./vcc.y"
1038{
1039 lexPushMode(L_VEVENT);
1040 if (!pushVObject(VCEventProp)) YYERROR;
1041 ;
1042 break;}
1043case 42:
1044#line 345 "./vcc.y"
1045{
1046 lexPopMode(0);
1047 popVObject();
1048 ;
1049 break;}
1050case 43:
1051#line 353 "./vcc.y"
1052{
1053 lexPushMode(L_VTODO);
1054 if (!pushVObject(VCTodoProp)) YYERROR;
1055 ;
1056 break;}
1057case 44:
1058#line 359 "./vcc.y"
1059{
1060 lexPopMode(0);
1061 popVObject();
1062 ;
1063 break;}
1064case 45:
1065#line 364 "./vcc.y"
1066{
1067 lexPushMode(L_VTODO);
1068 if (!pushVObject(VCTodoProp)) YYERROR;
1069 ;
1070 break;}
1071case 46:
1072#line 369 "./vcc.y"
1073{
1074 lexPopMode(0);
1075 popVObject();
1076 ;
1077 break;}
1078}
1079 /* the action file gets copied in in place of this dollarsign */
1080#line 543 "/usr/share/bison.simple"
1081
1082 yyvsp -= yylen;
1083 yyssp -= yylen;
1084#ifdef YYLSP_NEEDED
1085 yylsp -= yylen;
1086#endif
1087
1088#if YYDEBUG != 0
1089 if (yydebug)
1090 {
1091 short *ssp1 = yyss - 1;
1092 fprintf (stderr, "state stack now");
1093 while (ssp1 != yyssp)
1094 fprintf (stderr, " %d", *++ssp1);
1095 fprintf (stderr, "\n");
1096 }
1097#endif
1098
1099 *++yyvsp = yyval;
1100
1101#ifdef YYLSP_NEEDED
1102 yylsp++;
1103 if (yylen == 0)
1104 {
1105 yylsp->first_line = yylloc.first_line;
1106 yylsp->first_column = yylloc.first_column;
1107 yylsp->last_line = (yylsp-1)->last_line;
1108 yylsp->last_column = (yylsp-1)->last_column;
1109 yylsp->text = 0;
1110 }
1111 else
1112 {
1113 yylsp->last_line = (yylsp+yylen-1)->last_line;
1114 yylsp->last_column = (yylsp+yylen-1)->last_column;
1115 }
1116#endif
1117
1118 /* Now "shift" the result of the reduction.
1119 Determine what state that goes to,
1120 based on the state we popped back to
1121 and the rule number reduced by. */
1122
1123 yyn = yyr1[yyn];
1124
1125 yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
1126 if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
1127 yystate = yytable[yystate];
1128 else
1129 yystate = yydefgoto[yyn - YYNTBASE];
1130
1131 goto yynewstate;
1132
1133yyerrlab: /* here on detecting error */
1134
1135 if (! yyerrstatus)
1136 /* If not already recovering from an error, report this error. */
1137 {
1138 ++yynerrs;
1139
1140#ifdef YYERROR_VERBOSE
1141 yyn = yypact[yystate];
1142
1143 if (yyn > YYFLAG && yyn < YYLAST)
1144 {
1145 int size = 0;
1146 char *msg;
1147 int x, count;
1148
1149 count = 0;
1150 /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
1151 for (x = (yyn < 0 ? -yyn : 0);
1152 x < (sizeof(yytname) / sizeof(char *)); x++)
1153 if (yycheck[x + yyn] == x)
1154 size += strlen(yytname[x]) + 15, count++;
1155 msg = (char *) malloc(size + 15);
1156 if (msg != 0)
1157 {
1158 strcpy(msg, "parse error");
1159
1160 if (count < 5)
1161 {
1162 count = 0;
1163 for (x = (yyn < 0 ? -yyn : 0);
1164 x < (sizeof(yytname) / sizeof(char *)); x++)
1165 if (yycheck[x + yyn] == x)
1166 {
1167 strcat(msg, count == 0 ? ", expecting `" : " or `");
1168 strcat(msg, yytname[x]);
1169 strcat(msg, "'");
1170 count++;
1171 }
1172 }
1173 yyerror(msg);
1174 free(msg);
1175 }
1176 else
1177 yyerror ("parse error; also virtual memory exceeded");
1178 }
1179 else
1180#endif /* YYERROR_VERBOSE */
1181 yyerror("parse error");
1182 }
1183
1184 goto yyerrlab1;
1185yyerrlab1: /* here on error raised explicitly by an action */
1186
1187 if (yyerrstatus == 3)
1188 {
1189 /* if just tried and failed to reuse lookahead token after an error, discard it. */
1190
1191 /* return failure if at end of input */
1192 if (yychar == YYEOF)
1193 YYABORT;
1194
1195#if YYDEBUG != 0
1196 if (yydebug)
1197 fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
1198#endif
1199
1200 yychar = YYEMPTY;
1201 }
1202
1203 /* Else will try to reuse lookahead token
1204 after shifting the error token. */
1205
1206 yyerrstatus = 3; /* Each real token shifted decrements this */
1207
1208 goto yyerrhandle;
1209
1210yyerrdefault: /* current state does not do anything special for the error token. */
1211
1212#if 0
1213 /* This is wrong; only states that explicitly want error tokens
1214 should shift them. */
1215 yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
1216 if (yyn) goto yydefault;
1217#endif
1218
1219yyerrpop: /* pop the current state because it cannot handle the error token */
1220
1221 if (yyssp == yyss) YYABORT;
1222 yyvsp--;
1223 yystate = *--yyssp;
1224#ifdef YYLSP_NEEDED
1225 yylsp--;
1226#endif
1227
1228#if YYDEBUG != 0
1229 if (yydebug)
1230 {
1231 short *ssp1 = yyss - 1;
1232 fprintf (stderr, "Error: state stack now");
1233 while (ssp1 != yyssp)
1234 fprintf (stderr, " %d", *++ssp1);
1235 fprintf (stderr, "\n");
1236 }
1237#endif
1238
1239yyerrhandle:
1240
1241 yyn = yypact[yystate];
1242 if (yyn == YYFLAG)
1243 goto yyerrdefault;
1244
1245 yyn += YYTERROR;
1246 if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
1247 goto yyerrdefault;
1248
1249 yyn = yytable[yyn];
1250 if (yyn < 0)
1251 {
1252 if (yyn == YYFLAG)
1253 goto yyerrpop;
1254 yyn = -yyn;
1255 goto yyreduce;
1256 }
1257 else if (yyn == 0)
1258 goto yyerrpop;
1259
1260 if (yyn == YYFINAL)
1261 YYACCEPT;
1262
1263#if YYDEBUG != 0
1264 if (yydebug)
1265 fprintf(stderr, "Shifting error token, ");
1266#endif
1267
1268 *++yyvsp = yylval;
1269#ifdef YYLSP_NEEDED
1270 *++yylsp = yylloc;
1271#endif
1272
1273 yystate = yyn;
1274 goto yynewstate;
1275
1276 yyacceptlab:
1277 /* YYACCEPT comes here. */
1278 if (yyfree_stacks)
1279 {
1280 free (yyss);
1281 free (yyvs);
1282#ifdef YYLSP_NEEDED
1283 free (yyls);
1284#endif
1285 }
1286 return 0;
1287
1288 yyabortlab:
1289 /* YYABORT comes here. */
1290 if (yyfree_stacks)
1291 {
1292 free (yyss);
1293 free (yyvs);
1294#ifdef YYLSP_NEEDED
1295 free (yyls);
1296#endif
1297 }
1298 return 1;
1299}
1300#line 375 "./vcc.y"
1301
1302/****************************************************************************/
1303static int pushVObject(const char *prop)
1304 {
1305 VObject *newObj;
1306 if (ObjStackTop == MAXLEVEL)
1307 return FALSE;
1308
1309 ObjStack[++ObjStackTop] = curObj;
1310
1311 if (curObj) {
1312 newObj = addProp(curObj,prop);
1313 curObj = newObj;
1314 }
1315 else
1316 curObj = newVObject(prop);
1317
1318 return TRUE;
1319 }
1320
1321
1322/****************************************************************************/
1323/* This pops the recently built vCard off the stack and returns it. */
1324static VObject* popVObject()
1325 {
1326 VObject *oldObj;
1327 if (ObjStackTop < 0) {
1328 yyerror("pop on empty Object Stack\n");
1329 return 0;
1330 }
1331 oldObj = curObj;
1332 curObj = ObjStack[ObjStackTop--];
1333
1334 return oldObj;
1335 }
1336
1337
1338/* static void enterValues(const char *value) */
1339/* { */
1340/* if (fieldedProp && *fieldedProp) { */
1341 /* if (value) { */
1342 /* addPropValue(curProp,*fieldedProp,value); */
1343 /* } */
1344 /* else this field is empty, advance to next field */
1345 /* fieldedProp++; */
1346 /* } */
1347/* else { */
1348 /* if (value) { */
1349 /* setVObjectUStringZValue_(curProp,fakeUnicode(value,0)); */
1350 /* } */
1351 /* } */
1352/* deleteStr(value); */
1353/* } */
1354
1355static void appendValue(const char *value)
1356{
1357 char *p1, *p2;
1358 wchar_t *p3;
1359 int i;
1360
1361 if (fieldedProp && *fieldedProp) {
1362 if (value) {
1363 addPropValue(curProp, *fieldedProp, value);
1364 }
1365 /* else this field is empty, advance to next field */
1366 fieldedProp++;
1367 } else {
1368 if (value) {
1369 if (vObjectUStringZValue(curProp)) {
1370 p1 = fakeCString(vObjectUStringZValue(curProp));
1371 p2 = malloc(sizeof(char *) * (strlen(p1)+strlen(value)+1));
1372 strcpy(p2, p1);
1373 deleteStr(p1);
1374
1375 i = strlen(p2);
1376 p2[i] = ',';
1377 p2[i+1] = '\0';
1378 p2 = strcat(p2, value);
1379 p3 = (wchar_t *) vObjectUStringZValue(curProp);
1380 free(p3);
1381 setVObjectUStringZValue_(curProp,fakeUnicode(p2,0));
1382 deleteStr(p2);
1383 } else {
1384 setVObjectUStringZValue_(curProp,fakeUnicode(value,0));
1385 }
1386 }
1387 }
1388 deleteStr(value);
1389}
1390
1391
1392static void enterProps(const char *s)
1393 {
1394 curProp = addGroup(curObj,s);
1395 deleteStr(s);
1396 }
1397
1398static void enterAttr(const char *s1, const char *s2)
1399 {
1400 const char *p1=0L, *p2=0L;
1401 p1 = lookupProp_(s1);
1402 if (s2) {
1403 VObject *a;
1404 p2 = lookupProp_(s2);
1405 a = addProp(curProp,p1);
1406 setVObjectStringZValue(a,p2);
1407 }
1408 else
1409 addProp(curProp,p1);
1410 if (strcasecmp(p1,VCBase64Prop) == 0 || (s2 && strcasecmp(p2,VCBase64Prop)==0))
1411 lexPushMode(L_BASE64);
1412 else if (strcasecmp(p1,VCQuotedPrintableProp) == 0
1413 || (s2 && strcasecmp(p2,VCQuotedPrintableProp)==0))
1414 lexPushMode(L_QUOTED_PRINTABLE);
1415 deleteStr(s1); deleteStr(s2);
1416 }
1417
1418
1419#define MAX_LEX_LOOKAHEAD_0 32
1420#define MAX_LEX_LOOKAHEAD 64
1421#define MAX_LEX_MODE_STACK_SIZE 10
1422#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
1423
1424struct LexBuf {
1425 /* input */
1426 FILE *inputFile;
1427 char *inputString;
1428 unsigned long curPos;
1429 unsigned long inputLen;
1430 /* lookahead buffer */
1431 /* -- lookahead buffer is short instead of char so that EOF
1432 / can be represented correctly.
1433 */
1434 unsigned long len;
1435 short buf[MAX_LEX_LOOKAHEAD];
1436 unsigned long getPtr;
1437 /* context stack */
1438 unsigned long lexModeStackTop;
1439 enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
1440 /* token buffer */
1441 unsigned long maxToken;
1442 char *strs;
1443 unsigned long strsLen;
1444 } lexBuf;
1445
1446static void lexPushMode(enum LexMode mode)
1447 {
1448 if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
1449 yyerror("lexical context stack overflow");
1450 else {
1451 lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
1452 }
1453 }
1454
1455static void lexPopMode(int top)
1456 {
1457 /* special case of pop for ease of error recovery -- this
1458 version will never underflow */
1459 if (top)
1460 lexBuf.lexModeStackTop = 0;
1461 else
1462 if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
1463 }
1464
1465static int lexWithinMode(enum LexMode mode) {
1466 unsigned long i;
1467 for (i=0;i<lexBuf.lexModeStackTop;i++)
1468 if (mode == lexBuf.lexModeStack[i]) return 1;
1469 return 0;
1470 }
1471
1472static int lexGetc_()
1473 {
1474 /* get next char from input, no buffering. */
1475 if (lexBuf.curPos == lexBuf.inputLen)
1476 return EOF;
1477 else if (lexBuf.inputString)
1478 return *(lexBuf.inputString + lexBuf.curPos++);
1479 else {
1480 if (!feof(lexBuf.inputFile))
1481 return fgetc(lexBuf.inputFile);
1482 else
1483 return EOF;
1484 }
1485 }
1486
1487static int lexGeta()
1488 {
1489 ++lexBuf.len;
1490 return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
1491 }
1492
1493static int lexGeta_(int i)
1494 {
1495 ++lexBuf.len;
1496 return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
1497 }
1498
1499static void lexSkipLookahead() {
1500 if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
1501 /* don't skip EOF. */
1502 lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
1503 lexBuf.len--;
1504 }
1505 }
1506
1507static int lexLookahead() {
1508 int c = (lexBuf.len)?
1509 lexBuf.buf[lexBuf.getPtr]:
1510 lexGeta();
1511 /* do the \r\n -> \n or \r -> \n translation here */
1512 if (c == '\r') {
1513 int a = (lexBuf.len>1)?
1514 lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
1515 lexGeta_(1);
1516 if (a == '\n') {
1517 lexSkipLookahead();
1518 }
1519 lexBuf.buf[lexBuf.getPtr] = c = '\n';
1520 }
1521 else if (c == '\n') {
1522 int a;
1523 if (lexBuf.len > 1)
1524 a = lexBuf.buf[lexBuf.getPtr];
1525 else
1526 a = lexGeta_(1);
1527 if (a == '\r') {
1528 lexSkipLookahead();
1529 }
1530 lexBuf.buf[lexBuf.getPtr] = '\n';
1531 }
1532 return c;
1533 }
1534
1535static int lexGetc() {
1536 int c = lexLookahead();
1537 if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
1538 /* EOF will remain in lookahead buffer */
1539 lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
1540 lexBuf.len--;
1541 }
1542 return c;
1543 }
1544
1545static void lexSkipLookaheadWord() {
1546 if (lexBuf.strsLen <= lexBuf.len) {
1547 lexBuf.len -= lexBuf.strsLen;
1548 lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
1549 }
1550 }
1551
1552static void lexClearToken()
1553 {
1554 lexBuf.strsLen = 0;
1555 }
1556
1557static void lexAppendc(int c)
1558 {
1559 /* not sure if I am doing this right to fix purify report -- PGB */
1560 lexBuf.strs = (char *) realloc(lexBuf.strs, (size_t) lexBuf.strsLen + 1);
1561 lexBuf.strs[lexBuf.strsLen] = c;
1562 /* append up to zero termination */
1563 if (c == 0) return;
1564 lexBuf.strsLen++;
1565 if (lexBuf.strsLen > lexBuf.maxToken) {
1566 /* double the token string size */
1567 lexBuf.maxToken <<= 1;
1568 lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
1569 }
1570 }
1571
1572static char* lexStr() {
1573 return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
1574 }
1575
1576static void lexSkipWhite() {
1577 int c = lexLookahead();
1578 while (c == ' ' || c == '\t') {
1579 lexSkipLookahead();
1580 c = lexLookahead();
1581 }
1582 }
1583
1584static char* lexGetWord() {
1585 int c;
1586 lexSkipWhite();
1587 lexClearToken();
1588 c = lexLookahead();
1589 /* some "words" have a space in them, like "NEEDS ACTION".
1590 this may be an oversight of the spec, but it is true nevertheless.
1591 while (c != EOF && !strchr("\t\n ;:=",c)) { */
1592 while (c != EOF && !strchr("\n;:=",c)) {
1593 lexAppendc(c);
1594 lexSkipLookahead();
1595 c = lexLookahead();
1596 }
1597 lexAppendc(0);
1598 return lexStr();
1599 }
1600
1601void lexPushLookahead(char *s, int len) {
1602 int putptr;
1603 if (len == 0) len = strlen(s);
1604 putptr = (int)lexBuf.getPtr - len;
1605 /* this function assumes that length of word to push back
1606 / is not greater than MAX_LEX_LOOKAHEAD.
1607 */
1608 if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
1609 lexBuf.getPtr = putptr;
1610 while (*s) {
1611 lexBuf.buf[putptr] = *s++;
1612 putptr = (putptr + 1) % MAX_LEX_LOOKAHEAD;
1613 }
1614 lexBuf.len += len;
1615 }
1616
1617static void lexPushLookaheadc(int c) {
1618 int putptr;
1619 /* can't putback EOF, because it never leaves lookahead buffer */
1620 if (c == EOF) return;
1621 putptr = (int)lexBuf.getPtr - 1;
1622 if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
1623 lexBuf.getPtr = putptr;
1624 lexBuf.buf[putptr] = c;
1625 lexBuf.len += 1;
1626 }
1627
1628static char* lexLookaheadWord() {
1629 /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
1630 / and thing bigger than that will stop the lookahead and return 0;
1631 / leading white spaces are not recoverable.
1632 */
1633 int c;
1634 int len = 0;
1635 int curgetptr = 0;
1636 lexSkipWhite();
1637 lexClearToken();
1638 curgetptr = (int)lexBuf.getPtr;/* remember! */
1639 while (len < (MAX_LEX_LOOKAHEAD_0)) {
1640 c = lexGetc();
1641 len++;
1642 if (c == EOF || strchr("\t\n ;:=", c)) {
1643 lexAppendc(0);
1644 /* restore lookahead buf. */
1645 lexBuf.len += len;
1646 lexBuf.getPtr = curgetptr;
1647 return lexStr();
1648 }
1649 else
1650 lexAppendc(c);
1651 }
1652 lexBuf.len += len;/* char that has been moved to lookahead buffer */
1653 lexBuf.getPtr = curgetptr;
1654 return 0;
1655 }
1656
1657#ifdef _SUPPORT_LINE_FOLDING
1658static void handleMoreRFC822LineBreak(int c) {
1659 /* suport RFC 822 line break in cases like
1660 *ADR: foo;
1661 * morefoo;
1662 * more foo;
1663 */
1664 if (c == ';') {
1665 int a;
1666 lexSkipLookahead();
1667 /* skip white spaces */
1668 a = lexLookahead();
1669 while (a == ' ' || a == '\t') {
1670 lexSkipLookahead();
1671 a = lexLookahead();
1672 }
1673 if (a == '\n') {
1674 lexSkipLookahead();
1675 a = lexLookahead();
1676 if (a == ' ' || a == '\t') {
1677 /* continuation, throw away all the \n and spaces read so
1678 * far
1679 */
1680 lexSkipWhite();
1681 lexPushLookaheadc(';');
1682 }
1683 else {
1684 lexPushLookaheadc('\n');
1685 lexPushLookaheadc(';');
1686 }
1687 }
1688 else {
1689 lexPushLookaheadc(';');
1690 }
1691 }
1692 }
1693
1694static char* lexGet1Value() {
1695 int c;
1696 lexSkipWhite();
1697 c = lexLookahead();
1698 lexClearToken();
1699 while (c != EOF && c != ';') {
1700 if (c == '\n') {
1701 int a;
1702 lexSkipLookahead();
1703 a = lexLookahead();
1704 if (a == ' ' || a == '\t') {
1705 lexAppendc(' ');
1706 lexSkipLookahead();
1707 }
1708 else {
1709 lexPushLookaheadc('\n');
1710 break;
1711 }
1712 }
1713 else {
1714 lexAppendc(c);
1715 lexSkipLookahead();
1716 }
1717 c = lexLookahead();
1718 }
1719 lexAppendc(0);
1720 handleMoreRFC822LineBreak(c);
1721 return c==EOF?0:lexStr();
1722 }
1723#endif
1724
1725char* lexGetStrUntil(char *termset) {
1726 int c = lexLookahead();
1727 lexClearToken();
1728 while (c != EOF && !strchr(termset,c)) {
1729 lexAppendc(c);
1730 lexSkipLookahead();
1731 c = lexLookahead();
1732 }
1733 lexAppendc(0);
1734 return c==EOF?0:lexStr();
1735 }
1736
1737static int match_begin_name(int end) {
1738 char *n = lexLookaheadWord();
1739 int token = ID;
1740 if (n) {
1741 if (!strcasecmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
1742 else if (!strcasecmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
1743 else if (!strcasecmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
1744 else if (!strcasecmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
1745 deleteStr(n);
1746 return token;
1747 }
1748 return 0;
1749 }
1750
1751
1752void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
1753 {
1754 /* initialize lex mode stack */
1755 lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
1756
1757 /* iniatialize lex buffer. */
1758 lexBuf.inputString = (char*) inputstring;
1759 lexBuf.inputLen = inputlen;
1760 lexBuf.curPos = 0;
1761 lexBuf.inputFile = inputfile;
1762
1763 lexBuf.len = 0;
1764 lexBuf.getPtr = 0;
1765
1766 lexBuf.maxToken = MAXTOKEN;
1767 lexBuf.strs = (char*)malloc(MAXTOKEN);
1768 lexBuf.strsLen = 0;
1769
1770 }
1771
1772static void finiLex() {
1773 free(lexBuf.strs);
1774 }
1775
1776
1777/****************************************************************************/
1778/* This parses and converts the base64 format for binary encoding into
1779 * a decoded buffer (allocated with new). See RFC 1521.
1780 */
1781static char * lexGetDataFromBase64()
1782 {
1783 unsigned long bytesLen = 0, bytesMax = 0;
1784 int quadIx = 0, pad = 0;
1785 unsigned long trip = 0;
1786 unsigned char b;
1787 int c;
1788 unsigned char *bytes = NULL;
1789 unsigned char *oldBytes = NULL;
1790
1791 DBG_(("db: lexGetDataFromBase64\n"));
1792 while (1) {
1793 c = lexGetc();
1794 if (c == '\n') {
1795 ++mime_lineNum;
1796 if (lexLookahead() == '\n') {
1797 /* a '\n' character by itself means end of data */
1798 break;
1799 }
1800 else continue; /* ignore '\n' */
1801 }
1802 else {
1803 if ((c >= 'A') && (c <= 'Z'))
1804 b = (unsigned char)(c - 'A');
1805 else if ((c >= 'a') && (c <= 'z'))
1806 b = (unsigned char)(c - 'a') + 26;
1807 else if ((c >= '0') && (c <= '9'))
1808 b = (unsigned char)(c - '0') + 52;
1809 else if (c == '+')
1810 b = 62;
1811 else if (c == '/')
1812 b = 63;
1813 else if (c == '=') {
1814 b = 0;
1815 pad++;
1816 } else if ((c == ' ') || (c == '\t')) {
1817 continue;
1818 } else { /* error condition */
1819 if (bytes) free(bytes);
1820 else if (oldBytes) free(oldBytes);
1821 /* error recovery: skip until 2 adjacent newlines. */
1822 DBG_(("db: invalid character 0x%x '%c'\n", c,c));
1823 if (c != EOF) {
1824 c = lexGetc();
1825 while (c != EOF) {
1826 if (c == '\n' && lexLookahead() == '\n') {
1827 ++mime_lineNum;
1828 break;
1829 }
1830 c = lexGetc();
1831 }
1832 }
1833 return NULL;
1834 }
1835 trip = (trip << 6) | b;
1836 if (++quadIx == 4) {
1837 unsigned char outBytes[3];
1838 int numOut;
1839 int i;
1840 for (i = 0; i < 3; i++) {
1841 outBytes[2-i] = (unsigned char)(trip & 0xFF);
1842 trip >>= 8;
1843 }
1844 numOut = 3 - pad;
1845 if (bytesLen + numOut > bytesMax) {
1846 if (!bytes) {
1847 bytesMax = 1024;
1848 bytes = (unsigned char*)malloc((size_t)bytesMax);
1849 }
1850 else {
1851 bytesMax <<= 2;
1852 oldBytes = bytes;
1853 bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
1854 }
1855 if (bytes == 0) {
1856 mime_error("out of memory while processing BASE64 data\n");
1857 }
1858 }
1859 if (bytes) {
1860 memcpy(bytes + bytesLen, outBytes, numOut);
1861 bytesLen += numOut;
1862 }
1863 trip = 0;
1864 quadIx = 0;
1865 }
1866 }
1867 } /* while */
1868 DBG_(("db: bytesLen = %d\n", bytesLen));
1869 /* kludge: all this won't be necessary if we have tree form
1870 representation */
1871 if (bytes) {
1872 setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
1873 free(bytes);
1874 }
1875 else if (oldBytes) {
1876 setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
1877 free(oldBytes);
1878 }
1879 return 0;
1880 }
1881
1882static int match_begin_end_name(int end) {
1883 int token;
1884 lexSkipWhite();
1885 if (lexLookahead() != ':') return ID;
1886 lexSkipLookahead();
1887 lexSkipWhite();
1888 token = match_begin_name(end);
1889 if (token == ID) {
1890 lexPushLookaheadc(':');
1891 DBG_(("db: ID '%s'\n", yylval.str));
1892 return ID;
1893 }
1894 else if (token != 0) {
1895 lexSkipLookaheadWord();
1896 deleteStr(yylval.str);
1897 DBG_(("db: begin/end %d\n", token));
1898 return token;
1899 }
1900 return 0;
1901 }
1902
1903static char* lexGetQuotedPrintable()
1904 {
1905 char cur;
1906
1907 lexClearToken();
1908 do {
1909 cur = lexGetc();
1910 switch (cur) {
1911 case '=': {
1912 int c = 0;
1913 int next[2];
1914 int i;
1915 for (i = 0; i < 2; i++) {
1916 next[i] = lexGetc();
1917 if (next[i] >= '0' && next[i] <= '9')
1918 c = c * 16 + next[i] - '0';
1919 else if (next[i] >= 'A' && next[i] <= 'F')
1920 c = c * 16 + next[i] - 'A' + 10;
1921 else
1922 break;
1923 }
1924 if (i == 0) {
1925 /* single '=' follow by LINESEP is continuation sign? */
1926 if (next[0] == '\n') {
1927 ++mime_lineNum;
1928 }
1929 else {
1930 lexPushLookaheadc('=');
1931 goto EndString;
1932 }
1933 }
1934 else if (i == 1) {
1935 lexPushLookaheadc(next[1]);
1936 lexPushLookaheadc(next[0]);
1937 lexAppendc('=');
1938 } else {
1939 lexAppendc(c);
1940 }
1941 break;
1942 } /* '=' */
1943 case '\n': {
1944 lexPushLookaheadc('\n');
1945 goto EndString;
1946 }
1947 case (char)EOF:
1948 break;
1949 default:
1950 lexAppendc(cur);
1951 break;
1952 } /* switch */
1953 } while (cur != (char)EOF);
1954
1955EndString:
1956 lexAppendc(0);
1957 return lexStr();
1958 } /* LexQuotedPrintable */
1959
1960static int yylex() {
1961
1962 int lexmode = LEXMODE();
1963 if (lexmode == L_VALUES) {
1964 int c = lexGetc();
1965 if (c == ';') {
1966 DBG_(("db: SEMICOLON\n"));
1967 lexPushLookaheadc(c);
1968 handleMoreRFC822LineBreak(c);
1969 lexSkipLookahead();
1970 return SEMICOLON;
1971 }
1972 else if (strchr("\n",c)) {
1973 ++mime_lineNum;
1974 /* consume all line separator(s) adjacent to each other */
1975 c = lexLookahead();
1976 while (strchr("\n",c)) {
1977 lexSkipLookahead();
1978 c = lexLookahead();
1979 ++mime_lineNum;
1980 }
1981 DBG_(("db: LINESEP\n"));
1982 return LINESEP;
1983 }
1984 else {
1985 char *p = 0;
1986 lexPushLookaheadc(c);
1987 if (lexWithinMode(L_BASE64)) {
1988 /* get each char and convert to bin on the fly... */
1989 p = lexGetDataFromBase64();
1990 yylval.str = p;
1991 return STRING;
1992 }
1993 else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
1994 p = lexGetQuotedPrintable();
1995 }
1996 else {
1997#ifdef _SUPPORT_LINE_FOLDING
1998 p = lexGet1Value();
1999#else
2000 p = lexGetStrUntil(";\n");
2001#endif
2002 }
2003 if (p) {
2004 DBG_(("db: STRING: '%s'\n", p));
2005 yylval.str = p;
2006 return STRING;
2007 }
2008 else return 0;
2009 }
2010 }
2011
2012 else {
2013 /* normal mode */
2014 while (1) {
2015 int c = lexGetc();
2016 switch(c) {
2017 case ':': {
2018 /* consume all line separator(s) adjacent to each other */
2019 /* ignoring linesep immediately after colon. */
2020 c = lexLookahead();
2021 while (strchr("\n",c)) {
2022 lexSkipLookahead();
2023 c = lexLookahead();
2024 ++mime_lineNum;
2025 }
2026 DBG_(("db: COLON\n"));
2027 return COLON;
2028 }
2029 case ';':
2030 DBG_(("db: SEMICOLON\n"));
2031 return SEMICOLON;
2032 case '=':
2033 DBG_(("db: EQ\n"));
2034 return EQ;
2035 /* ignore tabs/newlines in this mode. We can't ignore
2036 * spaces, because values like NEEDS ACTION have a space. */
2037 case '\t': continue;
2038 case '\n': {
2039 ++mime_lineNum;
2040 continue;
2041 }
2042 case EOF: return 0;
2043 break;
2044 default: {
2045 lexPushLookaheadc(c);
2046 /* pending lutz : why linker error with isalpha(c)? */
2047 /*if ( isalpha(c) || c == ' ') { */
2048 if ( ( c >= 'A' && c <= 'Z') || ( c >= 'a' && c <= 'z') || c == ' ') {
2049
2050 char *t = lexGetWord();
2051 yylval.str = t;
2052 if (!strcasecmp(t, "begin")) {
2053 return match_begin_end_name(0);
2054 }
2055 else if (!strcasecmp(t,"end")) {
2056 return match_begin_end_name(1);
2057 }
2058 else {
2059 DBG_(("db: ID '%s'\n", t));
2060 return ID;
2061 }
2062 }
2063 else {
2064 /* unknown token */
2065 return 0;
2066 }
2067 break;
2068 }
2069 }
2070 }
2071 }
2072
2073 return 0;
2074 }
2075
2076
2077/***************************************************************************/
2078 /*** Public Functions ****/
2079/***************************************************************************/
2080
2081static VObject* Parse_MIMEHelper()
2082 {
2083 ObjStackTop = -1;
2084 mime_numErrors = 0;
2085 mime_lineNum = 1;
2086 vObjList = 0;
2087 curObj = 0;
2088
2089 if (yyparse() != 0)
2090 return 0;
2091
2092 finiLex();
2093 return vObjList;
2094 }
2095
2096/****************************************************************************/
2097VObject* Parse_MIME(const char *input, unsigned long len)
2098 {
2099 initLex(input, len, 0);
2100 return Parse_MIMEHelper();
2101 }
2102
2103
2104VObject* Parse_MIME_FromFile(FILE *file)
2105 {
2106 VObject *result;
2107 long startPos;
2108
2109 initLex(0,(unsigned long)-1,file);
2110 startPos = ftell(file);
2111 if (!(result = Parse_MIMEHelper())) {
2112 fseek(file,startPos,SEEK_SET);
2113 }
2114 return result;
2115 }
2116
2117VObject* Parse_MIME_FromFileName(const char *fname)
2118 {
2119 FILE *fp = fopen(fname,"r");
2120 if (fp) {
2121 VObject* o = Parse_MIME_FromFile(fp);
2122 fclose(fp);
2123 return o;
2124 }
2125 else {
2126 char msg[255];
2127 sprintf(msg, "can't open file '%s' for reading\n", fname);
2128 mime_error_(msg);
2129 return 0;
2130 }
2131 }
2132
2133/****************************************************************************/
2134void YYDebug(const char *s)
2135{
2136 Parse_Debug(s);
2137}
2138
2139
2140static MimeErrorHandler mimeErrorHandler;
2141
2142void registerMimeErrorHandler(MimeErrorHandler me)
2143 {
2144 mimeErrorHandler = me;
2145 }
2146
2147static void mime_error(char *s)
2148 {
2149 char msg[256];
2150 if (mimeErrorHandler) {
2151 sprintf(msg,"%s at line %d", s, mime_lineNum);
2152 mimeErrorHandler(msg);
2153 }
2154 }
2155
2156static void mime_error_(char *s)
2157 {
2158 if (mimeErrorHandler) {
2159 mimeErrorHandler(s);
2160 }
2161 }
2162
diff --git a/libkcal/versit/vcc.h b/libkcal/versit/vcc.h
new file mode 100644
index 0000000..03886d1
--- a/dev/null
+++ b/libkcal/versit/vcc.h
@@ -0,0 +1,76 @@
1/***************************************************************************
2(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
3Business Machines Corporation and Siemens Rolm Communications Inc.
4
5For purposes of this license notice, the term Licensors shall mean,
6collectively, Apple Computer, Inc., AT&T Corp., International
7Business Machines Corporation and Siemens Rolm Communications Inc.
8The term Licensor shall mean any of the Licensors.
9
10Subject to acceptance of the following conditions, permission is hereby
11granted by Licensors without the need for written agreement and without
12license or royalty fees, to use, copy, modify and distribute this
13software for any purpose.
14
15The above copyright notice and the following four paragraphs must be
16reproduced in all copies of this software and any software including
17this software.
18
19THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
20ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
21MODIFICATIONS.
22
23IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
24INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
25OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26DAMAGE.
27
28EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
29INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
30IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31PURPOSE.
32
33The software is provided with RESTRICTED RIGHTS. Use, duplication, or
34disclosure by the government are subject to restrictions set forth in
35DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
36
37***************************************************************************/
38
39#ifndef __VCC_H__
40#define __VCC_H__ 1
41
42#include "vobject.h"
43
44
45#if defined(__CPLUSPLUS__) || defined(__cplusplus)
46extern "C" {
47#endif
48
49typedef void (*MimeErrorHandler)(char *);
50
51extern void registerMimeErrorHandler(MimeErrorHandler);
52
53extern VObject* Parse_MIME(const char *input, unsigned long len);
54extern VObject* Parse_MIME_FromFileName(const char* fname);
55
56
57/* NOTE regarding Parse_MIME_FromFile
58The function below, Parse_MIME_FromFile, come in two flavors,
59neither of which is exported from the DLL. Each version takes
60a CFile or FILE* as a parameter, neither of which can be
61passed across a DLL interface (at least that is my experience).
62If you are linking this code into your build directly then
63you may find them a more convenient API that the other flavors
64that take a file name. If you use them with the DLL LIB you
65will get a link error.
66*/
67
68
69extern VObject* Parse_MIME_FromFile(FILE *file);
70
71#if defined(__CPLUSPLUS__) || defined(__cplusplus)
72}
73#endif
74
75#endif /* __VCC_H__ */
76
diff --git a/libkcal/versit/versit.pro b/libkcal/versit/versit.pro
new file mode 100644
index 0000000..915c25c
--- a/dev/null
+++ b/libkcal/versit/versit.pro
@@ -0,0 +1,15 @@
1 TEMPLATE= lib
2 CONFIG = qt warn_on release
3 TARGET = versit
4INTERFACES = \
5
6HEADERS = \
7 port.h \
8 vcc.h \
9 vobject.h \
10
11SOURCES = \
12 \ \
13 vcc.c \
14 vobject.c \
15
diff --git a/libkcal/versit/versit.pro.back b/libkcal/versit/versit.pro.back
new file mode 100644
index 0000000..915c25c
--- a/dev/null
+++ b/libkcal/versit/versit.pro.back
@@ -0,0 +1,15 @@
1 TEMPLATE= lib
2 CONFIG = qt warn_on release
3 TARGET = versit
4INTERFACES = \
5
6HEADERS = \
7 port.h \
8 vcc.h \
9 vobject.h \
10
11SOURCES = \
12 \ \
13 vcc.c \
14 vobject.c \
15
diff --git a/libkcal/versit/vobject.c b/libkcal/versit/vobject.c
new file mode 100644
index 0000000..637efb2
--- a/dev/null
+++ b/libkcal/versit/vobject.c
@@ -0,0 +1,1433 @@
1/***************************************************************************
2(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
3Business Machines Corporation and Siemens Rolm Communications Inc.
4
5For purposes of this license notice, the term Licensors shall mean,
6collectively, Apple Computer, Inc., AT&T Corp., International
7Business Machines Corporation and Siemens Rolm Communications Inc.
8The term Licensor shall mean any of the Licensors.
9
10Subject to acceptance of the following conditions, permission is hereby
11granted by Licensors without the need for written agreement and without
12license or royalty fees, to use, copy, modify and distribute this
13software for any purpose.
14
15The above copyright notice and the following four paragraphs must be
16reproduced in all copies of this software and any software including
17this software.
18
19THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
20ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
21MODIFICATIONS.
22
23IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
24INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
25OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26DAMAGE.
27
28EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
29INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
30IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31PURPOSE.
32
33The software is provided with RESTRICTED RIGHTS. Use, duplication, or
34disclosure by the government are subject to restrictions set forth in
35DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
36
37***************************************************************************/
38
39/*
40 * src: vobject.c
41 * doc: vobject and APIs to construct vobject, APIs pretty print
42 * vobject, and convert a vobject into its textual representation.
43 */
44
45#include <stdlib.h>
46
47#include "vobject.h"
48#include <string.h>
49#include <stdio.h>
50#ifdef _WIN32_
51
52 #define strcasecmp _stricmp
53
54#endif
55
56 #define NAME_OF(o) o->id
57 #define VALUE_TYPE(o) o->valType
58 #define STRINGZ_VALUE_OF(o) o->val.strs
59 #define USTRINGZ_VALUE_OF(o)o->val.ustrs
60 #define INTEGER_VALUE_OF(o) o->val.i
61 #define LONG_VALUE_OF(o) o->val.l
62 #define ANY_VALUE_OF(o) o->val.any
63 #define VOBJECT_VALUE_OF(o) o->val.vobj
64
65const char** fieldedProp;
66
67
68
69/*----------------------------------------------------------------------
70 The following functions involve with memory allocation:
71 newVObject
72 deleteVObject
73 dupStr
74 deleteStr
75 newStrItem
76 deleteStrItem
77 ----------------------------------------------------------------------*/
78
79VObject* newVObject_(const char *id)
80{
81 VObject *p = (VObject*)malloc(sizeof(VObject));
82 p->next = 0;
83 p->id = id;
84 p->prop = 0;
85 VALUE_TYPE(p) = 0;
86 ANY_VALUE_OF(p) = 0;
87 return p;
88}
89
90VObject* newVObject(const char *id)
91{
92 return newVObject_(lookupStr(id));
93}
94
95void deleteVObject(VObject *p)
96{
97 if (p->id)
98 unUseStr(p->id);
99 if (p)
100 free(p);
101 p = NULL;
102}
103
104char* dupStr(const char *s, unsigned int size)
105{
106 char *t;
107 if (size == 0) {
108 size = strlen(s);
109 }
110 t = (char*)malloc(size+1);
111 if (t) {
112 memcpy(t,s,size);
113 t[size] = 0;
114 return t;
115 }
116 else {
117 return (char*)0;
118 }
119}
120
121void deleteStr(const char *p)
122{
123 if (p)
124 free((void*)p);
125 p = NULL;
126}
127
128
129static StrItem* newStrItem(const char *s, StrItem *next)
130{
131 StrItem *p = (StrItem*)malloc(sizeof(StrItem));
132 p->next = next;
133 p->s = s;
134 p->refCnt = 1;
135 return p;
136}
137
138static void deleteStrItem(StrItem *p)
139{
140 if (p)
141 free((void*)p);
142 p = NULL;
143}
144
145
146/*----------------------------------------------------------------------
147 The following function provide accesses to VObject's value.
148 ----------------------------------------------------------------------*/
149
150const char* vObjectName(VObject *o)
151{
152 return NAME_OF(o);
153}
154
155void setVObjectName(VObject *o, const char* id)
156{
157 NAME_OF(o) = id;
158}
159
160const char* vObjectStringZValue(VObject *o)
161{
162 return STRINGZ_VALUE_OF(o);
163}
164
165void setVObjectStringZValue(VObject *o, const char *s)
166{
167 STRINGZ_VALUE_OF(o) = dupStr(s,0);
168 VALUE_TYPE(o) = VCVT_STRINGZ;
169}
170
171void setVObjectStringZValue_(VObject *o, const char *s)
172{
173 STRINGZ_VALUE_OF(o) = s;
174 VALUE_TYPE(o) = VCVT_STRINGZ;
175}
176
177const wchar_t* vObjectUStringZValue(VObject *o)
178{
179 return USTRINGZ_VALUE_OF(o);
180}
181
182void setVObjectUStringZValue(VObject *o, const wchar_t *s)
183{
184 USTRINGZ_VALUE_OF(o) = (wchar_t*) dupStr((char*)s,(uStrLen(s)+1)*2);
185 VALUE_TYPE(o) = VCVT_USTRINGZ;
186}
187
188void setVObjectUStringZValue_(VObject *o, const wchar_t *s)
189{
190 USTRINGZ_VALUE_OF(o) = s;
191 VALUE_TYPE(o) = VCVT_USTRINGZ;
192}
193
194unsigned int vObjectIntegerValue(VObject *o)
195{
196 return INTEGER_VALUE_OF(o);
197}
198
199void setVObjectIntegerValue(VObject *o, unsigned int i)
200{
201 INTEGER_VALUE_OF(o) = i;
202 VALUE_TYPE(o) = VCVT_UINT;
203}
204
205unsigned long vObjectLongValue(VObject *o)
206{
207 return LONG_VALUE_OF(o);
208}
209
210void setVObjectLongValue(VObject *o, unsigned long l)
211{
212 LONG_VALUE_OF(o) = l;
213 VALUE_TYPE(o) = VCVT_ULONG;
214}
215
216void* vObjectAnyValue(VObject *o)
217{
218 return ANY_VALUE_OF(o);
219}
220
221void setVObjectAnyValue(VObject *o, void *t)
222{
223 ANY_VALUE_OF(o) = t;
224 VALUE_TYPE(o) = VCVT_RAW;
225}
226
227VObject* vObjectVObjectValue(VObject *o)
228{
229 return VOBJECT_VALUE_OF(o);
230}
231
232void setVObjectVObjectValue(VObject *o, VObject *p)
233{
234 VOBJECT_VALUE_OF(o) = p;
235 VALUE_TYPE(o) = VCVT_VOBJECT;
236}
237
238int vObjectValueType(VObject *o)
239{
240 return VALUE_TYPE(o);
241}
242
243
244/*----------------------------------------------------------------------
245 The following functions can be used to build VObject.
246 ----------------------------------------------------------------------*/
247
248VObject* addVObjectProp(VObject *o, VObject *p)
249{
250 /* circular link list pointed to tail */
251 /*
252 o {next,id,prop,val}
253 V
254 pn {next,id,prop,val}
255 V
256 ...
257 p1 {next,id,prop,val}
258 V
259 pn
260 -->
261 o {next,id,prop,val}
262 V
263 pn {next,id,prop,val}
264 V
265 p {next,id,prop,val}
266 ...
267 p1 {next,id,prop,val}
268 V
269 pn
270 */
271
272 VObject *tail = o->prop;
273 if (tail) {
274 p->next = tail->next;
275 o->prop = tail->next = p;
276 }
277 else {
278 o->prop = p->next = p;
279 }
280 return p;
281}
282
283VObject* addProp(VObject *o, const char *id)
284{
285 return addVObjectProp(o,newVObject(id));
286}
287
288VObject* addProp_(VObject *o, const char *id)
289{
290 return addVObjectProp(o,newVObject_(id));
291}
292
293void addList(VObject **o, VObject *p)
294{
295 p->next = 0;
296 if (*o == 0) {
297 *o = p;
298 }
299 else {
300 VObject *t = *o;
301 while (t->next) {
302 t = t->next;
303 }
304 t->next = p;
305 }
306}
307
308VObject* nextVObjectInList(VObject *o)
309{
310 return o->next;
311}
312
313VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size)
314{
315 VObject *sizeProp;
316 setVObjectAnyValue(prop, val);
317 sizeProp = addProp(prop,VCDataSizeProp);
318 setVObjectLongValue(sizeProp, size);
319 return prop;
320}
321
322VObject* setValueWithSize(VObject *prop, void *val, unsigned int size)
323{
324 void *p = dupStr(val,size);
325 return setValueWithSize_(prop,p,p?size:0);
326}
327
328void initPropIterator(VObjectIterator *i, VObject *o)
329{
330 i->start = o->prop;
331 i->next = 0;
332}
333
334void initVObjectIterator(VObjectIterator *i, VObject *o)
335{
336 i->start = o->next;
337 i->next = 0;
338}
339
340int moreIteration(VObjectIterator *i)
341{
342 return (i->start && (i->next==0 || i->next!=i->start));
343}
344
345VObject* nextVObject(VObjectIterator *i)
346{
347 if (i->start && i->next != i->start) {
348 if (i->next == 0) {
349 i->next = i->start->next;
350 return i->next;
351 }
352 else {
353 i->next = i->next->next;
354 return i->next;
355 }
356 }
357 else return (VObject*)0;
358}
359
360VObject* isAPropertyOf(VObject *o, const char *id)
361{
362 VObjectIterator i;
363 initPropIterator(&i,o);
364 while (moreIteration(&i)) {
365 VObject *each = nextVObject(&i);
366 if (!strcasecmp(id,each->id))
367 return each;
368 }
369 return (VObject*)0;
370}
371
372VObject* addGroup(VObject *o, const char *g)
373{
374 /*
375 a.b.c
376 -->
377 prop(c)
378 prop(VCGrouping=b)
379 prop(VCGrouping=a)
380 */
381 char *dot = strrchr(g,'.');
382 if (dot) {
383 VObject *p, *t;
384 char *gs, *n = dot+1;
385 gs = dupStr(g,0);/* so we can write to it. */
386 /* used to be
387 * t = p = addProp_(o,lookupProp_(n));
388 */
389 t = p = addProp_(o,lookupProp(n));
390 dot = strrchr(gs,'.');
391 *dot = 0;
392 do {
393 dot = strrchr(gs,'.');
394 if (dot) {
395 n = dot+1;
396 *dot=0;
397 }
398 else
399 n = gs;
400 /* property(VCGroupingProp=n);
401 *and the value may have VCGrouping property
402 */
403 t = addProp(t,VCGroupingProp);
404 setVObjectStringZValue(t,lookupProp_(n));
405 } while (n != gs);
406 deleteStr(gs);
407 return p;
408 }
409 else
410 return addProp_(o,lookupProp(g));
411}
412
413VObject* addPropValue(VObject *o, const char *p, const char *v)
414{
415 VObject *prop;
416 prop = addProp(o,p);
417 setVObjectUStringZValue_(prop, fakeUnicode(v,0));
418 return prop;
419}
420
421VObject* addPropSizedValue_(VObject *o, const char *p, const char *v,
422 unsigned int size)
423{
424 VObject *prop;
425 prop = addProp(o,p);
426 setValueWithSize_(prop, (void*)v, size);
427 return prop;
428}
429
430VObject* addPropSizedValue(VObject *o, const char *p, const char *v,
431 unsigned int size)
432{
433 return addPropSizedValue_(o,p,dupStr(v,size),size);
434}
435
436
437
438/*----------------------------------------------------------------------
439 The following pretty print a VObject
440 ----------------------------------------------------------------------*/
441
442static void printVObject_(FILE *fp, VObject *o, int level);
443
444static void indent(FILE *fp, int level)
445{
446 int i;
447 for (i=0;i<level*4;i++) {
448 fputc(' ', fp);
449 }
450}
451
452static void printValue(FILE *fp, VObject *o, int level)
453{
454 switch (VALUE_TYPE(o)) {
455 case VCVT_USTRINGZ: {
456 char c;
457 char *t,*s;
458 s = t = fakeCString(USTRINGZ_VALUE_OF(o));
459 fputc('"',fp);
460 while (c=*t,c) {
461 fputc(c,fp);
462 if (c == '\n') indent(fp,level+2);
463 t++;
464 }
465 fputc('"',fp);
466 deleteStr(s);
467 break;
468 }
469 case VCVT_STRINGZ: {
470 char c;
471 const char *s = STRINGZ_VALUE_OF(o);
472 fputc('"',fp);
473 while (c=*s,c) {
474 fputc(c,fp);
475 if (c == '\n') indent(fp,level+2);
476 s++;
477 }
478 fputc('"',fp);
479 break;
480 }
481 case VCVT_UINT:
482 fprintf(fp,"%d", INTEGER_VALUE_OF(o)); break;
483 case VCVT_ULONG:
484 fprintf(fp,"%ld", LONG_VALUE_OF(o)); break;
485 case VCVT_RAW:
486 fprintf(fp,"[raw data]"); break;
487 case VCVT_VOBJECT:
488 fprintf(fp,"[vobject]\n");
489 printVObject_(fp,VOBJECT_VALUE_OF(o),level+1);
490 break;
491 case 0:
492 fprintf(fp,"[none]"); break;
493 default:
494 fprintf(fp,"[unknown]"); break;
495 }
496}
497
498static void printNameValue(FILE *fp,VObject *o, int level)
499{
500 indent(fp,level);
501 if (NAME_OF(o)) {
502 fprintf(fp,"%s", NAME_OF(o));
503 }
504 if (VALUE_TYPE(o)) {
505 fputc('=',fp);
506 printValue(fp,o, level);
507 }
508 fprintf(fp,"\n");
509}
510
511static void printVObject_(FILE *fp, VObject *o, int level)
512 {
513 VObjectIterator t;
514 if (o == 0) {
515 fprintf(fp,"[NULL]\n");
516 return;
517 }
518 printNameValue(fp,o,level);
519 initPropIterator(&t,o);
520 while (moreIteration(&t)) {
521 VObject *eachProp = nextVObject(&t);
522 printVObject_(fp,eachProp,level+1);
523 }
524 }
525
526void printVObject(FILE *fp,VObject *o)
527{
528 printVObject_(fp,o,0);
529}
530
531void printVObjectToFile(char *fname,VObject *o)
532{
533 FILE *fp = fopen(fname,"w");
534 if (fp) {
535 printVObject(fp,o);
536 fclose(fp);
537 }
538}
539
540void printVObjectsToFile(char *fname,VObject *list)
541{
542 FILE *fp = fopen(fname,"w");
543 if (fp) {
544 while (list) {
545 printVObject(fp,list);
546 list = nextVObjectInList(list);
547 }
548 fclose(fp);
549 }
550}
551
552void cleanVObject(VObject *o)
553{
554 if (o == 0) return;
555 if (o->prop) {
556 /* destroy time: cannot use the iterator here.
557 Have to break the cycle in the circular link
558 list and turns it into regular NULL-terminated
559 list -- since at some point of destruction,
560 the reference entry for the iterator to work
561 will not longer be valid.
562 */
563 VObject *p;
564 p = o->prop->next;
565 o->prop->next = 0;
566 do {
567 VObject *t = p->next;
568 cleanVObject(p);
569 p = t;
570 } while (p);
571 }
572 switch (VALUE_TYPE(o)) {
573 case VCVT_USTRINGZ:
574 case VCVT_STRINGZ:
575 case VCVT_RAW:
576 /* assume they are all allocated by malloc. */
577 free((char*)STRINGZ_VALUE_OF(o));
578 break;
579 case VCVT_VOBJECT:
580 cleanVObject(VOBJECT_VALUE_OF(o));
581 break;
582 }
583 deleteVObject(o);
584}
585
586void cleanVObjects(VObject *list)
587{
588 while (list) {
589 VObject *t = list;
590 list = nextVObjectInList(list);
591 cleanVObject(t);
592 }
593}
594
595/*----------------------------------------------------------------------
596 The following is a String Table Facilities.
597 ----------------------------------------------------------------------*/
598
599#define STRTBLSIZE 255
600
601static StrItem *strTbl[STRTBLSIZE];
602
603static unsigned int hashStr(const char *s)
604{
605 unsigned int h = 0;
606 int i;
607 for (i=0;s[i];i++) {
608 h += s[i]*i;
609 }
610 return h % STRTBLSIZE;
611}
612
613const char* lookupStr(const char *s)
614{
615 char *newS;
616
617 StrItem *t;
618 unsigned int h = hashStr(s);
619 if ((t = strTbl[h]) != 0) {
620 do {
621 if (strcasecmp(t->s,s) == 0) {
622 t->refCnt++;
623 return t->s;
624 }
625 t = t->next;
626 } while (t);
627 }
628 newS = dupStr(s,0);
629 strTbl[h] = newStrItem(newS,strTbl[h]);
630 return newS;
631}
632
633void unUseStr(const char *s)
634{
635 StrItem *cur, *prev;
636
637 unsigned int h = hashStr(s);
638 cur = strTbl[h];
639 prev = cur;
640 while (cur != 0) {
641 if (strcasecmp(cur->s,s) == 0) {
642 cur->refCnt--;
643 /* if that was the last reference to this string, kill it. */
644 if (cur->refCnt == 0) {
645 if (cur == strTbl[h]) {
646 strTbl[h] = cur->next;
647 deleteStr(prev->s);
648 deleteStrItem(prev);
649 } else {
650 prev->next = cur->next;
651 deleteStr(cur->s);
652 deleteStrItem(cur);
653 }
654 return;
655 }
656 }
657 prev = cur;
658 cur = cur->next;
659 }
660}
661
662void cleanStrTbl()
663{
664 int i;
665 for (i=0; i<STRTBLSIZE;i++) {
666 StrItem *t = strTbl[i];
667 while (t) {
668 StrItem *p;
669 deleteStr(t->s);
670 p = t;
671 t = t->next;
672 deleteStrItem(p);
673 }
674 strTbl[i] = 0;
675 }
676}
677
678
679struct PreDefProp {
680 const char *name;
681 const char *alias;
682 const char** fields;
683 unsigned int flags;
684 };
685
686/* flags in PreDefProp */
687 #define PD_BEGIN0x1
688 #define PD_INTERNAL0x2
689
690static const char *adrFields[] = {
691 VCPostalBoxProp,
692 VCExtAddressProp,
693 VCStreetAddressProp,
694 VCCityProp,
695 VCRegionProp,
696 VCPostalCodeProp,
697 VCCountryNameProp,
698 0
699};
700
701static const char *nameFields[] = {
702 VCFamilyNameProp,
703 VCGivenNameProp,
704 VCAdditionalNamesProp,
705 VCNamePrefixesProp,
706 VCNameSuffixesProp,
707 NULL
708 };
709
710static const char *orgFields[] = {
711 VCOrgNameProp,
712 VCOrgUnitProp,
713 VCOrgUnit2Prop,
714 VCOrgUnit3Prop,
715 VCOrgUnit4Prop,
716 NULL
717 };
718
719static const char *AAlarmFields[] = {
720 VCRunTimeProp,
721 VCSnoozeTimeProp,
722 VCRepeatCountProp,
723 VCAudioContentProp,
724 0
725 };
726
727/* ExDate -- has unamed fields */
728/* RDate -- has unamed fields */
729
730static const char *DAlarmFields[] = {
731 VCRunTimeProp,
732 VCSnoozeTimeProp,
733 VCRepeatCountProp,
734 VCDisplayStringProp,
735 0
736 };
737
738static const char *MAlarmFields[] = {
739 VCRunTimeProp,
740 VCSnoozeTimeProp,
741 VCRepeatCountProp,
742 VCEmailAddressProp,
743 VCNoteProp,
744 0
745 };
746
747static const char *PAlarmFields[] = {
748 VCRunTimeProp,
749 VCSnoozeTimeProp,
750 VCRepeatCountProp,
751 VCProcedureNameProp,
752 0
753 };
754
755static struct PreDefProp propNames[] = {
756 { VC7bitProp, 0, 0, 0 },
757 { VC8bitProp, 0, 0, 0 },
758 { VCAAlarmProp, 0, AAlarmFields, 0 },
759 { VCAdditionalNamesProp, 0, 0, 0 },
760 { VCAdrProp, 0, adrFields, 0 },
761 { VCAgentProp, 0, 0, 0 },
762 { VCAIFFProp, 0, 0, 0 },
763 { VCAOLProp, 0, 0, 0 },
764 { VCAppleLinkProp, 0, 0, 0 },
765 { VCAttachProp, 0, 0, 0 },
766 { VCAttendeeProp, 0, 0, 0 },
767 { VCATTMailProp, 0, 0, 0 },
768 { VCAudioContentProp, 0, 0, 0 },
769 { VCAVIProp, 0, 0, 0 },
770 { VCBase64Prop, 0, 0, 0 },
771 { VCBBSProp, 0, 0, 0 },
772 { VCBirthDateProp, 0, 0, 0 },
773 { VCBMPProp, 0, 0, 0 },
774 { VCBodyProp, 0, 0, 0 },
775 { VCBusinessRoleProp, 0, 0, 0 },
776 { VCCalProp, 0, 0, PD_BEGIN },
777 { VCCaptionProp, 0, 0, 0 },
778 { VCCardProp, 0, 0, PD_BEGIN },
779 { VCCarProp, 0, 0, 0 },
780 { VCCategoriesProp, 0, 0, 0 },
781 { VCCellularProp, 0, 0, 0 },
782 { VCCGMProp, 0, 0, 0 },
783 { VCCharSetProp, 0, 0, 0 },
784 { VCCIDProp, VCContentIDProp, 0, 0 },
785 { VCCISProp, 0, 0, 0 },
786 { VCCityProp, 0, 0, 0 },
787 { VCClassProp, 0, 0, 0 },
788 { VCCommentProp, 0, 0, 0 },
789 { VCCompletedProp, 0, 0, 0 },
790 { VCContentIDProp, 0, 0, 0 },
791 { VCCountryNameProp, 0, 0, 0 },
792 { VCDAlarmProp, 0, DAlarmFields, 0 },
793 { VCDataSizeProp, 0, 0, PD_INTERNAL },
794 { VCDayLightProp, 0, 0, 0 },
795 { VCDCreatedProp, 0, 0, 0 },
796 { VCDeliveryLabelProp, 0, 0, 0 },
797 { VCDescriptionProp, 0, 0, 0 },
798 { VCDIBProp, 0, 0, 0 },
799 { VCDisplayStringProp, 0, 0, 0 },
800 { VCDomesticProp, 0, 0, 0 },
801 { VCDTendProp, 0, 0, 0 },
802 { VCDTstartProp, 0, 0, 0 },
803 { VCDueProp, 0, 0, 0 },
804 { VCEmailAddressProp, 0, 0, 0 },
805 { VCEncodingProp, 0, 0, 0 },
806 { VCEndProp, 0, 0, 0 },
807 { VCEventProp, 0, 0, PD_BEGIN },
808 { VCEWorldProp, 0, 0, 0 },
809 { VCExNumProp, 0, 0, 0 },
810 { VCExDateProp, 0, 0, 0 },
811 { VCExpectProp, 0, 0, 0 },
812 { VCExtAddressProp, 0, 0, 0 },
813 { VCFamilyNameProp, 0, 0, 0 },
814 { VCFaxProp, 0, 0, 0 },
815 { VCFullNameProp, 0, 0, 0 },
816 { VCGeoLocationProp, 0, 0, 0 },
817 { VCGeoProp, 0, 0, 0 },
818 { VCGIFProp, 0, 0, 0 },
819 { VCGivenNameProp, 0, 0, 0 },
820 { VCGroupingProp, 0, 0, 0 },
821 { VCHomeProp, 0, 0, 0 },
822 { VCIBMMailProp, 0, 0, 0 },
823 { VCInlineProp, 0, 0, 0 },
824 { VCInternationalProp, 0, 0, 0 },
825 { VCInternetProp, 0, 0, 0 },
826 { VCISDNProp, 0, 0, 0 },
827 { VCJPEGProp, 0, 0, 0 },
828 { VCLanguageProp, 0, 0, 0 },
829 { VCLastModifiedProp, 0, 0, 0 },
830 { VCLastRevisedProp, 0, 0, 0 },
831 { VCLocationProp, 0, 0, 0 },
832 { VCLogoProp, 0, 0, 0 },
833 { VCMailerProp, 0, 0, 0 },
834 { VCMAlarmProp, 0, MAlarmFields, 0 },
835 { VCMCIMailProp, 0, 0, 0 },
836 { VCMessageProp, 0, 0, 0 },
837 { VCMETProp, 0, 0, 0 },
838 { VCModemProp, 0, 0, 0 },
839 { VCMPEG2Prop, 0, 0, 0 },
840 { VCMPEGProp, 0, 0, 0 },
841 { VCMSNProp, 0, 0, 0 },
842 { VCNamePrefixesProp, 0, 0, 0 },
843 { VCNameProp, 0, nameFields, 0 },
844 { VCNameSuffixesProp, 0, 0, 0 },
845 { VCNoteProp, 0, 0, 0 },
846 { VCOrgNameProp, 0, 0, 0 },
847 { VCOrgProp, 0, orgFields, 0 },
848 { VCOrgUnit2Prop, 0, 0, 0 },
849 { VCOrgUnit3Prop, 0, 0, 0 },
850 { VCOrgUnit4Prop, 0, 0, 0 },
851 { VCOrgUnitProp, 0, 0, 0 },
852 { VCPagerProp, 0, 0, 0 },
853 { VCPAlarmProp, 0, PAlarmFields, 0 },
854 { VCParcelProp, 0, 0, 0 },
855 { VCPartProp, 0, 0, 0 },
856 { VCPCMProp, 0, 0, 0 },
857 { VCPDFProp, 0, 0, 0 },
858 { VCPGPProp, 0, 0, 0 },
859 { VCPhotoProp, 0, 0, 0 },
860 { VCPICTProp, 0, 0, 0 },
861 { VCPMBProp, 0, 0, 0 },
862 { VCPostalBoxProp, 0, 0, 0 },
863 { VCPostalCodeProp, 0, 0, 0 },
864 { VCPostalProp, 0, 0, 0 },
865 { VCPowerShareProp, 0, 0, 0 },
866 { VCPreferredProp, 0, 0, 0 },
867 { VCPriorityProp, 0, 0, 0 },
868 { VCProcedureNameProp, 0, 0, 0 },
869 { VCProdIdProp, 0, 0, 0 },
870 { VCProdigyProp, 0, 0, 0 },
871 { VCPronunciationProp, 0, 0, 0 },
872 { VCPSProp, 0, 0, 0 },
873 { VCPublicKeyProp, 0, 0, 0 },
874 { VCQPProp, VCQuotedPrintableProp, 0, 0 },
875 { VCQuickTimeProp, 0, 0, 0 },
876 { VCQuotedPrintableProp, 0, 0, 0 },
877 { VCRDateProp, 0, 0, 0 },
878 { VCRegionProp, 0, 0, 0 },
879 { VCRelatedToProp, 0, 0, 0 },
880 { VCRepeatCountProp, 0, 0, 0 },
881 { VCResourcesProp, 0, 0, 0 },
882 { VCRNumProp, 0, 0, 0 },
883 { VCRoleProp, 0, 0, 0 },
884 { VCRRuleProp, 0, 0, 0 },
885 { VCRSVPProp, 0, 0, 0 },
886 { VCRunTimeProp, 0, 0, 0 },
887 { VCSequenceProp, 0, 0, 0 },
888 { VCSnoozeTimeProp, 0, 0, 0 },
889 { VCStartProp, 0, 0, 0 },
890 { VCStatusProp, 0, 0, 0 },
891 { VCStreetAddressProp, 0, 0, 0 },
892 { VCSubTypeProp, 0, 0, 0 },
893 { VCSummaryProp, 0, 0, 0 },
894 { VCTelephoneProp, 0, 0, 0 },
895 { VCTIFFProp, 0, 0, 0 },
896 { VCTimeZoneProp, 0, 0, 0 },
897 { VCTitleProp, 0, 0, 0 },
898 { VCTLXProp, 0, 0, 0 },
899 { VCTodoProp, 0, 0, PD_BEGIN },
900 { VCTranspProp, 0, 0, 0 },
901 { VCUniqueStringProp, 0, 0, 0 },
902 { VCURLProp, 0, 0, 0 },
903 { VCURLValueProp, 0, 0, 0 },
904 { VCValueProp, 0, 0, 0 },
905 { VCVersionProp, 0, 0, 0 },
906 { VCVideoProp, 0, 0, 0 },
907 { VCVoiceProp, 0, 0, 0 },
908 { VCWAVEProp, 0, 0, 0 },
909 { VCWMFProp, 0, 0, 0 },
910 { VCWorkProp, 0, 0, 0 },
911 { VCX400Prop, 0, 0, 0 },
912 { VCX509Prop, 0, 0, 0 },
913 { VCXRuleProp, 0, 0, 0 },
914 { 0,0,0,0 }
915 };
916
917
918static struct PreDefProp* lookupPropInfo(const char* str)
919{
920 /* brute force for now, could use a hash table here. */
921 int i;
922
923 for (i = 0; propNames[i].name; i++)
924 if (strcasecmp(str, propNames[i].name) == 0) {
925 return &propNames[i];
926 }
927
928 return 0;
929}
930
931
932const char* lookupProp_(const char* str)
933{
934 int i;
935
936 for (i = 0; propNames[i].name; i++)
937 if (strcasecmp(str, propNames[i].name) == 0) {
938 const char* s;
939 s = propNames[i].alias?propNames[i].alias:propNames[i].name;
940 return lookupStr(s);
941 }
942 return lookupStr(str);
943}
944
945
946const char* lookupProp(const char* str)
947{
948 int i;
949
950 for (i = 0; propNames[i].name; i++)
951 if (strcasecmp(str, propNames[i].name) == 0) {
952 const char *s;
953 fieldedProp = propNames[i].fields;
954 s = propNames[i].alias?propNames[i].alias:propNames[i].name;
955 return lookupStr(s);
956 }
957 fieldedProp = 0;
958 return lookupStr(str);
959}
960
961
962/*----------------------------------------------------------------------
963 APIs to Output text form.
964 ----------------------------------------------------------------------*/
965#define OFILE_REALLOC_SIZE 256
966typedef struct OFile {
967 FILE *fp;
968 char *s;
969 int len;
970 int limit;
971 int alloc:1;
972 int fail:1;
973 } OFile;
974
975
976/* vCalendar files need crlf linebreaks. The disabled functions didn't provide
977 that. */
978#if 0
979
980static void appendsOFile(OFile *fp, const char *s)
981{
982 int slen;
983 if (fp->fail) return;
984 slen = strlen(s);
985 if (fp->fp) {
986 fwrite(s,1,slen,fp->fp);
987 }
988 else {
989stuff:
990 if (fp->len + slen < fp->limit) {
991 memcpy(fp->s+fp->len,s,slen);
992 fp->len += slen;
993 return;
994 }
995 else if (fp->alloc) {
996 fp->limit = fp->limit + OFILE_REALLOC_SIZE;
997 if (OFILE_REALLOC_SIZE <= slen) fp->limit += slen;
998 if (fp->s)
999 fp->s = realloc(fp->s,fp->limit);
1000 else
1001 fp->s = malloc(fp->limit);
1002 if (fp->s) goto stuff;
1003 }
1004 if (fp->alloc)
1005 free(fp->s);
1006 fp->s = 0;
1007 fp->fail = 1;
1008 }
1009}
1010
1011static void appendcOFile(OFile *fp, char c)
1012{
1013 if (fp->fail) return;
1014 if (fp->fp) {
1015 fputc(c,fp->fp);
1016 }
1017 else {
1018stuff:
1019 if (fp->len+1 < fp->limit) {
1020 fp->s[fp->len] = c;
1021 fp->len++;
1022 return;
1023 }
1024 else if (fp->alloc) {
1025 fp->limit = fp->limit + OFILE_REALLOC_SIZE;
1026 fp->s = realloc(fp->s,fp->limit);
1027 if (fp->s) goto stuff;
1028 }
1029 if (fp->alloc)
1030 free(fp->s);
1031 fp->s = 0;
1032 fp->fail = 1;
1033 }
1034}
1035
1036#else
1037
1038static void appendcOFile_(OFile *fp, char c)
1039{
1040 if (fp->fail) return;
1041 if (fp->fp) {
1042 fputc(c,fp->fp);
1043 }
1044 else {
1045stuff:
1046 if (fp->len+1 < fp->limit) {
1047 fp->s[fp->len] = c;
1048 fp->len++;
1049 return;
1050 }
1051 else if (fp->alloc) {
1052 fp->limit = fp->limit + OFILE_REALLOC_SIZE;
1053 fp->s = realloc(fp->s,fp->limit);
1054 if (fp->s) goto stuff;
1055 }
1056 if (fp->alloc)
1057 free(fp->s);
1058 fp->s = 0;
1059 fp->fail = 1;
1060 }
1061}
1062
1063static void appendcOFile(OFile *fp, char c)
1064{
1065 if (c == '\n') {
1066 /* write out as <CR><LF> */
1067 appendcOFile_(fp,0xd);
1068 appendcOFile_(fp,0xa);
1069 }
1070 else
1071 appendcOFile_(fp,c);
1072}
1073
1074static void appendsOFile(OFile *fp, const char *s)
1075{
1076 int i, slen;
1077 slen = strlen(s);
1078 for (i=0; i<slen; i++) {
1079 appendcOFile(fp,s[i]);
1080 }
1081}
1082
1083#endif
1084
1085static void initOFile(OFile *fp, FILE *ofp)
1086{
1087 fp->fp = ofp;
1088 fp->s = 0;
1089 fp->len = 0;
1090 fp->limit = 0;
1091 fp->alloc = 0;
1092 fp->fail = 0;
1093}
1094
1095static void initMemOFile(OFile *fp, char *s, int len)
1096{
1097 fp->fp = 0;
1098 fp->s = s;
1099 fp->len = 0;
1100 fp->limit = s?len:0;
1101 fp->alloc = s?0:1;
1102 fp->fail = 0;
1103}
1104
1105
1106static int writeBase64(OFile *fp, unsigned char *s, long len)
1107{
1108 long cur = 0;
1109 int i, numQuads = 0;
1110 unsigned long trip;
1111 unsigned char b;
1112 char quad[5];
1113#define MAXQUADS 16
1114
1115 quad[4] = 0;
1116
1117 while (cur < len) {
1118 /* collect the triplet of bytes into 'trip' */
1119 trip = 0;
1120 for (i = 0; i < 3; i++) {
1121 b = (cur < len) ? *(s + cur) : 0;
1122 cur++;
1123 trip = trip << 8 | b;
1124 }
1125 /* fill in 'quad' with the appropriate four characters */
1126 for (i = 3; i >= 0; i--) {
1127 b = (unsigned char)(trip & 0x3F);
1128 trip = trip >> 6;
1129 if ((3 - i) < (cur - len))
1130 quad[i] = '='; /* pad char */
1131 else if (b < 26) quad[i] = (char)b + 'A';
1132 else if (b < 52) quad[i] = (char)(b - 26) + 'a';
1133 else if (b < 62) quad[i] = (char)(b - 52) + '0';
1134 else if (b == 62) quad[i] = '+';
1135 else quad[i] = '/';
1136 }
1137 /* now output 'quad' with appropriate whitespace and line ending */
1138 appendsOFile(fp, (numQuads == 0 ? " " : ""));
1139 appendsOFile(fp, quad);
1140 appendsOFile(fp, ((cur >= len)?"\n" :(numQuads==MAXQUADS-1?"\n" : "")));
1141 numQuads = (numQuads + 1) % MAXQUADS;
1142 }
1143 appendcOFile(fp,'\n');
1144
1145 return 1;
1146}
1147
1148/* this function really sucks. Too basic. */
1149static void writeQPString(OFile *fp, const char *s, int qp)
1150{
1151 const char *p = s;
1152 while (*p) {
1153 if (*p == '\n') {
1154 if (p[1]) appendsOFile(fp,"=0A=");
1155 }
1156 if (*p == '=' && qp)
1157 appendsOFile(fp,"=3D");
1158 else
1159 appendcOFile(fp,*p);
1160 p++;
1161 }
1162}
1163
1164static void writeVObject_(OFile *fp, VObject *o);
1165
1166static void writeValue(OFile *fp, VObject *o, unsigned long size)
1167{
1168 if (o == 0) return;
1169 switch (VALUE_TYPE(o)) {
1170 case VCVT_USTRINGZ: {
1171 char *s = fakeCString(USTRINGZ_VALUE_OF(o));
1172 if (isAPropertyOf(o, VCQuotedPrintableProp))
1173 writeQPString(fp, s, 1);
1174 else
1175 writeQPString(fp, s, 0);
1176 deleteStr(s);
1177 break;
1178 }
1179 case VCVT_STRINGZ: {
1180 if (isAPropertyOf(o, VCQuotedPrintableProp))
1181 writeQPString(fp, STRINGZ_VALUE_OF(o), 1);
1182 else
1183 writeQPString(fp, STRINGZ_VALUE_OF(o), 0);
1184 break;
1185 }
1186 case VCVT_UINT: {
1187 char buf[16];
1188 sprintf(buf,"%u", INTEGER_VALUE_OF(o));
1189 appendsOFile(fp,buf);
1190 break;
1191 }
1192 case VCVT_ULONG: {
1193 char buf[16];
1194 sprintf(buf,"%lu", LONG_VALUE_OF(o));
1195 appendsOFile(fp,buf);
1196 break;
1197 }
1198 case VCVT_RAW: {
1199 appendcOFile(fp,'\n');
1200 writeBase64(fp,(unsigned char*)(ANY_VALUE_OF(o)),size);
1201 break;
1202 }
1203 case VCVT_VOBJECT:
1204 appendcOFile(fp,'\n');
1205 writeVObject_(fp,VOBJECT_VALUE_OF(o));
1206 break;
1207 }
1208}
1209
1210static void writeAttrValue(OFile *fp, VObject *o)
1211{
1212 if (NAME_OF(o)) {
1213 struct PreDefProp *pi;
1214 pi = lookupPropInfo(NAME_OF(o));
1215 if (pi && ((pi->flags & PD_INTERNAL) != 0)) return;
1216 appendcOFile(fp,';');
1217 appendsOFile(fp,NAME_OF(o));
1218 }
1219 else
1220 appendcOFile(fp,';');
1221 if (VALUE_TYPE(o)) {
1222 appendcOFile(fp,'=');
1223 writeValue(fp,o,0);
1224 }
1225}
1226
1227static void writeGroup(OFile *fp, VObject *o)
1228{
1229 char buf1[256];
1230 char buf2[256];
1231 strcpy(buf1,NAME_OF(o));
1232 while ((o=isAPropertyOf(o,VCGroupingProp)) != 0) {
1233 strncpy(buf2,STRINGZ_VALUE_OF(o),sizeof(buf2));
1234 buf2[sizeof(buf2)] = '\0';
1235 strncat(buf2,".",sizeof(buf2)-strlen(buf2)-1);
1236 strncat(buf2,buf1,sizeof(buf2)-strlen(buf2)-1);
1237 strcpy(buf1,buf2);
1238 }
1239 appendsOFile(fp,buf1);
1240}
1241
1242static int inList(const char **list, const char *s)
1243{
1244 if (list == 0) return 0;
1245 while (*list) {
1246 if (strcasecmp(*list,s) == 0) return 1;
1247 list++;
1248 }
1249 return 0;
1250}
1251
1252static void writeProp(OFile *fp, VObject *o)
1253{
1254 if (NAME_OF(o)) {
1255 struct PreDefProp *pi;
1256 VObjectIterator t;
1257 const char **fields_ = 0;
1258 pi = lookupPropInfo(NAME_OF(o));
1259 if (pi && ((pi->flags & PD_BEGIN) != 0)) {
1260 writeVObject_(fp,o);
1261 return;
1262 }
1263 if (isAPropertyOf(o,VCGroupingProp))
1264 writeGroup(fp,o);
1265 else
1266 appendsOFile(fp,NAME_OF(o));
1267 if (pi) fields_ = pi->fields;
1268 initPropIterator(&t,o);
1269 while (moreIteration(&t)) {
1270 const char *s;
1271 VObject *eachProp = nextVObject(&t);
1272 s = NAME_OF(eachProp);
1273 if (strcasecmp(VCGroupingProp,s) && !inList(fields_,s))
1274 writeAttrValue(fp,eachProp);
1275 }
1276 if (fields_) {
1277 int i = 0, n = 0;
1278 const char** fields = fields_;
1279 /* output prop as fields */
1280 appendcOFile(fp,':');
1281 while (*fields) {
1282 VObject *tl = isAPropertyOf(o,*fields);
1283 i++;
1284 if (tl) n = i;
1285 fields++;
1286 }
1287 fields = fields_;
1288 for (i=0;i<n;i++) {
1289 writeValue(fp,isAPropertyOf(o,*fields),0);
1290 fields++;
1291 if (i<(n-1)) appendcOFile(fp,';');
1292 }
1293 }
1294 }
1295
1296 if (VALUE_TYPE(o)) {
1297 unsigned long size = 0;
1298 VObject *p = isAPropertyOf(o,VCDataSizeProp);
1299 if (p) size = LONG_VALUE_OF(p);
1300 appendcOFile(fp,':');
1301 writeValue(fp,o,size);
1302 }
1303
1304 appendcOFile(fp,'\n');
1305}
1306
1307static void writeVObject_(OFile *fp, VObject *o)
1308{
1309 if (NAME_OF(o)) {
1310 struct PreDefProp *pi;
1311 pi = lookupPropInfo(NAME_OF(o));
1312
1313 if (pi && ((pi->flags & PD_BEGIN) != 0)) {
1314 VObjectIterator t;
1315 const char *begin = NAME_OF(o);
1316 appendsOFile(fp,"BEGIN:");
1317 appendsOFile(fp,begin);
1318 appendcOFile(fp,'\n');
1319 initPropIterator(&t,o);
1320 while (moreIteration(&t)) {
1321 VObject *eachProp = nextVObject(&t);
1322 writeProp(fp, eachProp);
1323 }
1324 appendsOFile(fp,"END:");
1325 appendsOFile(fp,begin);
1326 appendsOFile(fp,"\n\n");
1327 }
1328 }
1329}
1330
1331void writeVObject(FILE *fp, VObject *o)
1332{
1333 OFile ofp;
1334 initOFile(&ofp,fp);
1335 writeVObject_(&ofp,o);
1336}
1337
1338void writeVObjectToFile(char *fname, VObject *o)
1339{
1340 FILE *fp = fopen(fname,"w");
1341 if (fp) {
1342 writeVObject(fp,o);
1343 fclose(fp);
1344 }
1345}
1346
1347void writeVObjectsToFile(char *fname, VObject *list)
1348{
1349 FILE *fp = fopen(fname,"w");
1350 if (fp) {
1351 while (list) {
1352 writeVObject(fp,list);
1353 list = nextVObjectInList(list);
1354 }
1355 fclose(fp);
1356 }
1357}
1358
1359char* writeMemVObject(char *s, int *len, VObject *o)
1360{
1361 OFile ofp;
1362 initMemOFile(&ofp,s,len?*len:0);
1363 writeVObject_(&ofp,o);
1364 if (len) *len = ofp.len;
1365 appendcOFile(&ofp,0);
1366 return ofp.s;
1367}
1368
1369char* writeMemVObjects(char *s, int *len, VObject *list)
1370{
1371 OFile ofp;
1372 initMemOFile(&ofp,s,len?*len:0);
1373 while (list) {
1374 writeVObject_(&ofp,list);
1375 list = nextVObjectInList(list);
1376 }
1377 if (len) *len = ofp.len;
1378 appendcOFile(&ofp,0);
1379 return ofp.s;
1380}
1381
1382/*----------------------------------------------------------------------
1383 APIs to do fake Unicode stuff.
1384 ----------------------------------------------------------------------*/
1385wchar_t* fakeUnicode(const char *ps, int *bytes)
1386{
1387 wchar_t *r, *pw;
1388 int len = strlen(ps)+1;
1389
1390 pw = r = (wchar_t*)malloc(sizeof(wchar_t)*len);
1391 if (bytes)
1392 *bytes = len * sizeof(wchar_t);
1393
1394 while (*ps) {
1395 if (*ps == '\n')
1396 *pw = (wchar_t)0x2028;
1397 else if (*ps == '\r')
1398 *pw = (wchar_t)0x2029;
1399 else
1400 *pw = (wchar_t)(unsigned char)*ps;
1401 ps++; pw++;
1402 }
1403 *pw = (wchar_t)0;
1404
1405 return r;
1406}
1407
1408int uStrLen(const wchar_t *u)
1409{
1410 int i = 0;
1411 while (*u != (wchar_t)0) { u++; i++; }
1412 return i;
1413}
1414
1415char* fakeCString(const wchar_t *u)
1416{
1417 char *s, *t;
1418 int len = uStrLen(u) + 1;
1419 t = s = (char*)malloc(len+1);
1420 while (*u) {
1421 if (*u == (wchar_t)0x2028)
1422 *t = '\n';
1423 else if (*u == (wchar_t)0x2029)
1424 *t = '\r';
1425 else
1426 *t = (char)*u;
1427 u++; t++;
1428 }
1429 *t = 0;
1430 return s;
1431}
1432
1433/* end of source file vobject.c */
diff --git a/libkcal/versit/vobject.h b/libkcal/versit/vobject.h
new file mode 100644
index 0000000..0ec8b31
--- a/dev/null
+++ b/libkcal/versit/vobject.h
@@ -0,0 +1,384 @@
1/***************************************************************************
2(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
3Business Machines Corporation and Siemens Rolm Communications Inc.
4
5For purposes of this license notice, the term Licensors shall mean,
6collectively, Apple Computer, Inc., AT&T Corp., International
7Business Machines Corporation and Siemens Rolm Communications Inc.
8The term Licensor shall mean any of the Licensors.
9
10Subject to acceptance of the following conditions, permission is hereby
11granted by Licensors without the need for written agreement and without
12license or royalty fees, to use, copy, modify and distribute this
13software for any purpose.
14
15The above copyright notice and the following four paragraphs must be
16reproduced in all copies of this software and any software including
17this software.
18
19THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
20ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
21MODIFICATIONS.
22
23IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
24INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
25OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26DAMAGE.
27
28EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
29INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
30IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31PURPOSE.
32
33The software is provided with RESTRICTED RIGHTS. Use, duplication, or
34disclosure by the government are subject to restrictions set forth in
35DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
36
37***************************************************************************/
38
39/*
40
41The vCard/vCalendar C interface is implemented in the set
42of files as follows:
43
44vcc.y, yacc source, and vcc.c, the yacc output you will use
45implements the core parser
46
47vobject.c implements an API that insulates the caller from
48the parser and changes in the vCard/vCalendar BNF
49
50port.h defines compilation environment dependent stuff
51
52vcc.h and vobject.h are header files for their .c counterparts
53
54vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions
55which you may find useful.
56
57test.c is a standalone test driver that exercises some of
58the features of the APIs provided. Invoke test.exe on a
59VCARD/VCALENDAR input text file and you will see the pretty
60print output of the internal representation (this pretty print
61output should give you a good idea of how the internal
62representation looks like -- there is one such output in the
63following too). Also, a file with the .out suffix is generated
64to show that the internal representation can be written back
65in the original text format.
66
67For more information on this API see the readme.txt file
68which accompanied this distribution.
69
70 Also visit:
71
72 http://www.versit.com
73 http://www.ralden.com
74
75*/
76
77
78#ifndef __VOBJECT_H__
79#define __VOBJECT_H__ 1
80
81
82#include "port.h"
83#include <stdlib.h>
84#include <stdio.h>
85
86#if defined(__CPLUSPLUS__) || defined(__cplusplus)
87extern "C" {
88#endif
89
90
91 #define VC7bitProp "7BIT"
92 #define VC8bitProp "8BIT"
93 #define VCAAlarmProp "AALARM"
94 #define VCAdditionalNamesProp"ADDN"
95 #define VCAdrProp "ADR"
96 #define VCAgentProp "AGENT"
97 #define VCAIFFProp "AIFF"
98 #define VCAOLProp "AOL"
99 #define VCAppleLinkProp "APPLELINK"
100 #define VCAttachProp "ATTACH"
101 #define VCAttendeeProp "ATTENDEE"
102 #define VCATTMailProp "ATTMAIL"
103 #define VCAudioContentProp "AUDIOCONTENT"
104 #define VCAVIProp "AVI"
105 #define VCBase64Prop "BASE64"
106 #define VCBBSProp "BBS"
107 #define VCBirthDateProp "BDAY"
108 #define VCBMPProp "BMP"
109 #define VCBodyProp "BODY"
110 #define VCBusinessRoleProp "ROLE"
111 #define VCCalProp "VCALENDAR"
112 #define VCCaptionProp "CAP"
113 #define VCCardProp "VCARD"
114 #define VCCarProp "CAR"
115 #define VCCategoriesProp "CATEGORIES"
116 #define VCCellularProp "CELL"
117 #define VCCGMProp "CGM"
118 #define VCCharSetProp "CS"
119 #define VCCIDProp "CID"
120 #define VCCISProp "CIS"
121 #define VCCityProp "L"
122 #define VCClassProp "CLASS"
123 #define VCCommentProp "NOTE"
124 #define VCCompletedProp "COMPLETED"
125 #define VCContentIDProp "CONTENT-ID"
126 #define VCCountryNameProp "C"
127 #define VCDAlarmProp "DALARM"
128 #define VCDataSizeProp "DATASIZE"
129 #define VCDayLightProp "DAYLIGHT"
130 #define VCDCreatedProp "DCREATED"
131#define VCDeliveryLabelProp "LABEL"
132 #define VCDescriptionProp "DESCRIPTION"
133 #define VCDIBProp "DIB"
134 #define VCDisplayStringProp "DISPLAYSTRING"
135 #define VCDomesticProp "DOM"
136 #define VCDTendProp "DTEND"
137 #define VCDTstartProp "DTSTART"
138 #define VCDueProp "DUE"
139 #define VCEmailAddressProp "EMAIL"
140 #define VCEncodingProp "ENCODING"
141 #define VCEndProp "END"
142 #define VCEventProp "VEVENT"
143 #define VCEWorldProp "EWORLD"
144 #define VCExNumProp "EXNUM"
145 #define VCExDateProp "EXDATE"
146 #define VCExpectProp "EXPECT"
147 #define VCExtAddressProp "EXT ADD"
148 #define VCFamilyNameProp "F"
149 #define VCFaxProp "FAX"
150 #define VCFullNameProp "FN"
151 #define VCGeoProp "GEO"
152 #define VCGeoLocationProp "GEO"
153 #define VCGIFProp "GIF"
154 #define VCGivenNameProp "G"
155 #define VCGroupingProp "Grouping"
156 #define VCHomeProp "HOME"
157 #define VCIBMMailProp "IBMMail"
158 #define VCInlineProp "INLINE"
159 #define VCInternationalProp "INTL"
160 #define VCInternetProp "INTERNET"
161 #define VCISDNProp "ISDN"
162 #define VCJPEGProp "JPEG"
163 #define VCLanguageProp "LANG"
164 #define VCLastModifiedProp "LAST-MODIFIED"
165 #define VCLastRevisedProp "REV"
166 #define VCLocationProp "LOCATION"
167 #define VCLogoProp "LOGO"
168 #define VCMailerProp "MAILER"
169 #define VCMAlarmProp "MALARM"
170 #define VCMCIMailProp "MCIMAIL"
171 #define VCMessageProp "MSG"
172 #define VCMETProp "MET"
173 #define VCModemProp "MODEM"
174 #define VCMPEG2Prop "MPEG2"
175 #define VCMPEGProp "MPEG"
176 #define VCMSNProp "MSN"
177 #define VCNamePrefixesProp "NPRE"
178 #define VCNameProp "N"
179 #define VCNameSuffixesProp "NSUF"
180 #define VCNoteProp "NOTE"
181 #define VCOrgNameProp "ORGNAME"
182 #define VCOrgProp "ORG"
183 #define VCOrgUnit2Prop "OUN2"
184 #define VCOrgUnit3Prop "OUN3"
185 #define VCOrgUnit4Prop "OUN4"
186 #define VCOrgUnitProp "OUN"
187 #define VCPagerProp "PAGER"
188 #define VCPAlarmProp "PALARM"
189 #define VCParcelProp "PARCEL"
190 #define VCPartProp "PART"
191 #define VCPCMProp "PCM"
192 #define VCPDFProp "PDF"
193 #define VCPGPProp "PGP"
194 #define VCPhotoProp "PHOTO"
195 #define VCPICTProp "PICT"
196 #define VCPMBProp "PMB"
197 #define VCPostalBoxProp "BOX"
198 #define VCPostalCodeProp "PC"
199 #define VCPostalProp "POSTAL"
200 #define VCPowerShareProp "POWERSHARE"
201 #define VCPreferredProp "PREF"
202 #define VCPriorityProp "PRIORITY"
203 #define VCProcedureNameProp "PROCEDURENAME"
204 #define VCProdIdProp "PRODID"
205 #define VCProdigyProp "PRODIGY"
206 #define VCPronunciationProp "SOUND"
207 #define VCPSProp "PS"
208 #define VCPublicKeyProp "KEY"
209 #define VCQPProp "QP"
210 #define VCQuickTimeProp "QTIME"
211 #define VCQuotedPrintableProp"QUOTED-PRINTABLE"
212 #define VCRDateProp "RDATE"
213 #define VCRegionProp "R"
214 #define VCRelatedToProp "RELATED-TO"
215 #define VCRepeatCountProp "REPEATCOUNT"
216 #define VCResourcesProp "RESOURCES"
217 #define VCRNumProp "RNUM"
218 #define VCRoleProp "ROLE"
219 #define VCRRuleProp "RRULE"
220 #define VCRSVPProp "RSVP"
221 #define VCRunTimeProp "RUNTIME"
222 #define VCSequenceProp "SEQUENCE"
223 #define VCSnoozeTimeProp "SNOOZETIME"
224 #define VCStartProp "START"
225 #define VCStatusProp "STATUS"
226 #define VCStreetAddressProp "STREET"
227 #define VCSubTypeProp "SUBTYPE"
228 #define VCSummaryProp "SUMMARY"
229 #define VCTelephoneProp "TEL"
230 #define VCTIFFProp "TIFF"
231 #define VCTimeZoneProp "TZ"
232 #define VCTitleProp "TITLE"
233 #define VCTLXProp "TLX"
234 #define VCTodoProp "VTODO"
235 #define VCTranspProp "TRANSP"
236 #define VCUniqueStringProp "UID"
237 #define VCURLProp "URL"
238 #define VCURLValueProp "URLVAL"
239 #define VCValueProp "VALUE"
240 #define VCVersionProp "VERSION"
241 #define VCVideoProp "VIDEO"
242 #define VCVoiceProp "VOICE"
243 #define VCWAVEProp "WAVE"
244 #define VCWMFProp "WMF"
245 #define VCWorkProp "WORK"
246 #define VCX400Prop "X400"
247 #define VCX509Prop "X509"
248 #define VCXRuleProp "XRULE"
249
250/* extensions for KOrganizer / KPilot */
251#define KPilotIdProp "X-PILOTID"
252#define KPilotStatusProp "X-PILOTSTAT"
253
254/* extensions for iMIP / iTIP */
255#define ICOrganizerProp "X-ORGANIZER"
256#define ICMethodProp "X-METHOD"
257#define ICRequestStatusProp "X-REQUEST-STATUS"
258
259typedef struct VObject VObject;
260
261typedef union ValueItem {
262 const char *strs;
263 const wchar_t *ustrs;
264 unsigned int i;
265 unsigned long l;
266 void *any;
267 VObject *vobj;
268 } ValueItem;
269
270struct VObject {
271 VObject *next;
272 const char *id;
273 VObject *prop;
274 unsigned short valType;
275 ValueItem val;
276 };
277
278typedef struct StrItem StrItem;
279
280struct StrItem {
281 StrItem *next;
282 const char *s;
283 unsigned int refCnt;
284 };
285
286typedef struct VObjectIterator {
287 VObject* start;
288 VObject* next;
289 } VObjectIterator;
290
291extern VObject* newVObject(const char *id);
292extern void deleteVObject(VObject *p);
293extern char* dupStr(const char *s, unsigned int size);
294extern void deleteStr(const char *p);
295extern void unUseStr(const char *s);
296
297extern void setVObjectName(VObject *o, const char* id);
298extern void setVObjectStringZValue(VObject *o, const char *s);
299extern void setVObjectStringZValue_(VObject *o, const char *s);
300extern void setVObjectUStringZValue(VObject *o, const wchar_t *s);
301extern void setVObjectUStringZValue_(VObject *o, const wchar_t *s);
302extern void setVObjectIntegerValue(VObject *o, unsigned int i);
303extern void setVObjectLongValue(VObject *o, unsigned long l);
304extern void setVObjectAnyValue(VObject *o, void *t);
305extern VObject* setValueWithSize(VObject *prop, void *val, unsigned int size);
306extern VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size);
307
308extern const char* vObjectName(VObject *o);
309extern const char* vObjectStringZValue(VObject *o);
310extern const wchar_t* vObjectUStringZValue(VObject *o);
311extern unsigned int vObjectIntegerValue(VObject *o);
312extern unsigned long vObjectLongValue(VObject *o);
313extern void* vObjectAnyValue(VObject *o);
314extern VObject* vObjectVObjectValue(VObject *o);
315extern void setVObjectVObjectValue(VObject *o, VObject *p);
316
317extern VObject* addVObjectProp(VObject *o, VObject *p);
318extern VObject* addProp(VObject *o, const char *id);
319extern VObject* addProp_(VObject *o, const char *id);
320extern VObject* addPropValue(VObject *o, const char *p, const char *v);
321extern VObject* addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size);
322extern VObject* addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size);
323extern VObject* addGroup(VObject *o, const char *g);
324extern void addList(VObject **o, VObject *p);
325
326extern VObject* isAPropertyOf(VObject *o, const char *id);
327
328extern VObject* nextVObjectInList(VObject *o);
329extern void initPropIterator(VObjectIterator *i, VObject *o);
330extern int moreIteration(VObjectIterator *i);
331extern VObject* nextVObject(VObjectIterator *i);
332
333extern char* writeMemVObject(char *s, int *len, VObject *o);
334extern char* writeMemVObjects(char *s, int *len, VObject *list);
335
336extern const char* lookupStr(const char *s);
337extern void cleanStrTbl();
338
339extern void cleanVObject(VObject *o);
340extern void cleanVObjects(VObject *list);
341
342extern const char* lookupProp(const char* str);
343extern const char* lookupProp_(const char* str);
344
345extern wchar_t* fakeUnicode(const char *ps, int *bytes);
346extern int uStrLen(const wchar_t *u);
347extern char* fakeCString(const wchar_t *u);
348
349extern void printVObjectToFile(char *fname,VObject *o);
350extern void printVObjectsToFile(char *fname,VObject *list);
351extern void writeVObjectToFile(char *fname, VObject *o);
352extern void writeVObjectsToFile(char *fname, VObject *list);
353
354extern int vObjectValueType(VObject *o);
355
356/* return type of vObjectValueType: */
357 #define VCVT_NOVALUE0
358 /* if the VObject has no value associated with it. */
359 #define VCVT_STRINGZ1
360 /* if the VObject has value set by setVObjectStringZValue. */
361 #define VCVT_USTRINGZ2
362 /* if the VObject has value set by setVObjectUStringZValue. */
363 #define VCVT_UINT 3
364 /* if the VObject has value set by setVObjectIntegerValue. */
365 #define VCVT_ULONG 4
366 /* if the VObject has value set by setVObjectLongValue. */
367 #define VCVT_RAW 5
368 /* if the VObject has value set by setVObjectAnyValue. */
369 #define VCVT_VOBJECT6
370 /* if the VObject has value set by setVObjectVObjectValue. */
371
372extern const char** fieldedProp;
373
374extern void printVObject(FILE *fp,VObject *o);
375extern void writeVObject(FILE *fp, VObject *o);
376
377
378#if defined(__CPLUSPLUS__) || defined(__cplusplus)
379}
380#endif
381
382#endif /* __VOBJECT_H__ */
383
384