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 | |||
29 | using namespace KCal; | ||
30 | #include <qwidget.h> | ||
31 | Alarm::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 | |||
46 | Alarm::~Alarm() | ||
47 | { | ||
48 | } | ||
49 | |||
50 | bool 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 | |||
91 | void 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 | |||
120 | Alarm::Type Alarm::type() const | ||
121 | { | ||
122 | return mType; | ||
123 | } | ||
124 | |||
125 | void Alarm::setAudioAlarm(const QString &audioFile) | ||
126 | { | ||
127 | mType = Audio; | ||
128 | mFile = audioFile; | ||
129 | mParent->updated(); | ||
130 | } | ||
131 | |||
132 | void Alarm::setAudioFile(const QString &audioFile) | ||
133 | { | ||
134 | if (mType == Audio) { | ||
135 | mFile = audioFile; | ||
136 | mParent->updated(); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | QString Alarm::audioFile() const | ||
141 | { | ||
142 | return (mType == Audio) ? mFile : QString::null; | ||
143 | } | ||
144 | |||
145 | void Alarm::setProcedureAlarm(const QString &programFile, const QString &arguments) | ||
146 | { | ||
147 | mType = Procedure; | ||
148 | mFile = programFile; | ||
149 | mDescription = arguments; | ||
150 | mParent->updated(); | ||
151 | } | ||
152 | |||
153 | void Alarm::setProgramFile(const QString &programFile) | ||
154 | { | ||
155 | if (mType == Procedure) { | ||
156 | mFile = programFile; | ||
157 | mParent->updated(); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | QString Alarm::programFile() const | ||
162 | { | ||
163 | return (mType == Procedure) ? mFile : QString::null; | ||
164 | } | ||
165 | |||
166 | void Alarm::setProgramArguments(const QString &arguments) | ||
167 | { | ||
168 | if (mType == Procedure) { | ||
169 | mDescription = arguments; | ||
170 | mParent->updated(); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | QString Alarm::programArguments() const | ||
175 | { | ||
176 | return (mType == Procedure) ? mDescription : QString::null; | ||
177 | } | ||
178 | |||
179 | void 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 | |||
190 | void Alarm::setMailAddress(const Person &mailAddress) | ||
191 | { | ||
192 | if (mType == Email) { | ||
193 | mMailAddresses.clear(); | ||
194 | mMailAddresses += mailAddress; | ||
195 | mParent->updated(); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | void Alarm::setMailAddresses(const QValueList<Person> &mailAddresses) | ||
200 | { | ||
201 | if (mType == Email) { | ||
202 | mMailAddresses = mailAddresses; | ||
203 | mParent->updated(); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | void Alarm::addMailAddress(const Person &mailAddress) | ||
208 | { | ||
209 | if (mType == Email) { | ||
210 | mMailAddresses += mailAddress; | ||
211 | mParent->updated(); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | QValueList<Person> Alarm::mailAddresses() const | ||
216 | { | ||
217 | return (mType == Email) ? mMailAddresses : QValueList<Person>(); | ||
218 | } | ||
219 | |||
220 | void Alarm::setMailSubject(const QString &mailAlarmSubject) | ||
221 | { | ||
222 | if (mType == Email) { | ||
223 | mMailSubject = mailAlarmSubject; | ||
224 | mParent->updated(); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | QString Alarm::mailSubject() const | ||
229 | { | ||
230 | return (mType == Email) ? mMailSubject : QString::null; | ||
231 | } | ||
232 | |||
233 | void Alarm::setMailAttachment(const QString &mailAttachFile) | ||
234 | { | ||
235 | if (mType == Email) { | ||
236 | mMailAttachFiles.clear(); | ||
237 | mMailAttachFiles += mailAttachFile; | ||
238 | mParent->updated(); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | void Alarm::setMailAttachments(const QStringList &mailAttachFiles) | ||
243 | { | ||
244 | if (mType == Email) { | ||
245 | mMailAttachFiles = mailAttachFiles; | ||
246 | mParent->updated(); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | void Alarm::addMailAttachment(const QString &mailAttachFile) | ||
251 | { | ||
252 | if (mType == Email) { | ||
253 | mMailAttachFiles += mailAttachFile; | ||
254 | mParent->updated(); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | QStringList Alarm::mailAttachments() const | ||
259 | { | ||
260 | return (mType == Email) ? mMailAttachFiles : QStringList(); | ||
261 | } | ||
262 | |||
263 | void Alarm::setMailText(const QString &text) | ||
264 | { | ||
265 | if (mType == Email) { | ||
266 | mDescription = text; | ||
267 | mParent->updated(); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | QString Alarm::mailText() const | ||
272 | { | ||
273 | return (mType == Email) ? mDescription : QString::null; | ||
274 | } | ||
275 | |||
276 | void Alarm::setDisplayAlarm(const QString &text) | ||
277 | { | ||
278 | mType = Display; | ||
279 | mDescription = text; | ||
280 | mParent->updated(); | ||
281 | } | ||
282 | |||
283 | void Alarm::setText(const QString &text) | ||
284 | { | ||
285 | if (mType == Display) { | ||
286 | mDescription = text; | ||
287 | mParent->updated(); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | QString Alarm::text() const | ||
292 | { | ||
293 | return (mType == Display) ? mDescription : QString::null; | ||
294 | } | ||
295 | |||
296 | void Alarm::setTime(const QDateTime &alarmTime) | ||
297 | { | ||
298 | mAlarmTime = alarmTime; | ||
299 | mHasTime = true; | ||
300 | |||
301 | mParent->updated(); | ||
302 | } | ||
303 | |||
304 | QDateTime 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 | |||
321 | bool Alarm::hasTime() const | ||
322 | { | ||
323 | return mHasTime; | ||
324 | } | ||
325 | |||
326 | void Alarm::setSnoozeTime(int alarmSnoozeTime) | ||
327 | { | ||
328 | mAlarmSnoozeTime = alarmSnoozeTime; | ||
329 | mParent->updated(); | ||
330 | } | ||
331 | |||
332 | int Alarm::snoozeTime() const | ||
333 | { | ||
334 | return mAlarmSnoozeTime; | ||
335 | } | ||
336 | |||
337 | void Alarm::setRepeatCount(int alarmRepeatCount) | ||
338 | { | ||
339 | kdDebug(5800) << "Alarm::setRepeatCount(): " << alarmRepeatCount << endl; | ||
340 | |||
341 | mAlarmRepeatCount = alarmRepeatCount; | ||
342 | mParent->updated(); | ||
343 | } | ||
344 | |||
345 | int Alarm::repeatCount() const | ||
346 | { | ||
347 | kdDebug(5800) << "Alarm::repeatCount(): " << mAlarmRepeatCount << endl; | ||
348 | return mAlarmRepeatCount; | ||
349 | } | ||
350 | |||
351 | void Alarm::toggleAlarm() | ||
352 | { | ||
353 | mAlarmEnabled = !mAlarmEnabled; | ||
354 | mParent->updated(); | ||
355 | } | ||
356 | |||
357 | void Alarm::setEnabled(bool enable) | ||
358 | { | ||
359 | mAlarmEnabled = enable; | ||
360 | mParent->updated(); | ||
361 | } | ||
362 | |||
363 | bool Alarm::enabled() const | ||
364 | { | ||
365 | return mAlarmEnabled; | ||
366 | } | ||
367 | |||
368 | void Alarm::setStartOffset( const Duration &offset ) | ||
369 | { | ||
370 | mOffset = offset; | ||
371 | mEndOffset = false; | ||
372 | mHasTime = false; | ||
373 | mParent->updated(); | ||
374 | } | ||
375 | |||
376 | Duration Alarm::startOffset() const | ||
377 | { | ||
378 | return (mHasTime || mEndOffset) ? 0 : mOffset; | ||
379 | } | ||
380 | |||
381 | bool Alarm::hasStartOffset() const | ||
382 | { | ||
383 | return !mHasTime && !mEndOffset; | ||
384 | } | ||
385 | |||
386 | bool Alarm::hasEndOffset() const | ||
387 | { | ||
388 | return !mHasTime && mEndOffset; | ||
389 | } | ||
390 | |||
391 | void Alarm::setEndOffset( const Duration &offset ) | ||
392 | { | ||
393 | mOffset = offset; | ||
394 | mEndOffset = true; | ||
395 | mHasTime = false; | ||
396 | mParent->updated(); | ||
397 | } | ||
398 | |||
399 | Duration Alarm::endOffset() const | ||
400 | { | ||
401 | return (mHasTime || !mEndOffset) ? 0 : mOffset; | ||
402 | } | ||
403 | |||
404 | void 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 | |||
31 | namespace KCal { | ||
32 | |||
33 | class Incidence; | ||
34 | |||
35 | /** | ||
36 | This class represents an alarm notification. | ||
37 | */ | ||
38 | class 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 | |||
23 | using namespace KCal; | ||
24 | |||
25 | Attachment::Attachment(const QString& uri, const QString& mime) | ||
26 | { | ||
27 | mMimeType = mime; | ||
28 | mData = uri; | ||
29 | mBinary = false; | ||
30 | } | ||
31 | |||
32 | Attachment::Attachment(const char *base64, const QString& mime) | ||
33 | { | ||
34 | mMimeType = mime; | ||
35 | mData = QString::fromUtf8(base64); | ||
36 | mBinary = true; | ||
37 | } | ||
38 | |||
39 | bool Attachment::isURI() const | ||
40 | { | ||
41 | return !mBinary; | ||
42 | } | ||
43 | |||
44 | QString Attachment::uri() const | ||
45 | { | ||
46 | if (!mBinary) | ||
47 | return mData; | ||
48 | else | ||
49 | return QString::null; | ||
50 | } | ||
51 | |||
52 | void Attachment::setURI(const QString& uri) | ||
53 | { | ||
54 | mData = uri; | ||
55 | mBinary = false; | ||
56 | } | ||
57 | |||
58 | bool Attachment::isBinary() const | ||
59 | { | ||
60 | return mBinary; | ||
61 | } | ||
62 | |||
63 | char *Attachment::data() const | ||
64 | { | ||
65 | if (mBinary) | ||
66 | return mData.utf8().data(); | ||
67 | else | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | void Attachment::setData(const char *base64) | ||
72 | { | ||
73 | mData = QString::fromUtf8(base64); | ||
74 | mBinary = true; | ||
75 | } | ||
76 | |||
77 | QString Attachment::mimeType() const | ||
78 | { | ||
79 | return mMimeType; | ||
80 | } | ||
81 | |||
82 | void 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 | |||
27 | namespace KCal { | ||
28 | |||
29 | /** | ||
30 | * This class represents information related to an attachment. | ||
31 | */ | ||
32 | class Attachment | ||
33 | { | ||
34 | public: | ||
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); | ||
61 | private: | ||
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 | |||
28 | using namespace KCal; | ||
29 | |||
30 | Attendee::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 | |||
41 | Attendee::~Attendee() | ||
42 | { | ||
43 | } | ||
44 | |||
45 | |||
46 | bool 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 | |||
56 | void Attendee::setStatus(Attendee::PartStat s) | ||
57 | { | ||
58 | mStatus = s; | ||
59 | } | ||
60 | |||
61 | Attendee::PartStat Attendee::status() const | ||
62 | { | ||
63 | return mStatus; | ||
64 | } | ||
65 | |||
66 | QString Attendee::statusStr() const | ||
67 | { | ||
68 | return statusName(mStatus); | ||
69 | } | ||
70 | |||
71 | QString 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 | |||
99 | QStringList 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 | |||
114 | void Attendee::setRole(Attendee::Role r) | ||
115 | { | ||
116 | mRole = r; | ||
117 | } | ||
118 | |||
119 | Attendee::Role Attendee::role() const | ||
120 | { | ||
121 | return mRole; | ||
122 | } | ||
123 | |||
124 | QString Attendee::roleStr() const | ||
125 | { | ||
126 | return roleName(mRole); | ||
127 | } | ||
128 | |||
129 | void Attendee::setUid(QString uid) | ||
130 | { | ||
131 | mUid = uid; | ||
132 | } | ||
133 | |||
134 | QString Attendee::uid() const | ||
135 | { | ||
136 | return mUid; | ||
137 | } | ||
138 | |||
139 | QString 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 | |||
158 | QStringList 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 | |||
28 | namespace KCal { | ||
29 | |||
30 | /** | ||
31 | This class represents information related to an attendee of an event. | ||
32 | */ | ||
33 | class 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 | |||
34 | using namespace KCal; | ||
35 | |||
36 | Calendar::Calendar() | ||
37 | { | ||
38 | |||
39 | init(); | ||
40 | setTimeZoneId( i18n (" 00:00 Europe/London(UTC)") ); | ||
41 | } | ||
42 | |||
43 | Calendar::Calendar( const QString &timeZoneId ) | ||
44 | { | ||
45 | |||
46 | init(); | ||
47 | setTimeZoneId(timeZoneId); | ||
48 | } | ||
49 | |||
50 | void 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 | |||
108 | Calendar::~Calendar() | ||
109 | { | ||
110 | delete mDefaultFilter; | ||
111 | } | ||
112 | |||
113 | const QString &Calendar::getOwner() const | ||
114 | { | ||
115 | return mOwner; | ||
116 | } | ||
117 | |||
118 | void 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 | |||
129 | void 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 | |||
152 | QString 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 | |||
167 | void Calendar::setTimeZone(int tz) | ||
168 | { | ||
169 | mTimeZone = tz; | ||
170 | mLocalTime = false; | ||
171 | |||
172 | setModified( true ); | ||
173 | } | ||
174 | |||
175 | int Calendar::getTimeZone() const | ||
176 | { | ||
177 | return mTimeZone; | ||
178 | } | ||
179 | |||
180 | void 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 | |||
191 | QString Calendar::timeZoneId() const | ||
192 | { | ||
193 | return mTimeZoneId; | ||
194 | } | ||
195 | |||
196 | void Calendar::setLocalTime() | ||
197 | { | ||
198 | //qDebug("Calendar::setLocalTime() "); | ||
199 | mLocalTime = true; | ||
200 | mTimeZone = 0; | ||
201 | mTimeZoneId = ""; | ||
202 | |||
203 | setModified( true ); | ||
204 | } | ||
205 | |||
206 | bool Calendar::isLocalTime() const | ||
207 | { | ||
208 | return mLocalTime; | ||
209 | } | ||
210 | |||
211 | const QString &Calendar::getEmail() | ||
212 | { | ||
213 | return mOwnerEmail; | ||
214 | } | ||
215 | |||
216 | void Calendar::setEmail(const QString &e) | ||
217 | { | ||
218 | mOwnerEmail = e; | ||
219 | |||
220 | setModified( true ); | ||
221 | } | ||
222 | |||
223 | void Calendar::setFilter(CalFilter *filter) | ||
224 | { | ||
225 | mFilter = filter; | ||
226 | } | ||
227 | |||
228 | CalFilter *Calendar::filter() | ||
229 | { | ||
230 | return mFilter; | ||
231 | } | ||
232 | |||
233 | QPtrList<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 | |||
251 | QPtrList<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 | |||
269 | QPtrList<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 | |||
276 | QPtrList<Event> Calendar::events( const QDateTime &qdt ) | ||
277 | { | ||
278 | QPtrList<Event> el = rawEventsForDate(qdt); | ||
279 | mFilter->apply(&el); | ||
280 | return el; | ||
281 | } | ||
282 | |||
283 | QPtrList<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 | |||
291 | QPtrList<Event> Calendar::events() | ||
292 | { | ||
293 | QPtrList<Event> el = rawEvents(); | ||
294 | mFilter->apply(&el); | ||
295 | return el; | ||
296 | } | ||
297 | |||
298 | |||
299 | bool Calendar::addIncidence(Incidence *i) | ||
300 | { | ||
301 | Incidence::AddVisitor<Calendar> v(this); | ||
302 | |||
303 | return i->accept(v); | ||
304 | } | ||
305 | void 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 | |||
315 | Incidence* 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 | |||
329 | QPtrList<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 | ||
338 | void 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 | ||
368 | void 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 | |||
400 | void Calendar::registerObserver( Observer *observer ) | ||
401 | { | ||
402 | mObserver = observer; | ||
403 | mNewObserver = true; | ||
404 | } | ||
405 | |||
406 | void 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 | |||
416 | void Calendar::setLoadedProductId( const QString &id ) | ||
417 | { | ||
418 | mLoadedProductId = id; | ||
419 | } | ||
420 | |||
421 | QString 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 | |||
38 | class KConfig; | ||
39 | |||
40 | namespace KCal { | ||
41 | |||
42 | class 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 | */ | ||
60 | class Calendar : public QObject, public CustomProperties, | ||
61 | public IncidenceBase::Observer | ||
62 | { | ||
63 | Q_OBJECT | ||
64 | public: | ||
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 ¬i ); | ||
302 | void removeAlarm(const QDateTime &qdt, const QString ¬i ); | ||
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 | |||
322 | private: | ||
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 | ||
46 | using namespace KCal; | ||
47 | |||
48 | CalendarLocal::CalendarLocal() | ||
49 | : Calendar() | ||
50 | { | ||
51 | init(); | ||
52 | } | ||
53 | |||
54 | CalendarLocal::CalendarLocal(const QString &timeZoneId) | ||
55 | : Calendar(timeZoneId) | ||
56 | { | ||
57 | init(); | ||
58 | } | ||
59 | |||
60 | void CalendarLocal::init() | ||
61 | { | ||
62 | mNextAlarmIncidence = 0; | ||
63 | } | ||
64 | |||
65 | |||
66 | CalendarLocal::~CalendarLocal() | ||
67 | { | ||
68 | close(); | ||
69 | } | ||
70 | |||
71 | bool CalendarLocal::load( const QString &fileName ) | ||
72 | { | ||
73 | FileStorage storage( this, fileName ); | ||
74 | return storage.load(); | ||
75 | } | ||
76 | |||
77 | bool CalendarLocal::save( const QString &fileName, CalFormat *format ) | ||
78 | { | ||
79 | FileStorage storage( this, fileName, format ); | ||
80 | return storage.save(); | ||
81 | } | ||
82 | |||
83 | void 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 | } | ||
99 | bool 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 | |||
111 | bool CalendarLocal::addEvent( Event *event ) | ||
112 | { | ||
113 | insertEvent( event ); | ||
114 | |||
115 | event->registerObserver( this ); | ||
116 | |||
117 | setModified( true ); | ||
118 | |||
119 | return true; | ||
120 | } | ||
121 | |||
122 | void CalendarLocal::deleteEvent( Event *event ) | ||
123 | { | ||
124 | |||
125 | |||
126 | if ( mEventList.removeRef( event ) ) { | ||
127 | setModified( true ); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | |||
132 | Event *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 | } | ||
145 | bool 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 | } | ||
156 | bool 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 | |||
170 | void CalendarLocal::deleteTodo( Todo *todo ) | ||
171 | { | ||
172 | // Handle orphaned children | ||
173 | removeRelations( todo ); | ||
174 | |||
175 | if ( mTodoList.removeRef( todo ) ) { | ||
176 | setModified( true ); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | QPtrList<Todo> CalendarLocal::rawTodos() | ||
181 | { | ||
182 | return mTodoList; | ||
183 | } | ||
184 | Todo *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 | |||
194 | Event *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 | } | ||
203 | Todo *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 | } | ||
212 | QString CalendarLocal::nextSummary() const | ||
213 | { | ||
214 | return mNextSummary; | ||
215 | } | ||
216 | QDateTime CalendarLocal::nextAlarmEventDateTime() const | ||
217 | { | ||
218 | return mNextAlarmEventDateTime; | ||
219 | } | ||
220 | void 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 | } | ||
274 | QString 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 | |||
293 | void 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 | } | ||
302 | void 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 | |||
314 | QPtrList<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 | } | ||
328 | void CalendarLocal::reInitAlarmSettings() | ||
329 | { | ||
330 | if ( !mNextAlarmIncidence ) { | ||
331 | nextAlarm( 1000 ); | ||
332 | } | ||
333 | deRegisterAlarm(); | ||
334 | mNextAlarmIncidence = 0; | ||
335 | checkAlarmForIncidence( 0, false ); | ||
336 | |||
337 | } | ||
338 | |||
339 | |||
340 | |||
341 | QDateTime 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 | } | ||
382 | Alarm::List CalendarLocal::alarmsTo( const QDateTime &to ) | ||
383 | { | ||
384 | return alarms( QDateTime( QDate( 1900, 1, 1 ) ), to ); | ||
385 | } | ||
386 | |||
387 | Alarm::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 | |||
409 | void 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 | |||
427 | void 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. | ||
455 | void 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 | |||
466 | void CalendarLocal::insertEvent( Event *event ) | ||
467 | { | ||
468 | if ( mEventList.findRef( event ) < 0 ) mEventList.append( event ); | ||
469 | } | ||
470 | |||
471 | |||
472 | QPtrList<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 | |||
521 | QPtrList<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 | |||
598 | QPtrList<Event> CalendarLocal::rawEventsForDate( const QDateTime &qdt ) | ||
599 | { | ||
600 | return rawEventsForDate( qdt.date() ); | ||
601 | } | ||
602 | |||
603 | QPtrList<Event> CalendarLocal::rawEvents() | ||
604 | { | ||
605 | return mEventList; | ||
606 | } | ||
607 | |||
608 | bool 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 | |||
624 | void CalendarLocal::deleteJournal( Journal *journal ) | ||
625 | { | ||
626 | if ( mJournalList.removeRef(journal) ) { | ||
627 | setModified( true ); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | Journal *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 | |||
642 | Journal *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 | |||
651 | QPtrList<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 | |||
27 | namespace KCal { | ||
28 | |||
29 | class CalFormat; | ||
30 | |||
31 | /** | ||
32 | This class provides a calendar stored as a local file. | ||
33 | */ | ||
34 | class 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 | |||
7 | namespace KCal { | ||
8 | |||
9 | class 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 | |||
25 | using namespace KCal; | ||
26 | |||
27 | CalFilter::CalFilter() | ||
28 | { | ||
29 | mEnabled = true; | ||
30 | mCriteria = ShowPublic | ShowPrivate| ShowConfidential ; | ||
31 | } | ||
32 | |||
33 | CalFilter::CalFilter(const QString &name) | ||
34 | { | ||
35 | mName = name; | ||
36 | mEnabled = true; | ||
37 | mCriteria = ShowPublic | ShowPrivate| ShowConfidential ; | ||
38 | } | ||
39 | |||
40 | CalFilter::~CalFilter() | ||
41 | { | ||
42 | } | ||
43 | |||
44 | void 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 | ||
64 | void 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 | |||
83 | bool 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 | |||
94 | bool 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 | } | ||
104 | bool CalFilter::showCategories() | ||
105 | { | ||
106 | return mCriteria & ShowCategories; | ||
107 | } | ||
108 | int 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 | } | ||
118 | bool 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 | |||
173 | void CalFilter::setEnabled(bool enabled) | ||
174 | { | ||
175 | mEnabled = enabled; | ||
176 | } | ||
177 | |||
178 | bool CalFilter::isEnabled() | ||
179 | { | ||
180 | return mEnabled; | ||
181 | } | ||
182 | |||
183 | void CalFilter::setCriteria(int criteria) | ||
184 | { | ||
185 | mCriteria = criteria; | ||
186 | } | ||
187 | |||
188 | int CalFilter::criteria() | ||
189 | { | ||
190 | return mCriteria; | ||
191 | } | ||
192 | |||
193 | void CalFilter::setCategoryList(const QStringList &categoryList) | ||
194 | { | ||
195 | mCategoryList = categoryList; | ||
196 | } | ||
197 | |||
198 | QStringList 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 | |||
30 | namespace KCal { | ||
31 | |||
32 | /** | ||
33 | Filter for calendar objects. | ||
34 | */ | ||
35 | class 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 | |||
27 | using namespace KCal; | ||
28 | |||
29 | QString CalFormat::mApplication = QString::fromLatin1("libkcal"); | ||
30 | QString 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. | ||
34 | struct CalVersion { | ||
35 | int version; | ||
36 | QString prodId; | ||
37 | }; | ||
38 | static 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 | |||
46 | CalFormat::CalFormat() | ||
47 | { | ||
48 | mException = 0; | ||
49 | } | ||
50 | |||
51 | CalFormat::~CalFormat() | ||
52 | { | ||
53 | delete mException; | ||
54 | } | ||
55 | |||
56 | void CalFormat::clearException() | ||
57 | { | ||
58 | delete mException; | ||
59 | mException = 0; | ||
60 | } | ||
61 | |||
62 | void CalFormat::setException(ErrorFormat *exception) | ||
63 | { | ||
64 | delete mException; | ||
65 | mException = exception; | ||
66 | } | ||
67 | |||
68 | ErrorFormat *CalFormat::exception() | ||
69 | { | ||
70 | return mException; | ||
71 | } | ||
72 | |||
73 | void CalFormat::setApplication(const QString& application, const QString& productID) | ||
74 | { | ||
75 | mApplication = application; | ||
76 | mProductId = productID; | ||
77 | } | ||
78 | |||
79 | QString 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 | |||
91 | int 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 | |||
30 | namespace KCal { | ||
31 | |||
32 | class VCalDrag; | ||
33 | class 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 | */ | ||
41 | class 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 | |||
23 | namespace KCal { | ||
24 | |||
25 | class Calendar; | ||
26 | |||
27 | /** | ||
28 | This class provides the interface to the storage of a calendar. | ||
29 | */ | ||
30 | class 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 | |||
27 | using namespace KCal; | ||
28 | |||
29 | Compat *CompatFactory::createCompat( const QString & ) | ||
30 | { | ||
31 | return new Compat; | ||
32 | } | ||
33 | |||
34 | void 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 | |||
26 | namespace KCal { | ||
27 | |||
28 | class Compat; | ||
29 | |||
30 | class CompatFactory | ||
31 | { | ||
32 | public: | ||
33 | static Compat *createCompat( const QString &productId ); | ||
34 | }; | ||
35 | |||
36 | class Compat | ||
37 | { | ||
38 | public: | ||
39 | Compat() {}; | ||
40 | virtual ~Compat() {}; | ||
41 | |||
42 | virtual void fixFloatingEnd( QDate & ) {} | ||
43 | }; | ||
44 | |||
45 | class 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 | |||
23 | using namespace KCal; | ||
24 | |||
25 | CustomProperties::CustomProperties() | ||
26 | { | ||
27 | } | ||
28 | |||
29 | CustomProperties::CustomProperties(const CustomProperties &cp) | ||
30 | : mProperties(cp.mProperties) | ||
31 | { | ||
32 | } | ||
33 | |||
34 | CustomProperties::~CustomProperties() | ||
35 | { | ||
36 | } | ||
37 | |||
38 | void 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 | |||
49 | void CustomProperties::removeCustomProperty(const QCString &app, const QCString &key) | ||
50 | { | ||
51 | removeNonKDECustomProperty(QCString("X-KDE-" + app + "-" + key)); | ||
52 | } | ||
53 | |||
54 | QString CustomProperties::customProperty(const QCString &app, const QCString &key) const | ||
55 | { | ||
56 | return nonKDECustomProperty(QCString("X-KDE-" + app + "-" + key)); | ||
57 | } | ||
58 | |||
59 | void CustomProperties::setNonKDECustomProperty(const QCString &name, const QString &value) | ||
60 | { | ||
61 | if (value.isNull() || !checkName(name)) | ||
62 | return; | ||
63 | mProperties[name] = value; | ||
64 | } | ||
65 | |||
66 | void 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 | |||
73 | QString 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 | |||
81 | void 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 | |||
91 | QMap<QCString, QString> CustomProperties::customProperties() const | ||
92 | { | ||
93 | return mProperties; | ||
94 | } | ||
95 | |||
96 | bool 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 | |||
27 | namespace 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 | */ | ||
38 | class 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 | |||
29 | class QDropEvent; | ||
30 | |||
31 | namespace 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 | */ | ||
39 | class 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 | |||
35 | using namespace KCal; | ||
36 | |||
37 | DummyScheduler::DummyScheduler(Calendar *calendar) | ||
38 | : Scheduler(calendar) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | DummyScheduler::~DummyScheduler() | ||
43 | { | ||
44 | } | ||
45 | |||
46 | bool DummyScheduler::publish (IncidenceBase *incidence,const QString &recipients) | ||
47 | { | ||
48 | QString messageText = mFormat->createScheduleMessage(incidence, | ||
49 | Scheduler::Publish); | ||
50 | |||
51 | return saveMessage(messageText); | ||
52 | } | ||
53 | |||
54 | bool DummyScheduler::performTransaction(IncidenceBase *incidence,Method method,const QString &recipients) | ||
55 | { | ||
56 | QString messageText = mFormat->createScheduleMessage(incidence,method); | ||
57 | |||
58 | return saveMessage(messageText); | ||
59 | } | ||
60 | |||
61 | bool DummyScheduler::performTransaction(IncidenceBase *incidence,Method method) | ||
62 | { | ||
63 | QString messageText = mFormat->createScheduleMessage(incidence,method); | ||
64 | |||
65 | return saveMessage(messageText); | ||
66 | } | ||
67 | |||
68 | bool 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 | |||
81 | QPtrList<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 | |||
28 | namespace 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 | */ | ||
34 | class 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 | |||
26 | using namespace KCal; | ||
27 | |||
28 | Duration::Duration() | ||
29 | { | ||
30 | mSeconds = 0; | ||
31 | } | ||
32 | |||
33 | Duration::Duration( const QDateTime &start, const QDateTime &end ) | ||
34 | { | ||
35 | mSeconds = start.secsTo( end ); | ||
36 | } | ||
37 | |||
38 | Duration::Duration( int seconds ) | ||
39 | { | ||
40 | mSeconds = seconds; | ||
41 | } | ||
42 | |||
43 | |||
44 | bool KCal::operator==( const Duration& d1, const Duration& d2 ) | ||
45 | { | ||
46 | return ( d1.asSeconds() == d2.asSeconds() ); | ||
47 | } | ||
48 | |||
49 | |||
50 | |||
51 | QDateTime Duration::end( const QDateTime &start ) const | ||
52 | { | ||
53 | return start.addSecs( mSeconds ); | ||
54 | } | ||
55 | |||
56 | int 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 | |||
25 | namespace KCal { | ||
26 | |||
27 | class 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 | |||
27 | using namespace KCal; | ||
28 | |||
29 | Event::Event() : | ||
30 | mHasEndDate( false ), mTransparency( Opaque ) | ||
31 | { | ||
32 | } | ||
33 | |||
34 | Event::Event(const Event &e) : Incidence(e) | ||
35 | { | ||
36 | mDtEnd = e.mDtEnd; | ||
37 | mHasEndDate = e.mHasEndDate; | ||
38 | mTransparency = e.mTransparency; | ||
39 | } | ||
40 | |||
41 | Event::~Event() | ||
42 | { | ||
43 | } | ||
44 | |||
45 | Incidence *Event::clone() | ||
46 | { | ||
47 | kdDebug(5800) << "Event::clone()" << endl; | ||
48 | return new Event(*this); | ||
49 | } | ||
50 | |||
51 | bool 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 | |||
61 | void 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 | |||
73 | QDateTime 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 | |||
83 | QString Event::dtEndTimeStr() const | ||
84 | { | ||
85 | return KGlobal::locale()->formatTime(mDtEnd.time()); | ||
86 | } | ||
87 | |||
88 | QString Event::dtEndDateStr(bool shortfmt) const | ||
89 | { | ||
90 | return KGlobal::locale()->formatDate(mDtEnd.date(),shortfmt); | ||
91 | } | ||
92 | |||
93 | QString Event::dtEndStr(bool shortfmt) const | ||
94 | { | ||
95 | return KGlobal::locale()->formatDateTime(mDtEnd, shortfmt); | ||
96 | } | ||
97 | |||
98 | void Event::setHasEndDate(bool b) | ||
99 | { | ||
100 | mHasEndDate = b; | ||
101 | } | ||
102 | |||
103 | bool Event::hasEndDate() const | ||
104 | { | ||
105 | return mHasEndDate; | ||
106 | } | ||
107 | |||
108 | bool Event::isMultiDay() const | ||
109 | { | ||
110 | bool multi = !(dtStart().date() == dtEnd().date()); | ||
111 | return multi; | ||
112 | } | ||
113 | |||
114 | void Event::setTransparency(Event::Transparency transparency) | ||
115 | { | ||
116 | if (mReadOnly) return; | ||
117 | mTransparency = transparency; | ||
118 | updated(); | ||
119 | } | ||
120 | |||
121 | Event::Transparency Event::transparency() const | ||
122 | { | ||
123 | return mTransparency; | ||
124 | } | ||
125 | |||
126 | void Event::setDuration(int seconds) | ||
127 | { | ||
128 | setHasEndDate(false); | ||
129 | Incidence::setDuration(seconds); | ||
130 | } | ||
131 | QDateTime 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" | ||
28 | namespace KCal { | ||
29 | |||
30 | /** | ||
31 | This class provides an Event in the sense of RFC2445. | ||
32 | */ | ||
33 | class 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 | |||
82 | bool 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 | |||
26 | using namespace KCal; | ||
27 | |||
28 | Exception::Exception(const QString &message) | ||
29 | { | ||
30 | mMessage = message; | ||
31 | } | ||
32 | |||
33 | Exception::~Exception() | ||
34 | { | ||
35 | } | ||
36 | |||
37 | QString Exception::message() | ||
38 | { | ||
39 | if (mMessage.isEmpty()) return i18n("%1 Error").arg(CalFormat::application()); | ||
40 | else return mMessage; | ||
41 | } | ||
42 | |||
43 | |||
44 | ErrorFormat::ErrorFormat(ErrorCodeFormat code,const QString &message) : | ||
45 | Exception(message) | ||
46 | { | ||
47 | mCode = code; | ||
48 | } | ||
49 | |||
50 | QString 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 | |||
87 | ErrorFormat::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 | |||
32 | namespace 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 | */ | ||
38 | class 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 */ | ||
52 | class 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 | |||
36 | using namespace KCal; | ||
37 | |||
38 | FileStorage::FileStorage( Calendar *cal, const QString &fileName, | ||
39 | CalFormat *format ) | ||
40 | : CalStorage( cal ), | ||
41 | mFileName( fileName ), | ||
42 | mSaveFormat( format ) | ||
43 | { | ||
44 | } | ||
45 | |||
46 | FileStorage::~FileStorage() | ||
47 | { | ||
48 | delete mSaveFormat; | ||
49 | } | ||
50 | |||
51 | void FileStorage::setFileName( const QString &fileName ) | ||
52 | { | ||
53 | mFileName = fileName; | ||
54 | } | ||
55 | |||
56 | QString FileStorage::fileName()const | ||
57 | { | ||
58 | return mFileName; | ||
59 | } | ||
60 | |||
61 | |||
62 | void FileStorage::setSaveFormat( CalFormat *format ) | ||
63 | { | ||
64 | delete mSaveFormat; | ||
65 | mSaveFormat = format; | ||
66 | } | ||
67 | |||
68 | CalFormat *FileStorage::saveFormat()const | ||
69 | { | ||
70 | return mSaveFormat; | ||
71 | } | ||
72 | |||
73 | |||
74 | bool FileStorage::open() | ||
75 | { | ||
76 | return true; | ||
77 | } | ||
78 | |||
79 | bool 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 | |||
119 | bool 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 | |||
137 | bool 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 | |||
25 | namespace KCal { | ||
26 | |||
27 | /** | ||
28 | This class provides a calendar storage as a local file. | ||
29 | */ | ||
30 | class 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 | |||
25 | using namespace KCal; | ||
26 | |||
27 | FreeBusy::FreeBusy() | ||
28 | { | ||
29 | } | ||
30 | |||
31 | FreeBusy::FreeBusy(const QDateTime &start, const QDateTime &end) | ||
32 | { | ||
33 | setDtStart(start); | ||
34 | setDtEnd(end); | ||
35 | } | ||
36 | |||
37 | FreeBusy::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 | |||
101 | FreeBusy::~FreeBusy() | ||
102 | { | ||
103 | } | ||
104 | |||
105 | bool FreeBusy::setDtEnd( const QDateTime &end ) | ||
106 | { | ||
107 | mDtEnd = end; | ||
108 | return true; | ||
109 | } | ||
110 | |||
111 | QDateTime FreeBusy::dtEnd() const | ||
112 | { | ||
113 | return mDtEnd; | ||
114 | } | ||
115 | |||
116 | QValueList<Period> FreeBusy::busyPeriods() const | ||
117 | { | ||
118 | return mBusyPeriods; | ||
119 | } | ||
120 | |||
121 | bool 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 | |||
149 | FreeBusy::FreeBusy(QValueList<Period> busyPeriods) | ||
150 | { | ||
151 | mBusyPeriods = busyPeriods; | ||
152 | } | ||
153 | |||
154 | void 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 | |||
178 | void 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 | |||
35 | namespace KCal { | ||
36 | |||
37 | /** | ||
38 | This class provides information about free/busy time of a calendar user. | ||
39 | */ | ||
40 | class 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 | |||
28 | using namespace KCal; | ||
29 | |||
30 | ICalDrag::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 | |||
39 | bool ICalDrag::canDecode( QMimeSource *me ) | ||
40 | { | ||
41 | return me->provides( "text/calendar" ); | ||
42 | } | ||
43 | |||
44 | bool 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 | |||
28 | namespace KCal { | ||
29 | |||
30 | /** iCalendar drag&drop class. */ | ||
31 | class 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 | |||
35 | extern "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 | |||
51 | using namespace KCal; | ||
52 | |||
53 | ICalFormat::ICalFormat(bool quick ) | ||
54 | { | ||
55 | mQuicksave = false; //quick; | ||
56 | mImpl = new ICalFormatImpl( this ); | ||
57 | tzOffsetMin = 0; | ||
58 | //qDebug("new ICalFormat() "); | ||
59 | } | ||
60 | |||
61 | ICalFormat::~ICalFormat() | ||
62 | { | ||
63 | delete mImpl; | ||
64 | //qDebug("delete ICalFormat "); | ||
65 | } | ||
66 | |||
67 | bool 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> | ||
97 | bool 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 | |||
134 | bool 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 | |||
171 | Incidence *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 | |||
195 | QString 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 | |||
254 | QString ICalFormat::toICalString( Incidence *incidence ) | ||
255 | { | ||
256 | CalendarLocal cal( mTimeZoneId ); | ||
257 | cal.addIncidence( incidence->clone() ); | ||
258 | return toString( &cal ); | ||
259 | } | ||
260 | |||
261 | QString 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 | |||
274 | QString 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 | /* | ||
283 | bool 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 | |||
301 | QString 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 | |||
313 | ScheduleMessage *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 | |||
449 | void 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 | |||
461 | QString ICalFormat::timeZoneId() const | ||
462 | { | ||
463 | return mTimeZoneId; | ||
464 | } | ||
465 | |||
466 | bool ICalFormat::utc() const | ||
467 | { | ||
468 | return mUtc; | ||
469 | } | ||
470 | int ICalFormat::timeOffset() | ||
471 | { | ||
472 | return tzOffsetMin; | ||
473 | } | ||
474 | const 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 | |||
29 | namespace KCal { | ||
30 | |||
31 | class 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 | */ | ||
40 | class 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 | |||
30 | extern "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 | |||
45 | using namespace KCal; | ||
46 | |||
47 | const int gSecondsPerMinute = 60; | ||
48 | const int gSecondsPerHour = gSecondsPerMinute * 60; | ||
49 | const int gSecondsPerDay = gSecondsPerHour * 24; | ||
50 | const int gSecondsPerWeek = gSecondsPerDay * 7; | ||
51 | |||
52 | ICalFormatImpl::ICalFormatImpl( ICalFormat *parent ) : | ||
53 | mParent( parent ), mCalendarVersion( 0 ) | ||
54 | { | ||
55 | mCompat = new Compat; | ||
56 | } | ||
57 | |||
58 | ICalFormatImpl::~ICalFormatImpl() | ||
59 | { | ||
60 | delete mCompat; | ||
61 | } | ||
62 | |||
63 | class 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 | |||
79 | icalcomponent *ICalFormatImpl::writeIncidence(Incidence *incidence) | ||
80 | { | ||
81 | ToStringVisitor v( this ); | ||
82 | incidence->accept(v); | ||
83 | return v.component(); | ||
84 | } | ||
85 | |||
86 | icalcomponent *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 | |||
136 | icalcomponent *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 | |||
203 | icalcomponent *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 | |||
240 | icalcomponent *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 | |||
262 | void 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 | |||
424 | void 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 | |||
446 | void 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 | |||
456 | icalproperty *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 | |||
522 | icalproperty *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 | |||
542 | icalproperty *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 | |||
684 | icalcomponent *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 | |||
783 | Todo *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 | |||
844 | Event *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 | |||
982 | FreeBusy *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 | |||
1026 | Journal *ICalFormatImpl::readJournal(icalcomponent *vjournal) | ||
1027 | { | ||
1028 | Journal *journal = new Journal; | ||
1029 | |||
1030 | readIncidence(vjournal,journal); | ||
1031 | |||
1032 | return journal; | ||
1033 | } | ||
1034 | |||
1035 | Attendee *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 | |||
1119 | Attachment *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> | ||
1151 | void 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 | |||
1318 | void 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 | |||
1349 | void 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 | |||
1366 | void 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 | |||
1380 | void 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 | |||
1575 | void 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 | |||
1700 | icaltimetype 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 | |||
1721 | icaltimetype 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 | |||
1759 | QDateTime 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 | |||
1772 | QDate ICalFormatImpl::readICalDate(icaltimetype t) | ||
1773 | { | ||
1774 | return QDate(t.year,t.month,t.day); | ||
1775 | } | ||
1776 | |||
1777 | icaldurationtype 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 | |||
1795 | int 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 | |||
1810 | icalcomponent *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. | ||
1841 | bool 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 | |||
2057 | QString 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 | |||
2077 | void 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 | |||
2119 | icalcomponent *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 | |||
28 | extern "C" { | ||
29 | #include <ical.h> | ||
30 | #include <icalss.h> | ||
31 | } | ||
32 | |||
33 | namespace KCal { | ||
34 | |||
35 | class Compat; | ||
36 | |||
37 | /** | ||
38 | This class provides the libical dependent functions for ICalFormat. | ||
39 | */ | ||
40 | class 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 | |||
28 | extern "C" { | ||
29 | #include <ical.h> | ||
30 | #include <icalss.h> | ||
31 | } | ||
32 | |||
33 | namespace KCal { | ||
34 | |||
35 | class Compat; | ||
36 | |||
37 | /** | ||
38 | This class provides the libical dependent functions for ICalFormat. | ||
39 | */ | ||
40 | class 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 | |||
30 | using namespace KCal; | ||
31 | |||
32 | IMIPScheduler::IMIPScheduler(Calendar *calendar) | ||
33 | : Scheduler(calendar) | ||
34 | { | ||
35 | } | ||
36 | |||
37 | IMIPScheduler::~IMIPScheduler() | ||
38 | { | ||
39 | } | ||
40 | |||
41 | bool IMIPScheduler::publish (IncidenceBase *incidence,const QString &recipients) | ||
42 | { | ||
43 | return false; | ||
44 | } | ||
45 | |||
46 | bool IMIPScheduler::performTransaction(IncidenceBase *incidence,Method method) | ||
47 | { | ||
48 | mFormat->createScheduleMessage(incidence,method); | ||
49 | |||
50 | return false; | ||
51 | } | ||
52 | |||
53 | QPtrList<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 | |||
30 | namespace KCal { | ||
31 | |||
32 | /* | ||
33 | This class implements the iTIP interface using the email interface specified | ||
34 | as iMIP. | ||
35 | */ | ||
36 | class 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 | |||
30 | using namespace KCal; | ||
31 | |||
32 | Incidence::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 | |||
44 | Incidence::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 | |||
78 | Incidence::~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 | |||
91 | bool Incidence::cancelled() const | ||
92 | { | ||
93 | return mCancelled; | ||
94 | } | ||
95 | void Incidence::setCancelled( bool b ) | ||
96 | { | ||
97 | mCancelled = b; | ||
98 | updated(); | ||
99 | } | ||
100 | bool Incidence::hasStartDate() const | ||
101 | { | ||
102 | return mHasStartDate; | ||
103 | } | ||
104 | |||
105 | void 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 | ||
113 | static bool stringCompare( const QString& s1, const QString& s2 ) | ||
114 | { | ||
115 | if ( s1.isEmpty() && s2.isEmpty() ) | ||
116 | return true; | ||
117 | return s1 == s2; | ||
118 | } | ||
119 | |||
120 | bool 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 | |||
177 | void Incidence::recreate() | ||
178 | { | ||
179 | setCreated(QDateTime::currentDateTime()); | ||
180 | |||
181 | setUid(CalFormat::createUniqueId()); | ||
182 | |||
183 | setRevision(0); | ||
184 | |||
185 | setLastModified(QDateTime::currentDateTime()); | ||
186 | } | ||
187 | |||
188 | void Incidence::setReadOnly( bool readOnly ) | ||
189 | { | ||
190 | IncidenceBase::setReadOnly( readOnly ); | ||
191 | recurrence()->setRecurReadOnly( readOnly); | ||
192 | } | ||
193 | |||
194 | void Incidence::setCreated(QDateTime created) | ||
195 | { | ||
196 | if (mReadOnly) return; | ||
197 | mCreated = getEvenTime(created); | ||
198 | } | ||
199 | |||
200 | QDateTime Incidence::created() const | ||
201 | { | ||
202 | return mCreated; | ||
203 | } | ||
204 | |||
205 | void Incidence::setRevision(int rev) | ||
206 | { | ||
207 | if (mReadOnly) return; | ||
208 | mRevision = rev; | ||
209 | |||
210 | updated(); | ||
211 | } | ||
212 | |||
213 | int Incidence::revision() const | ||
214 | { | ||
215 | return mRevision; | ||
216 | } | ||
217 | |||
218 | void Incidence::setDtStart(const QDateTime &dtStart) | ||
219 | { | ||
220 | |||
221 | QDateTime dt = getEvenTime(dtStart); | ||
222 | recurrence()->setRecurStart( dt); | ||
223 | IncidenceBase::setDtStart( dt ); | ||
224 | } | ||
225 | |||
226 | void Incidence::setDescription(const QString &description) | ||
227 | { | ||
228 | if (mReadOnly) return; | ||
229 | mDescription = description; | ||
230 | updated(); | ||
231 | } | ||
232 | |||
233 | QString Incidence::description() const | ||
234 | { | ||
235 | return mDescription; | ||
236 | } | ||
237 | |||
238 | |||
239 | void Incidence::setSummary(const QString &summary) | ||
240 | { | ||
241 | if (mReadOnly) return; | ||
242 | mSummary = summary; | ||
243 | updated(); | ||
244 | } | ||
245 | |||
246 | QString Incidence::summary() const | ||
247 | { | ||
248 | return mSummary; | ||
249 | } | ||
250 | |||
251 | void Incidence::setCategories(const QStringList &categories) | ||
252 | { | ||
253 | if (mReadOnly) return; | ||
254 | mCategories = categories; | ||
255 | updated(); | ||
256 | } | ||
257 | |||
258 | // TODO: remove setCategories(QString) function | ||
259 | void 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 | |||
276 | QStringList Incidence::categories() const | ||
277 | { | ||
278 | return mCategories; | ||
279 | } | ||
280 | |||
281 | QString Incidence::categoriesStr() | ||
282 | { | ||
283 | return mCategories.join(","); | ||
284 | } | ||
285 | |||
286 | void Incidence::setRelatedToUid(const QString &relatedToUid) | ||
287 | { | ||
288 | if (mReadOnly) return; | ||
289 | mRelatedToUid = relatedToUid; | ||
290 | } | ||
291 | |||
292 | QString Incidence::relatedToUid() const | ||
293 | { | ||
294 | return mRelatedToUid; | ||
295 | } | ||
296 | |||
297 | void 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 | |||
310 | Incidence *Incidence::relatedTo() const | ||
311 | { | ||
312 | return mRelatedTo; | ||
313 | } | ||
314 | |||
315 | QPtrList<Incidence> Incidence::relations() const | ||
316 | { | ||
317 | return mRelations; | ||
318 | } | ||
319 | |||
320 | void Incidence::addRelation(Incidence *event) | ||
321 | { | ||
322 | if( mRelations.findRef( event ) == -1 ) { | ||
323 | mRelations.append(event); | ||
324 | //updated(); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | void Incidence::removeRelation(Incidence *event) | ||
329 | { | ||
330 | |||
331 | mRelations.removeRef(event); | ||
332 | |||
333 | // if (event->getRelatedTo() == this) event->setRelatedTo(0); | ||
334 | } | ||
335 | |||
336 | bool Incidence::recursOn(const QDate &qd) const | ||
337 | { | ||
338 | if (recurrence()->recursOnPure(qd) && !isException(qd)) return true; | ||
339 | else return false; | ||
340 | } | ||
341 | |||
342 | void Incidence::setExDates(const DateList &exDates) | ||
343 | { | ||
344 | if (mReadOnly) return; | ||
345 | mExDates = exDates; | ||
346 | |||
347 | recurrence()->setRecurExDatesCount(mExDates.count()); | ||
348 | |||
349 | updated(); | ||
350 | } | ||
351 | |||
352 | void 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 | |||
362 | DateList Incidence::exDates() const | ||
363 | { | ||
364 | return mExDates; | ||
365 | } | ||
366 | |||
367 | bool 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 | |||
379 | void Incidence::addAttachment(Attachment *attachment) | ||
380 | { | ||
381 | if (mReadOnly || !attachment) return; | ||
382 | mAttachments.append(attachment); | ||
383 | updated(); | ||
384 | } | ||
385 | |||
386 | void Incidence::deleteAttachment(Attachment *attachment) | ||
387 | { | ||
388 | mAttachments.removeRef(attachment); | ||
389 | } | ||
390 | |||
391 | void 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 | |||
402 | QPtrList<Attachment> Incidence::attachments() const | ||
403 | { | ||
404 | return mAttachments; | ||
405 | } | ||
406 | |||
407 | QPtrList<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 | |||
421 | void Incidence::setResources(const QStringList &resources) | ||
422 | { | ||
423 | if (mReadOnly) return; | ||
424 | mResources = resources; | ||
425 | updated(); | ||
426 | } | ||
427 | |||
428 | QStringList Incidence::resources() const | ||
429 | { | ||
430 | return mResources; | ||
431 | } | ||
432 | |||
433 | |||
434 | void Incidence::setPriority(int priority) | ||
435 | { | ||
436 | if (mReadOnly) return; | ||
437 | mPriority = priority; | ||
438 | updated(); | ||
439 | } | ||
440 | |||
441 | int Incidence::priority() const | ||
442 | { | ||
443 | return mPriority; | ||
444 | } | ||
445 | |||
446 | void Incidence::setSecrecy(int sec) | ||
447 | { | ||
448 | if (mReadOnly) return; | ||
449 | mSecrecy = sec; | ||
450 | updated(); | ||
451 | } | ||
452 | |||
453 | int Incidence::secrecy() const | ||
454 | { | ||
455 | return mSecrecy; | ||
456 | } | ||
457 | |||
458 | QString Incidence::secrecyStr() const | ||
459 | { | ||
460 | return secrecyName(mSecrecy); | ||
461 | } | ||
462 | |||
463 | QString 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 | |||
481 | QStringList 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 | |||
492 | QPtrList<Alarm> Incidence::alarms() const | ||
493 | { | ||
494 | return mAlarms; | ||
495 | } | ||
496 | |||
497 | Alarm* Incidence::newAlarm() | ||
498 | { | ||
499 | Alarm* alarm = new Alarm(this); | ||
500 | mAlarms.append(alarm); | ||
501 | // updated(); | ||
502 | return alarm; | ||
503 | } | ||
504 | |||
505 | void Incidence::addAlarm(Alarm *alarm) | ||
506 | { | ||
507 | mAlarms.append(alarm); | ||
508 | updated(); | ||
509 | } | ||
510 | |||
511 | void Incidence::removeAlarm(Alarm *alarm) | ||
512 | { | ||
513 | mAlarms.removeRef(alarm); | ||
514 | updated(); | ||
515 | } | ||
516 | |||
517 | void Incidence::clearAlarms() | ||
518 | { | ||
519 | mAlarms.clear(); | ||
520 | updated(); | ||
521 | } | ||
522 | |||
523 | bool 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 | |||
533 | Recurrence *Incidence::recurrence() const | ||
534 | { | ||
535 | return mRecurrence; | ||
536 | } | ||
537 | |||
538 | void Incidence::setLocation(const QString &location) | ||
539 | { | ||
540 | if (mReadOnly) return; | ||
541 | mLocation = location; | ||
542 | updated(); | ||
543 | } | ||
544 | |||
545 | QString Incidence::location() const | ||
546 | { | ||
547 | return mLocation; | ||
548 | } | ||
549 | |||
550 | ushort Incidence::doesRecur() const | ||
551 | { | ||
552 | if ( mRecurrence ) return mRecurrence->doesRecur(); | ||
553 | else return Recurrence::rNone; | ||
554 | } | ||
555 | |||
556 | QDateTime 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 | |||
36 | namespace KCal { | ||
37 | |||
38 | class Event; | ||
39 | class Todo; | ||
40 | class Journal; | ||
41 | |||
42 | /** | ||
43 | This class provides the base class common to all calendar components. | ||
44 | */ | ||
45 | class 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 | |||
266 | protected: | ||
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 | |||
294 | bool 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 | |||
29 | using namespace KCal; | ||
30 | |||
31 | IncidenceBase::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 | |||
48 | IncidenceBase::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 | |||
76 | IncidenceBase::~IncidenceBase() | ||
77 | { | ||
78 | } | ||
79 | |||
80 | |||
81 | bool 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 | |||
122 | QDateTime 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 | |||
130 | void IncidenceBase::setUid(const QString &uid) | ||
131 | { | ||
132 | mUid = uid; | ||
133 | updated(); | ||
134 | } | ||
135 | |||
136 | QString IncidenceBase::uid() const | ||
137 | { | ||
138 | return mUid; | ||
139 | } | ||
140 | |||
141 | void 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 | |||
149 | QDateTime IncidenceBase::lastModified() const | ||
150 | { | ||
151 | return mLastModified; | ||
152 | } | ||
153 | |||
154 | void 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 | |||
166 | QString IncidenceBase::organizer() const | ||
167 | { | ||
168 | return mOrganizer; | ||
169 | } | ||
170 | |||
171 | void IncidenceBase::setReadOnly( bool readOnly ) | ||
172 | { | ||
173 | mReadOnly = readOnly; | ||
174 | } | ||
175 | |||
176 | void IncidenceBase::setDtStart(const QDateTime &dtStart) | ||
177 | { | ||
178 | // if (mReadOnly) return; | ||
179 | mDtStart = getEvenTime(dtStart); | ||
180 | updated(); | ||
181 | } | ||
182 | |||
183 | QDateTime IncidenceBase::dtStart() const | ||
184 | { | ||
185 | return mDtStart; | ||
186 | } | ||
187 | |||
188 | QString IncidenceBase::dtStartTimeStr() const | ||
189 | { | ||
190 | return KGlobal::locale()->formatTime(dtStart().time()); | ||
191 | } | ||
192 | |||
193 | QString IncidenceBase::dtStartDateStr(bool shortfmt) const | ||
194 | { | ||
195 | return KGlobal::locale()->formatDate(dtStart().date(),shortfmt); | ||
196 | } | ||
197 | |||
198 | QString IncidenceBase::dtStartStr(bool shortfmt) const | ||
199 | { | ||
200 | return KGlobal::locale()->formatDateTime(dtStart(), shortfmt); | ||
201 | } | ||
202 | |||
203 | |||
204 | bool IncidenceBase::doesFloat() const | ||
205 | { | ||
206 | return mFloats; | ||
207 | } | ||
208 | |||
209 | void IncidenceBase::setFloats(bool f) | ||
210 | { | ||
211 | if (mReadOnly) return; | ||
212 | mFloats = f; | ||
213 | updated(); | ||
214 | } | ||
215 | |||
216 | |||
217 | void 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 | ||
228 | void IncidenceBase::removeAttendee(Attendee *a) | ||
229 | { | ||
230 | if (mReadOnly) return; | ||
231 | mAttendees.removeRef(a); | ||
232 | updated(); | ||
233 | } | ||
234 | |||
235 | void 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 | |||
248 | void IncidenceBase::clearAttendees() | ||
249 | { | ||
250 | if (mReadOnly) return; | ||
251 | mAttendees.clear(); | ||
252 | } | ||
253 | |||
254 | #if 0 | ||
255 | Attendee *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 | |||
269 | Attendee *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 | |||
282 | Attendee *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 | |||
302 | void IncidenceBase::setDuration(int seconds) | ||
303 | { | ||
304 | mDuration = seconds; | ||
305 | setHasDuration(true); | ||
306 | } | ||
307 | |||
308 | int IncidenceBase::duration() const | ||
309 | { | ||
310 | return mDuration; | ||
311 | } | ||
312 | |||
313 | void IncidenceBase::setHasDuration(bool b) | ||
314 | { | ||
315 | mHasDuration = b; | ||
316 | } | ||
317 | |||
318 | bool IncidenceBase::hasDuration() const | ||
319 | { | ||
320 | return mHasDuration; | ||
321 | } | ||
322 | |||
323 | void IncidenceBase::setSyncStatus(int stat) | ||
324 | { | ||
325 | if (mReadOnly) return; | ||
326 | mSyncStatus = stat; | ||
327 | } | ||
328 | |||
329 | int IncidenceBase::syncStatus() const | ||
330 | { | ||
331 | return mSyncStatus; | ||
332 | } | ||
333 | |||
334 | void IncidenceBase::setPilotId( int id ) | ||
335 | { | ||
336 | if (mReadOnly) return; | ||
337 | mPilotId = id; | ||
338 | } | ||
339 | |||
340 | int IncidenceBase::pilotId() const | ||
341 | { | ||
342 | return mPilotId; | ||
343 | } | ||
344 | void IncidenceBase::setZaurusId( int id ) | ||
345 | { | ||
346 | if (mReadOnly) return; | ||
347 | mZaurusId = id; | ||
348 | } | ||
349 | |||
350 | int IncidenceBase::zaurusId() const | ||
351 | { | ||
352 | return mZaurusId; | ||
353 | } | ||
354 | |||
355 | int IncidenceBase::zaurusUid() const | ||
356 | { | ||
357 | return mZaurusUid; | ||
358 | } | ||
359 | void IncidenceBase::setZaurusUid( int id ) | ||
360 | { | ||
361 | if (mReadOnly) return; | ||
362 | mZaurusUid = id; | ||
363 | } | ||
364 | |||
365 | int IncidenceBase::zaurusStat() const | ||
366 | { | ||
367 | return mZaurusStat; | ||
368 | } | ||
369 | void IncidenceBase::setZaurusStat( int id ) | ||
370 | { | ||
371 | if (mReadOnly) return; | ||
372 | mZaurusStat = id; | ||
373 | } | ||
374 | |||
375 | void IncidenceBase::registerObserver( IncidenceBase::Observer *observer ) | ||
376 | { | ||
377 | if( !mObservers.contains(observer) ) mObservers.append( observer ); | ||
378 | } | ||
379 | |||
380 | void IncidenceBase::unRegisterObserver( IncidenceBase::Observer *observer ) | ||
381 | { | ||
382 | mObservers.remove( observer ); | ||
383 | } | ||
384 | |||
385 | void 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 | |||
34 | namespace KCal { | ||
35 | |||
36 | typedef QValueList<QDate> DateList; | ||
37 | |||
38 | /** | ||
39 | This class provides the base class common to all calendar components. | ||
40 | */ | ||
41 | class 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 | |||
167 | bool 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 | |||
23 | using namespace KCal; | ||
24 | |||
25 | Journal::Journal() | ||
26 | { | ||
27 | } | ||
28 | |||
29 | Journal::~Journal() | ||
30 | { | ||
31 | } | ||
32 | |||
33 | Incidence *Journal::clone() | ||
34 | { | ||
35 | return new Journal(*this); | ||
36 | } | ||
37 | |||
38 | |||
39 | bool KCal::operator==( const Journal& j1, const Journal& j2 ) | ||
40 | { | ||
41 | return operator==( (const Incidence&)j1, (const Incidence&)j2 ); | ||
42 | } | ||
43 | |||
44 | |||
45 | QDateTime 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 | |||
28 | namespace KCal { | ||
29 | |||
30 | /** | ||
31 | This class provides a Journal in the sense of RFC2445. | ||
32 | */ | ||
33 | class 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; | ||
43 | private: | ||
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 | ||
4 | INCLUDEPATH += ../microkde ../qtcompat versit | ||
5 | INCLUDEPATH += ../libical/src/libical | ||
6 | INCLUDEPATH += ../libical/src/libicalss | ||
7 | OBJECTS_DIR = obj/$(PLATFORM) | ||
8 | MOC_DIR = moc | ||
9 | DESTDIR = $(QPEDIR)/lib | ||
10 | LIBS += -lical | ||
11 | LIBS += -licalss | ||
12 | |||
13 | INTERFACES = \ | ||
14 | |||
15 | HEADERS = \ | ||
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 | |||
51 | SOURCES = \ | ||
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 | |||
5 | include( ../variables.pri ) | ||
6 | |||
7 | INCLUDEPATH += ../microkde versit ../microkde/kdecore | ||
8 | #../qtcompat | ||
9 | INCLUDEPATH += ../libical/src/libical | ||
10 | INCLUDEPATH += ../libical/src/libicalss | ||
11 | DESTDIR = ../bin | ||
12 | DEFINES += DESKTOP_VERSION | ||
13 | unix: { | ||
14 | LIBS += ../libical/lib/libical.a | ||
15 | LIBS += ../libical/lib/libicalss.a | ||
16 | OBJECTS_DIR = obj/unix | ||
17 | MOC_DIR = moc/unix | ||
18 | } | ||
19 | win32: { | ||
20 | DEFINES += _WIN32_ | ||
21 | |||
22 | LIBS += ../libical/lib/ical.lib | ||
23 | LIBS += ../libical/lib/icalss.lib | ||
24 | OBJECTS_DIR = obj/win | ||
25 | MOC_DIR = moc/win | ||
26 | |||
27 | } | ||
28 | |||
29 | INTERFACES = \ | ||
30 | |||
31 | HEADERS = \ | ||
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 | |||
67 | SOURCES = \ | ||
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 | |||
6 | INCLUDEPATH += ../microkde ../qtcompat versit ../microkde/kdecore versit $(QPEDIR)/include | ||
7 | INCLUDEPATH += ../libical/src/libical | ||
8 | INCLUDEPATH += ../libical/src/libicalss | ||
9 | OBJECTS_DIR = obj/$(PLATFORM) | ||
10 | MOC_DIR = moc/$(PLATFORM) | ||
11 | DESTDIR = $(QPEDIR)/lib | ||
12 | LIBS += ../libical/lib/$(PLATFORM)/libical.a | ||
13 | LIBS += ../libical/lib/$(PLATFORM)/libicalss.a | ||
14 | |||
15 | INTERFACES = \ | ||
16 | |||
17 | HEADERS = \ | ||
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 | |||
54 | SOURCES = \ | ||
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 | |||
26 | namespace 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 | */ | ||
33 | template<class T> | ||
34 | class 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 | |||
26 | using namespace KCal; | ||
27 | |||
28 | Period::Period() | ||
29 | { | ||
30 | mHasDuration = false; | ||
31 | } | ||
32 | |||
33 | Period::Period( const QDateTime &start, const QDateTime &end ) | ||
34 | { | ||
35 | mStart = start; | ||
36 | mEnd = end; | ||
37 | mHasDuration = false; | ||
38 | } | ||
39 | |||
40 | Period::Period( const QDateTime &start, const Duration &duration ) | ||
41 | { | ||
42 | mStart = start; | ||
43 | mEnd = duration.end( start ); | ||
44 | mHasDuration = true; | ||
45 | } | ||
46 | |||
47 | QDateTime Period::start() const | ||
48 | { | ||
49 | return mStart; | ||
50 | } | ||
51 | |||
52 | QDateTime Period::end()const | ||
53 | { | ||
54 | return mEnd; | ||
55 | } | ||
56 | |||
57 | Duration Period::duration() | ||
58 | { | ||
59 | return Duration( mStart, mEnd ); | ||
60 | } | ||
61 | |||
62 | bool 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 | |||
27 | namespace KCal { | ||
28 | |||
29 | class 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 | |||
26 | using namespace KCal; | ||
27 | |||
28 | Person::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 | |||
39 | Person::Person( const QString &name, const QString &email ) | ||
40 | { | ||
41 | setName(name); | ||
42 | setEmail(email); | ||
43 | } | ||
44 | |||
45 | |||
46 | bool KCal::operator==( const Person& p1, const Person& p2 ) | ||
47 | { | ||
48 | return ( p1.name() == p2.name() && | ||
49 | p1.email() == p2.email() ); | ||
50 | } | ||
51 | |||
52 | |||
53 | QString 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 | |||
65 | void Person::setName(const QString &name) | ||
66 | { | ||
67 | mName = name; | ||
68 | } | ||
69 | |||
70 | void 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 | |||
25 | namespace KCal { | ||
26 | |||
27 | class 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 | |||
39 | using namespace KCal; | ||
40 | |||
41 | class 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 | |||
276 | QMap<QString,QString> QtopiaParser::mCategoriesMap; | ||
277 | |||
278 | QtopiaFormat::QtopiaFormat() | ||
279 | { | ||
280 | mCategories = 0; | ||
281 | } | ||
282 | |||
283 | QtopiaFormat::~QtopiaFormat() | ||
284 | { | ||
285 | } | ||
286 | #include <qdom.h> | ||
287 | bool 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 | |||
300 | bool 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 | |||
324 | bool QtopiaFormat::fromString( Calendar *, const QString & ) | ||
325 | { | ||
326 | |||
327 | return false; | ||
328 | } | ||
329 | |||
330 | QString 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 | |||
30 | namespace KCal { | ||
31 | |||
32 | /** | ||
33 | This class implements the calendar format used by Qtopia. | ||
34 | */ | ||
35 | class 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 | |||
33 | using namespace KCal; | ||
34 | |||
35 | Recurrence::Feb29Type Recurrence::mFeb29YearlyDefaultType = Recurrence::rMar1; | ||
36 | |||
37 | |||
38 | Recurrence::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 | |||
56 | Recurrence::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 | |||
95 | Recurrence::~Recurrence() | ||
96 | { | ||
97 | } | ||
98 | |||
99 | |||
100 | bool 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 | /* | ||
146 | bool 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 | */ | ||
160 | QString 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 | |||
184 | void Recurrence::setCompatVersion(int version) | ||
185 | { | ||
186 | mCompatVersion = version ? version : INT_MAX; | ||
187 | } | ||
188 | |||
189 | ushort Recurrence::doesRecur() const | ||
190 | { | ||
191 | return recurs; | ||
192 | } | ||
193 | |||
194 | bool 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 | |||
222 | bool 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 | |||
255 | QDate 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 | |||
303 | QDateTime 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 | |||
351 | int Recurrence::durationTo(const QDate &date) const | ||
352 | { | ||
353 | QDate d = date; | ||
354 | return recurCalc(COUNT_TO_DATE, d); | ||
355 | } | ||
356 | |||
357 | int Recurrence::durationTo(const QDateTime &datetime) const | ||
358 | { | ||
359 | QDateTime dt = datetime; | ||
360 | return recurCalc(COUNT_TO_DATE, dt); | ||
361 | } | ||
362 | |||
363 | void Recurrence::unsetRecurs() | ||
364 | { | ||
365 | if (mRecurReadOnly) return; | ||
366 | recurs = rNone; | ||
367 | rMonthPositions.clear(); | ||
368 | rMonthDays.clear(); | ||
369 | rYearNums.clear(); | ||
370 | } | ||
371 | |||
372 | void 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 | |||
394 | void 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 | |||
416 | void 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 | |||
440 | int Recurrence::frequency() const | ||
441 | { | ||
442 | return rFreq; | ||
443 | } | ||
444 | |||
445 | int Recurrence::duration() const | ||
446 | { | ||
447 | return rDuration; | ||
448 | } | ||
449 | |||
450 | void 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 | |||
461 | QString Recurrence::endDateStr(bool shortfmt) const | ||
462 | { | ||
463 | return KGlobal::locale()->formatDate(rEndDateTime.date(),shortfmt); | ||
464 | } | ||
465 | |||
466 | const QBitArray &Recurrence::days() const | ||
467 | { | ||
468 | return rDays; | ||
469 | } | ||
470 | |||
471 | const QPtrList<Recurrence::rMonthPos> &Recurrence::monthPositions() const | ||
472 | { | ||
473 | return rMonthPositions; | ||
474 | } | ||
475 | |||
476 | const QPtrList<Recurrence::rMonthPos> &Recurrence::yearMonthPositions() const | ||
477 | { | ||
478 | return rMonthPositions; | ||
479 | } | ||
480 | |||
481 | const QPtrList<int> &Recurrence::monthDays() const | ||
482 | { | ||
483 | return rMonthDays; | ||
484 | } | ||
485 | |||
486 | void Recurrence::setMinutely(int _rFreq, int _rDuration) | ||
487 | { | ||
488 | if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) | ||
489 | return; | ||
490 | setDailySub(rMinutely, _rFreq, _rDuration); | ||
491 | } | ||
492 | |||
493 | void Recurrence::setMinutely(int _rFreq, const QDateTime &_rEndDateTime) | ||
494 | { | ||
495 | if (mRecurReadOnly) return; | ||
496 | rEndDateTime = _rEndDateTime; | ||
497 | setDailySub(rMinutely, _rFreq, 0); | ||
498 | } | ||
499 | |||
500 | void Recurrence::setHourly(int _rFreq, int _rDuration) | ||
501 | { | ||
502 | if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) | ||
503 | return; | ||
504 | setDailySub(rHourly, _rFreq, _rDuration); | ||
505 | } | ||
506 | |||
507 | void Recurrence::setHourly(int _rFreq, const QDateTime &_rEndDateTime) | ||
508 | { | ||
509 | if (mRecurReadOnly) return; | ||
510 | rEndDateTime = _rEndDateTime; | ||
511 | setDailySub(rHourly, _rFreq, 0); | ||
512 | } | ||
513 | |||
514 | void Recurrence::setDaily(int _rFreq, int _rDuration) | ||
515 | { | ||
516 | if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) | ||
517 | return; | ||
518 | setDailySub(rDaily, _rFreq, _rDuration); | ||
519 | } | ||
520 | |||
521 | void 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 | |||
529 | void 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 | |||
558 | void 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 | |||
577 | void 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 | |||
591 | void 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 | |||
606 | void Recurrence::addMonthlyPos(short _rPos, const QBitArray &_rDays) | ||
607 | { | ||
608 | if (recurs == rMonthlyPos) | ||
609 | addMonthlyPos_(_rPos, _rDays); | ||
610 | } | ||
611 | |||
612 | void 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 | |||
655 | void 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 | |||
682 | void 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 | |||
691 | void 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 | |||
700 | void 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 | |||
709 | void 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 | |||
718 | void Recurrence::addYearlyMonthPos(short _rPos, const QBitArray &_rDays) | ||
719 | { | ||
720 | if (recurs == rYearlyPos) | ||
721 | addMonthlyPos_(_rPos, _rDays); | ||
722 | } | ||
723 | |||
724 | const QPtrList<int> &Recurrence::yearNums() const | ||
725 | { | ||
726 | return rYearNums; | ||
727 | } | ||
728 | |||
729 | void 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 | |||
772 | QDateTime 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 | |||
821 | QDate 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 | |||
844 | QDateTime 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 | |||
893 | QDate 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 | |||
918 | bool 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 | |||
934 | bool 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 | |||
947 | bool 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 | |||
963 | bool 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 | |||
982 | bool 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 | |||
1014 | bool 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 | |||
1062 | bool 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 | |||
1094 | bool 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 | */ | ||
1122 | QDate 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 | */ | ||
1206 | QDate 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 | |||
1303 | void 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 | |||
1317 | void 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 | |||
1335 | int 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 | |||
1426 | int 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 | */ | ||
1517 | int 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 | */ | ||
1545 | int 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 | */ | ||
1574 | int 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 | |||
1595 | int 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 | |||
1634 | int 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 | |||
1679 | int 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 | } | ||
1729 | ex: | ||
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 | */ | ||
1739 | struct 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 | |||
1775 | int 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 | |||
1793 | int 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 | |||
1855 | int 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 | |||
1915 | int 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 | } | ||
1986 | ex: | ||
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 | */ | ||
1997 | struct 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 | |||
2019 | int 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. | ||
2037 | int 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'. | ||
2129 | int 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'. | ||
2204 | int 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 | } | ||
2323 | ex: | ||
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 | */ | ||
2334 | struct 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 | |||
2361 | int 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 | |||
2377 | int 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 | } | ||
2467 | ex: | ||
2468 | enddate = data.date(); | ||
2469 | return countGone; | ||
2470 | } | ||
2471 | |||
2472 | int 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 | |||
2587 | int 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 | } | ||
2710 | ex: | ||
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 | */ | ||
2721 | struct 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 | |||
2737 | int 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 | |||
2753 | int 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 | } | ||
2807 | ex: | ||
2808 | enddate = data.date(); | ||
2809 | return countGone; | ||
2810 | } | ||
2811 | |||
2812 | int 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 | |||
2871 | int 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 | } | ||
2940 | ex: | ||
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. | ||
2948 | void 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. | ||
2987 | int 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. | ||
3025 | bool 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. | ||
3059 | bool 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 | */ | ||
3100 | int 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 | */ | ||
3118 | int 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 | */ | ||
3133 | QDate 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 | */ | ||
3170 | QDate 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 | */ | ||
3207 | QDate 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 | */ | ||
3280 | QDate 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 | |||
3348 | void 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 | |||
29 | namespace KCal { | ||
30 | |||
31 | class Incidence; | ||
32 | |||
33 | /** | ||
34 | This class represents a recurrence rule for a calendar incidence. | ||
35 | */ | ||
36 | class 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 | |||
4 | namespace KCal { | ||
5 | |||
6 | class ResourceCalendar | ||
7 | { | ||
8 | }; | ||
9 | |||
10 | class 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 | |||
37 | using namespace KCal; | ||
38 | |||
39 | ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status) | ||
40 | { | ||
41 | mIncidence = incidence; | ||
42 | mMethod = method; | ||
43 | mStatus = status; | ||
44 | } | ||
45 | |||
46 | QString 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 | |||
62 | Scheduler::Scheduler(Calendar *calendar) | ||
63 | { | ||
64 | mCalendar = calendar; | ||
65 | mFormat = new ICalFormat(); | ||
66 | } | ||
67 | |||
68 | Scheduler::~Scheduler() | ||
69 | { | ||
70 | delete mFormat; | ||
71 | } | ||
72 | |||
73 | bool 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 | |||
101 | QString 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 | |||
125 | QString 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 | |||
149 | bool Scheduler::deleteTransaction(IncidenceBase *) | ||
150 | { | ||
151 | return true; | ||
152 | } | ||
153 | |||
154 | bool 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 | |||
178 | bool 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 | |||
220 | bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status status) | ||
221 | { | ||
222 | deleteTransaction(incidence); | ||
223 | return false; | ||
224 | } | ||
225 | |||
226 | bool 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 | |||
244 | bool 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 | |||
256 | bool 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 | |||
292 | bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status status) | ||
293 | { | ||
294 | // handled in korganizer's IncomingDialog | ||
295 | deleteTransaction(incidence); | ||
296 | return false; | ||
297 | } | ||
298 | |||
299 | bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status status) | ||
300 | { | ||
301 | deleteTransaction(incidence); | ||
302 | return false; | ||
303 | } | ||
304 | |||
305 | bool 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 | |||
28 | namespace KCal { | ||
29 | |||
30 | class IncidenceBase; | ||
31 | class Event; | ||
32 | class Calendar; | ||
33 | class 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 | */ | ||
42 | class 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 | */ | ||
78 | class 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 | |||
46 | using 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 | |||
62 | class 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 | |||
326 | QMap<QString,QString> SharpParser::mCategoriesMap; | ||
327 | |||
328 | SharpFormat::SharpFormat() | ||
329 | { | ||
330 | mCategories = 0; | ||
331 | } | ||
332 | |||
333 | SharpFormat::~SharpFormat() | ||
334 | { | ||
335 | } | ||
336 | ulong 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 | ||
361 | bool 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 | } | ||
427 | int 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 | } | ||
477 | bool 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 | } | ||
673 | QString 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 | } | ||
695 | QString 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 | } | ||
859 | QString 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 | } | ||
909 | QString 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 | } | ||
967 | bool SharpFormat::fromString( Calendar *calendar, const QString & text) | ||
968 | { | ||
969 | return false; | ||
970 | } | ||
971 | bool 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 | |||
1004 | QString 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 | |||
30 | namespace KCal { | ||
31 | |||
32 | /** | ||
33 | This class implements the calendar format used by Sharp. | ||
34 | */ | ||
35 | class 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 | |||
27 | using namespace KCal; | ||
28 | |||
29 | Todo::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 | |||
40 | Todo::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 | |||
49 | Todo::~Todo() | ||
50 | { | ||
51 | |||
52 | } | ||
53 | |||
54 | Incidence *Todo::clone() | ||
55 | { | ||
56 | return new Todo(*this); | ||
57 | } | ||
58 | |||
59 | |||
60 | bool 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 | |||
97 | void 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 | |||
119 | QDateTime Todo::dtDue() const | ||
120 | { | ||
121 | return mDtDue; | ||
122 | } | ||
123 | |||
124 | QString Todo::dtDueTimeStr() const | ||
125 | { | ||
126 | return KGlobal::locale()->formatTime(mDtDue.time()); | ||
127 | } | ||
128 | |||
129 | QString Todo::dtDueDateStr(bool shortfmt) const | ||
130 | { | ||
131 | return KGlobal::locale()->formatDate(mDtDue.date(),shortfmt); | ||
132 | } | ||
133 | |||
134 | QString Todo::dtDueStr(bool shortfmt) const | ||
135 | { | ||
136 | return KGlobal::locale()->formatDateTime(mDtDue, shortfmt); | ||
137 | } | ||
138 | |||
139 | bool Todo::hasDueDate() const | ||
140 | { | ||
141 | return mHasDueDate; | ||
142 | } | ||
143 | |||
144 | void Todo::setHasDueDate(bool f) | ||
145 | { | ||
146 | if (mReadOnly) return; | ||
147 | mHasDueDate = f; | ||
148 | updated(); | ||
149 | } | ||
150 | |||
151 | |||
152 | #if 0 | ||
153 | void 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 | |||
180 | void Todo::setStatus(int status) | ||
181 | { | ||
182 | if (mReadOnly) return; | ||
183 | mStatus = status; | ||
184 | updated(); | ||
185 | } | ||
186 | |||
187 | int Todo::status() const | ||
188 | { | ||
189 | return mStatus; | ||
190 | } | ||
191 | |||
192 | QString 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 | |||
224 | bool Todo::isCompleted() const | ||
225 | { | ||
226 | if (mPercentComplete == 100) return true; | ||
227 | else return false; | ||
228 | } | ||
229 | |||
230 | void Todo::setCompleted(bool completed) | ||
231 | { | ||
232 | if (completed) mPercentComplete = 100; | ||
233 | else mPercentComplete = 0; | ||
234 | updated(); | ||
235 | } | ||
236 | |||
237 | QDateTime Todo::completed() const | ||
238 | { | ||
239 | return mCompleted; | ||
240 | } | ||
241 | |||
242 | QString Todo::completedStr() const | ||
243 | { | ||
244 | return KGlobal::locale()->formatDateTime(mCompleted); | ||
245 | } | ||
246 | |||
247 | void Todo::setCompleted(const QDateTime &completed) | ||
248 | { | ||
249 | mHasCompletedDate = true; | ||
250 | mPercentComplete = 100; | ||
251 | mCompleted = getEvenTime(completed); | ||
252 | updated(); | ||
253 | } | ||
254 | |||
255 | bool Todo::hasCompletedDate() const | ||
256 | { | ||
257 | return mHasCompletedDate; | ||
258 | } | ||
259 | |||
260 | int Todo::percentComplete() const | ||
261 | { | ||
262 | return mPercentComplete; | ||
263 | } | ||
264 | |||
265 | void Todo::setPercentComplete(int v) | ||
266 | { | ||
267 | mPercentComplete = v; | ||
268 | updated(); | ||
269 | } | ||
270 | QDateTime 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 | |||
28 | namespace KCal { | ||
29 | |||
30 | /** | ||
31 | This class provides a Todo in the sense of RFC2445. | ||
32 | */ | ||
33 | class 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 | |||
26 | using namespace KCal; | ||
27 | |||
28 | VCalDrag::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 | |||
35 | bool VCalDrag::canDecode( QMimeSource *me ) | ||
36 | { | ||
37 | return me->provides( "text/x-vCalendar" ); | ||
38 | } | ||
39 | |||
40 | bool 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 | |||
28 | namespace KCal { | ||
29 | |||
30 | class Calendar; | ||
31 | |||
32 | /** vCalendar drag&drop class. */ | ||
33 | class 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 | |||
44 | using namespace KCal; | ||
45 | |||
46 | VCalFormat::VCalFormat() | ||
47 | { | ||
48 | } | ||
49 | |||
50 | VCalFormat::~VCalFormat() | ||
51 | { | ||
52 | } | ||
53 | |||
54 | bool 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 | |||
86 | bool 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 | |||
133 | bool 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 | |||
168 | QString 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 | |||
197 | VObject *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 | |||
359 | VObject* 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 | |||
652 | Todo *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 | |||
869 | Event* 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 | |||
1392 | QString 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 | |||
1404 | QString 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 | |||
1426 | QDateTime 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 | |||
1452 | QDate 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. | ||
1466 | void 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 | |||
1600 | const 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 | |||
1607 | int 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 | |||
1620 | Attendee::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 | |||
1652 | QCString 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 | |||
29 | class VObject; | ||
30 | |||
31 | namespace 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 | */ | ||
40 | class 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 | ||
3 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
4 | |||
5 | For purposes of this license notice, the term Licensors shall mean, | ||
6 | collectively, Apple Computer, Inc., AT&T Corp., International | ||
7 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
8 | The term Licensor shall mean any of the Licensors. | ||
9 | |||
10 | Subject to acceptance of the following conditions, permission is hereby | ||
11 | granted by Licensors without the need for written agreement and without | ||
12 | license or royalty fees, to use, copy, modify and distribute this | ||
13 | software for any purpose. | ||
14 | |||
15 | The above copyright notice and the following four paragraphs must be | ||
16 | reproduced in all copies of this software and any software including | ||
17 | this software. | ||
18 | |||
19 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE | ||
20 | ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR | ||
21 | MODIFICATIONS. | ||
22 | |||
23 | IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, | ||
24 | INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT | ||
25 | OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
26 | DAMAGE. | ||
27 | |||
28 | EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, | ||
29 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE | ||
30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
31 | PURPOSE. | ||
32 | |||
33 | The software is provided with RESTRICTED RIGHTS. Use, duplication, or | ||
34 | disclosure by the government are subject to restrictions set forth in | ||
35 | DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. | ||
36 | |||
37 | ***************************************************************************/ | ||
38 | |||
39 | #ifndef __PORT_H__ | ||
40 | #define __PORT_H__ 1 | ||
41 | |||
42 | #if defined(__CPLUSPLUS__) || defined(__cplusplus) | ||
43 | extern "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 | ||
50 | are globally unique IDs which can be used to generate clipboard format | ||
51 | ID's as per the requirements of a specific platform. For example, in | ||
52 | Windows they are used as the parameter in a call to RegisterClipboardFormat. | ||
53 | For 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 | ||
35 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
36 | |||
37 | For purposes of this license notice, the term Licensors shall mean, | ||
38 | collectively, Apple Computer, Inc., AT&T Corp., International | ||
39 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
40 | The term Licensor shall mean any of the Licensors. | ||
41 | |||
42 | Subject to acceptance of the following conditions, permission is hereby | ||
43 | granted by Licensors without the need for written agreement and without | ||
44 | license or royalty fees, to use, copy, modify and distribute this | ||
45 | software for any purpose. | ||
46 | |||
47 | The above copyright notice and the following four paragraphs must be | ||
48 | reproduced in all copies of this software and any software including | ||
49 | this software. | ||
50 | |||
51 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE | ||
52 | ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR | ||
53 | MODIFICATIONS. | ||
54 | |||
55 | IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, | ||
56 | INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT | ||
57 | OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
58 | DAMAGE. | ||
59 | |||
60 | EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, | ||
61 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE | ||
62 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
63 | PURPOSE. | ||
64 | |||
65 | The software is provided with RESTRICTED RIGHTS. Use, duplication, or | ||
66 | disclosure by the government are subject to restrictions set forth in | ||
67 | DFARS 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 ****/ | ||
159 | int mime_lineNum, mime_numErrors; /* yyerror() can use these */ | ||
160 | static VObject* vObjList; | ||
161 | static VObject *curProp; | ||
162 | static VObject *curObj; | ||
163 | static VObject* ObjStack[MAXLEVEL]; | ||
164 | static int ObjStackTop; | ||
165 | |||
166 | |||
167 | /* A helpful utility for the rest of the app. */ | ||
168 | #if __CPLUSPLUS__ | ||
169 | extern "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 | |||
179 | int yyparse(); | ||
180 | static int yylex(); | ||
181 | enum 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 ****/ | ||
193 | static int pushVObject(const char *prop); | ||
194 | static VObject* popVObject(); | ||
195 | char* lexDataFromBase64(); | ||
196 | static void lexPopMode(int top); | ||
197 | static int lexWithinMode(enum LexMode mode); | ||
198 | static void lexPushMode(enum LexMode mode); | ||
199 | static void enterProps(const char *s); | ||
200 | static void enterAttr(const char *s1, const char *s2); | ||
201 | /* static void enterValues(const char *value); */ | ||
202 | static void appendValue(const char *value); | ||
203 | static void mime_error_(char *s); | ||
204 | |||
205 | |||
206 | #line 181 "./vcc.y" | ||
207 | typedef 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 | |||
227 | static 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 | ||
259 | static 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 | |||
267 | static 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 | ||
285 | static 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 | |||
297 | static 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 | |||
307 | static 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 | |||
315 | static 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 | |||
323 | static 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 | |||
333 | static 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 | |||
339 | static 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 | |||
349 | static 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 | |||
359 | static 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 | |||
368 | static 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; }\ | ||
483 | while (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. */ | ||
559 | static 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. */ | ||
577 | static 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 | ||
615 | int yyparse (void *); | ||
616 | #else | ||
617 | int yyparse (void); | ||
618 | #endif | ||
619 | #endif | ||
620 | |||
621 | int | ||
622 | yyparse(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. */ | ||
690 | yynewstate: | ||
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. */ | ||
889 | yydefault: | ||
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. */ | ||
896 | yyreduce: | ||
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 | |||
919 | case 2: | ||
920 | #line 213 "./vcc.y" | ||
921 | { addList(&vObjList, yyvsp[0].vobj); curObj = 0; ; | ||
922 | break;} | ||
923 | case 4: | ||
924 | #line 216 "./vcc.y" | ||
925 | { addList(&vObjList, yyvsp[0].vobj); curObj = 0; ; | ||
926 | break;} | ||
927 | case 7: | ||
928 | #line 225 "./vcc.y" | ||
929 | { | ||
930 | lexPushMode(L_VCARD); | ||
931 | if (!pushVObject(VCCardProp)) YYERROR; | ||
932 | ; | ||
933 | break;} | ||
934 | case 8: | ||
935 | #line 230 "./vcc.y" | ||
936 | { | ||
937 | lexPopMode(0); | ||
938 | yyval.vobj = popVObject(); | ||
939 | ; | ||
940 | break;} | ||
941 | case 9: | ||
942 | #line 235 "./vcc.y" | ||
943 | { | ||
944 | lexPushMode(L_VCARD); | ||
945 | if (!pushVObject(VCCardProp)) YYERROR; | ||
946 | ; | ||
947 | break;} | ||
948 | case 10: | ||
949 | #line 240 "./vcc.y" | ||
950 | { | ||
951 | lexPopMode(0); | ||
952 | yyval.vobj = popVObject(); | ||
953 | ; | ||
954 | break;} | ||
955 | case 13: | ||
956 | #line 251 "./vcc.y" | ||
957 | { | ||
958 | lexPushMode(L_VALUES); | ||
959 | ; | ||
960 | break;} | ||
961 | case 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;} | ||
969 | case 16: | ||
970 | #line 264 "./vcc.y" | ||
971 | { | ||
972 | enterProps(yyvsp[0].str); | ||
973 | ; | ||
974 | break;} | ||
975 | case 18: | ||
976 | #line 269 "./vcc.y" | ||
977 | { | ||
978 | enterProps(yyvsp[0].str); | ||
979 | ; | ||
980 | break;} | ||
981 | case 22: | ||
982 | #line 282 "./vcc.y" | ||
983 | { | ||
984 | enterAttr(yyvsp[0].str,0); | ||
985 | ; | ||
986 | break;} | ||
987 | case 23: | ||
988 | #line 286 "./vcc.y" | ||
989 | { | ||
990 | enterAttr(yyvsp[-2].str,yyvsp[0].str); | ||
991 | |||
992 | ; | ||
993 | break;} | ||
994 | case 25: | ||
995 | #line 295 "./vcc.y" | ||
996 | { appendValue(yyvsp[-1].str); ; | ||
997 | break;} | ||
998 | case 27: | ||
999 | #line 297 "./vcc.y" | ||
1000 | { appendValue(yyvsp[0].str); ; | ||
1001 | break;} | ||
1002 | case 29: | ||
1003 | #line 302 "./vcc.y" | ||
1004 | { yyval.str = 0; ; | ||
1005 | break;} | ||
1006 | case 30: | ||
1007 | #line 307 "./vcc.y" | ||
1008 | { if (!pushVObject(VCCalProp)) YYERROR; ; | ||
1009 | break;} | ||
1010 | case 31: | ||
1011 | #line 310 "./vcc.y" | ||
1012 | { yyval.vobj = popVObject(); ; | ||
1013 | break;} | ||
1014 | case 32: | ||
1015 | #line 312 "./vcc.y" | ||
1016 | { if (!pushVObject(VCCalProp)) YYERROR; ; | ||
1017 | break;} | ||
1018 | case 33: | ||
1019 | #line 314 "./vcc.y" | ||
1020 | { yyval.vobj = popVObject(); ; | ||
1021 | break;} | ||
1022 | case 39: | ||
1023 | #line 329 "./vcc.y" | ||
1024 | { | ||
1025 | lexPushMode(L_VEVENT); | ||
1026 | if (!pushVObject(VCEventProp)) YYERROR; | ||
1027 | ; | ||
1028 | break;} | ||
1029 | case 40: | ||
1030 | #line 335 "./vcc.y" | ||
1031 | { | ||
1032 | lexPopMode(0); | ||
1033 | popVObject(); | ||
1034 | ; | ||
1035 | break;} | ||
1036 | case 41: | ||
1037 | #line 340 "./vcc.y" | ||
1038 | { | ||
1039 | lexPushMode(L_VEVENT); | ||
1040 | if (!pushVObject(VCEventProp)) YYERROR; | ||
1041 | ; | ||
1042 | break;} | ||
1043 | case 42: | ||
1044 | #line 345 "./vcc.y" | ||
1045 | { | ||
1046 | lexPopMode(0); | ||
1047 | popVObject(); | ||
1048 | ; | ||
1049 | break;} | ||
1050 | case 43: | ||
1051 | #line 353 "./vcc.y" | ||
1052 | { | ||
1053 | lexPushMode(L_VTODO); | ||
1054 | if (!pushVObject(VCTodoProp)) YYERROR; | ||
1055 | ; | ||
1056 | break;} | ||
1057 | case 44: | ||
1058 | #line 359 "./vcc.y" | ||
1059 | { | ||
1060 | lexPopMode(0); | ||
1061 | popVObject(); | ||
1062 | ; | ||
1063 | break;} | ||
1064 | case 45: | ||
1065 | #line 364 "./vcc.y" | ||
1066 | { | ||
1067 | lexPushMode(L_VTODO); | ||
1068 | if (!pushVObject(VCTodoProp)) YYERROR; | ||
1069 | ; | ||
1070 | break;} | ||
1071 | case 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 | |||
1133 | yyerrlab: /* 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; | ||
1185 | yyerrlab1: /* 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 | |||
1210 | yyerrdefault: /* 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 | |||
1219 | yyerrpop: /* 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 | |||
1239 | yyerrhandle: | ||
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 | /****************************************************************************/ | ||
1303 | static 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. */ | ||
1324 | static 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 | |||
1355 | static 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 | |||
1392 | static void enterProps(const char *s) | ||
1393 | { | ||
1394 | curProp = addGroup(curObj,s); | ||
1395 | deleteStr(s); | ||
1396 | } | ||
1397 | |||
1398 | static 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 | |||
1424 | struct 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 | |||
1446 | static 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 | |||
1455 | static 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 | |||
1465 | static 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 | |||
1472 | static 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 | |||
1487 | static int lexGeta() | ||
1488 | { | ||
1489 | ++lexBuf.len; | ||
1490 | return (lexBuf.buf[lexBuf.getPtr] = lexGetc_()); | ||
1491 | } | ||
1492 | |||
1493 | static int lexGeta_(int i) | ||
1494 | { | ||
1495 | ++lexBuf.len; | ||
1496 | return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_()); | ||
1497 | } | ||
1498 | |||
1499 | static 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 | |||
1507 | static 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 | |||
1535 | static 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 | |||
1545 | static 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 | |||
1552 | static void lexClearToken() | ||
1553 | { | ||
1554 | lexBuf.strsLen = 0; | ||
1555 | } | ||
1556 | |||
1557 | static 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 | |||
1572 | static char* lexStr() { | ||
1573 | return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1); | ||
1574 | } | ||
1575 | |||
1576 | static void lexSkipWhite() { | ||
1577 | int c = lexLookahead(); | ||
1578 | while (c == ' ' || c == '\t') { | ||
1579 | lexSkipLookahead(); | ||
1580 | c = lexLookahead(); | ||
1581 | } | ||
1582 | } | ||
1583 | |||
1584 | static 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 | |||
1601 | void 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 | |||
1617 | static 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 | |||
1628 | static 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 | ||
1658 | static 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 | |||
1694 | static 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 | |||
1725 | char* 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 | |||
1737 | static 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 | |||
1752 | void 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 | |||
1772 | static 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 | */ | ||
1781 | static 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 | |||
1882 | static 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 | |||
1903 | static 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 | |||
1955 | EndString: | ||
1956 | lexAppendc(0); | ||
1957 | return lexStr(); | ||
1958 | } /* LexQuotedPrintable */ | ||
1959 | |||
1960 | static 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 | |||
2081 | static 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 | /****************************************************************************/ | ||
2097 | VObject* Parse_MIME(const char *input, unsigned long len) | ||
2098 | { | ||
2099 | initLex(input, len, 0); | ||
2100 | return Parse_MIMEHelper(); | ||
2101 | } | ||
2102 | |||
2103 | |||
2104 | VObject* 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 | |||
2117 | VObject* 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 | /****************************************************************************/ | ||
2134 | void YYDebug(const char *s) | ||
2135 | { | ||
2136 | Parse_Debug(s); | ||
2137 | } | ||
2138 | |||
2139 | |||
2140 | static MimeErrorHandler mimeErrorHandler; | ||
2141 | |||
2142 | void registerMimeErrorHandler(MimeErrorHandler me) | ||
2143 | { | ||
2144 | mimeErrorHandler = me; | ||
2145 | } | ||
2146 | |||
2147 | static 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 | |||
2156 | static 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 | ||
3 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
4 | |||
5 | For purposes of this license notice, the term Licensors shall mean, | ||
6 | collectively, Apple Computer, Inc., AT&T Corp., International | ||
7 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
8 | The term Licensor shall mean any of the Licensors. | ||
9 | |||
10 | Subject to acceptance of the following conditions, permission is hereby | ||
11 | granted by Licensors without the need for written agreement and without | ||
12 | license or royalty fees, to use, copy, modify and distribute this | ||
13 | software for any purpose. | ||
14 | |||
15 | The above copyright notice and the following four paragraphs must be | ||
16 | reproduced in all copies of this software and any software including | ||
17 | this software. | ||
18 | |||
19 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE | ||
20 | ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR | ||
21 | MODIFICATIONS. | ||
22 | |||
23 | IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, | ||
24 | INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT | ||
25 | OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
26 | DAMAGE. | ||
27 | |||
28 | EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, | ||
29 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE | ||
30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
31 | PURPOSE. | ||
32 | |||
33 | The software is provided with RESTRICTED RIGHTS. Use, duplication, or | ||
34 | disclosure by the government are subject to restrictions set forth in | ||
35 | DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. | ||
36 | |||
37 | ***************************************************************************/ | ||
38 | |||
39 | #ifndef __VCC_H__ | ||
40 | #define __VCC_H__ 1 | ||
41 | |||
42 | #include "vobject.h" | ||
43 | |||
44 | |||
45 | #if defined(__CPLUSPLUS__) || defined(__cplusplus) | ||
46 | extern "C" { | ||
47 | #endif | ||
48 | |||
49 | typedef void (*MimeErrorHandler)(char *); | ||
50 | |||
51 | extern void registerMimeErrorHandler(MimeErrorHandler); | ||
52 | |||
53 | extern VObject* Parse_MIME(const char *input, unsigned long len); | ||
54 | extern VObject* Parse_MIME_FromFileName(const char* fname); | ||
55 | |||
56 | |||
57 | /* NOTE regarding Parse_MIME_FromFile | ||
58 | The function below, Parse_MIME_FromFile, come in two flavors, | ||
59 | neither of which is exported from the DLL. Each version takes | ||
60 | a CFile or FILE* as a parameter, neither of which can be | ||
61 | passed across a DLL interface (at least that is my experience). | ||
62 | If you are linking this code into your build directly then | ||
63 | you may find them a more convenient API that the other flavors | ||
64 | that take a file name. If you use them with the DLL LIB you | ||
65 | will get a link error. | ||
66 | */ | ||
67 | |||
68 | |||
69 | extern 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 | ||
4 | INTERFACES = \ | ||
5 | |||
6 | HEADERS = \ | ||
7 | port.h \ | ||
8 | vcc.h \ | ||
9 | vobject.h \ | ||
10 | |||
11 | SOURCES = \ | ||
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 | ||
4 | INTERFACES = \ | ||
5 | |||
6 | HEADERS = \ | ||
7 | port.h \ | ||
8 | vcc.h \ | ||
9 | vobject.h \ | ||
10 | |||
11 | SOURCES = \ | ||
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 | ||
3 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
4 | |||
5 | For purposes of this license notice, the term Licensors shall mean, | ||
6 | collectively, Apple Computer, Inc., AT&T Corp., International | ||
7 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
8 | The term Licensor shall mean any of the Licensors. | ||
9 | |||
10 | Subject to acceptance of the following conditions, permission is hereby | ||
11 | granted by Licensors without the need for written agreement and without | ||
12 | license or royalty fees, to use, copy, modify and distribute this | ||
13 | software for any purpose. | ||
14 | |||
15 | The above copyright notice and the following four paragraphs must be | ||
16 | reproduced in all copies of this software and any software including | ||
17 | this software. | ||
18 | |||
19 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE | ||
20 | ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR | ||
21 | MODIFICATIONS. | ||
22 | |||
23 | IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, | ||
24 | INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT | ||
25 | OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
26 | DAMAGE. | ||
27 | |||
28 | EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, | ||
29 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE | ||
30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
31 | PURPOSE. | ||
32 | |||
33 | The software is provided with RESTRICTED RIGHTS. Use, duplication, or | ||
34 | disclosure by the government are subject to restrictions set forth in | ||
35 | DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. | ||
36 | |||
37 | ***************************************************************************/ | ||
38 | |||
39 | /* | ||
40 | * src: vobject.c | ||
41 | * doc: vobject and APIs to construct vobject, APIs pretty print | ||
42 | * vobject, and convert a vobject into its textual representation. | ||
43 | */ | ||
44 | |||
45 | #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 | |||
65 | const 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 | |||
79 | VObject* 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 | |||
90 | VObject* newVObject(const char *id) | ||
91 | { | ||
92 | return newVObject_(lookupStr(id)); | ||
93 | } | ||
94 | |||
95 | void deleteVObject(VObject *p) | ||
96 | { | ||
97 | if (p->id) | ||
98 | unUseStr(p->id); | ||
99 | if (p) | ||
100 | free(p); | ||
101 | p = NULL; | ||
102 | } | ||
103 | |||
104 | char* 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 | |||
121 | void deleteStr(const char *p) | ||
122 | { | ||
123 | if (p) | ||
124 | free((void*)p); | ||
125 | p = NULL; | ||
126 | } | ||
127 | |||
128 | |||
129 | static 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 | |||
138 | static 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 | |||
150 | const char* vObjectName(VObject *o) | ||
151 | { | ||
152 | return NAME_OF(o); | ||
153 | } | ||
154 | |||
155 | void setVObjectName(VObject *o, const char* id) | ||
156 | { | ||
157 | NAME_OF(o) = id; | ||
158 | } | ||
159 | |||
160 | const char* vObjectStringZValue(VObject *o) | ||
161 | { | ||
162 | return STRINGZ_VALUE_OF(o); | ||
163 | } | ||
164 | |||
165 | void setVObjectStringZValue(VObject *o, const char *s) | ||
166 | { | ||
167 | STRINGZ_VALUE_OF(o) = dupStr(s,0); | ||
168 | VALUE_TYPE(o) = VCVT_STRINGZ; | ||
169 | } | ||
170 | |||
171 | void setVObjectStringZValue_(VObject *o, const char *s) | ||
172 | { | ||
173 | STRINGZ_VALUE_OF(o) = s; | ||
174 | VALUE_TYPE(o) = VCVT_STRINGZ; | ||
175 | } | ||
176 | |||
177 | const wchar_t* vObjectUStringZValue(VObject *o) | ||
178 | { | ||
179 | return USTRINGZ_VALUE_OF(o); | ||
180 | } | ||
181 | |||
182 | void 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 | |||
188 | void setVObjectUStringZValue_(VObject *o, const wchar_t *s) | ||
189 | { | ||
190 | USTRINGZ_VALUE_OF(o) = s; | ||
191 | VALUE_TYPE(o) = VCVT_USTRINGZ; | ||
192 | } | ||
193 | |||
194 | unsigned int vObjectIntegerValue(VObject *o) | ||
195 | { | ||
196 | return INTEGER_VALUE_OF(o); | ||
197 | } | ||
198 | |||
199 | void setVObjectIntegerValue(VObject *o, unsigned int i) | ||
200 | { | ||
201 | INTEGER_VALUE_OF(o) = i; | ||
202 | VALUE_TYPE(o) = VCVT_UINT; | ||
203 | } | ||
204 | |||
205 | unsigned long vObjectLongValue(VObject *o) | ||
206 | { | ||
207 | return LONG_VALUE_OF(o); | ||
208 | } | ||
209 | |||
210 | void setVObjectLongValue(VObject *o, unsigned long l) | ||
211 | { | ||
212 | LONG_VALUE_OF(o) = l; | ||
213 | VALUE_TYPE(o) = VCVT_ULONG; | ||
214 | } | ||
215 | |||
216 | void* vObjectAnyValue(VObject *o) | ||
217 | { | ||
218 | return ANY_VALUE_OF(o); | ||
219 | } | ||
220 | |||
221 | void setVObjectAnyValue(VObject *o, void *t) | ||
222 | { | ||
223 | ANY_VALUE_OF(o) = t; | ||
224 | VALUE_TYPE(o) = VCVT_RAW; | ||
225 | } | ||
226 | |||
227 | VObject* vObjectVObjectValue(VObject *o) | ||
228 | { | ||
229 | return VOBJECT_VALUE_OF(o); | ||
230 | } | ||
231 | |||
232 | void setVObjectVObjectValue(VObject *o, VObject *p) | ||
233 | { | ||
234 | VOBJECT_VALUE_OF(o) = p; | ||
235 | VALUE_TYPE(o) = VCVT_VOBJECT; | ||
236 | } | ||
237 | |||
238 | int vObjectValueType(VObject *o) | ||
239 | { | ||
240 | return VALUE_TYPE(o); | ||
241 | } | ||
242 | |||
243 | |||
244 | /*---------------------------------------------------------------------- | ||
245 | The following functions can be used to build VObject. | ||
246 | ----------------------------------------------------------------------*/ | ||
247 | |||
248 | VObject* addVObjectProp(VObject *o, VObject *p) | ||
249 | { | ||
250 | /* circular link list pointed to tail */ | ||
251 | /* | ||
252 | o {next,id,prop,val} | ||
253 | V | ||
254 | pn {next,id,prop,val} | ||
255 | V | ||
256 | ... | ||
257 | p1 {next,id,prop,val} | ||
258 | V | ||
259 | pn | ||
260 | --> | ||
261 | o {next,id,prop,val} | ||
262 | V | ||
263 | pn {next,id,prop,val} | ||
264 | V | ||
265 | p {next,id,prop,val} | ||
266 | ... | ||
267 | p1 {next,id,prop,val} | ||
268 | V | ||
269 | pn | ||
270 | */ | ||
271 | |||
272 | VObject *tail = o->prop; | ||
273 | if (tail) { | ||
274 | p->next = tail->next; | ||
275 | o->prop = tail->next = p; | ||
276 | } | ||
277 | else { | ||
278 | o->prop = p->next = p; | ||
279 | } | ||
280 | return p; | ||
281 | } | ||
282 | |||
283 | VObject* addProp(VObject *o, const char *id) | ||
284 | { | ||
285 | return addVObjectProp(o,newVObject(id)); | ||
286 | } | ||
287 | |||
288 | VObject* addProp_(VObject *o, const char *id) | ||
289 | { | ||
290 | return addVObjectProp(o,newVObject_(id)); | ||
291 | } | ||
292 | |||
293 | void addList(VObject **o, VObject *p) | ||
294 | { | ||
295 | p->next = 0; | ||
296 | if (*o == 0) { | ||
297 | *o = p; | ||
298 | } | ||
299 | else { | ||
300 | VObject *t = *o; | ||
301 | while (t->next) { | ||
302 | t = t->next; | ||
303 | } | ||
304 | t->next = p; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | VObject* nextVObjectInList(VObject *o) | ||
309 | { | ||
310 | return o->next; | ||
311 | } | ||
312 | |||
313 | VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size) | ||
314 | { | ||
315 | VObject *sizeProp; | ||
316 | setVObjectAnyValue(prop, val); | ||
317 | sizeProp = addProp(prop,VCDataSizeProp); | ||
318 | setVObjectLongValue(sizeProp, size); | ||
319 | return prop; | ||
320 | } | ||
321 | |||
322 | VObject* 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 | |||
328 | void initPropIterator(VObjectIterator *i, VObject *o) | ||
329 | { | ||
330 | i->start = o->prop; | ||
331 | i->next = 0; | ||
332 | } | ||
333 | |||
334 | void initVObjectIterator(VObjectIterator *i, VObject *o) | ||
335 | { | ||
336 | i->start = o->next; | ||
337 | i->next = 0; | ||
338 | } | ||
339 | |||
340 | int moreIteration(VObjectIterator *i) | ||
341 | { | ||
342 | return (i->start && (i->next==0 || i->next!=i->start)); | ||
343 | } | ||
344 | |||
345 | VObject* nextVObject(VObjectIterator *i) | ||
346 | { | ||
347 | if (i->start && i->next != i->start) { | ||
348 | if (i->next == 0) { | ||
349 | i->next = i->start->next; | ||
350 | return i->next; | ||
351 | } | ||
352 | else { | ||
353 | i->next = i->next->next; | ||
354 | return i->next; | ||
355 | } | ||
356 | } | ||
357 | else return (VObject*)0; | ||
358 | } | ||
359 | |||
360 | VObject* isAPropertyOf(VObject *o, const char *id) | ||
361 | { | ||
362 | VObjectIterator i; | ||
363 | initPropIterator(&i,o); | ||
364 | while (moreIteration(&i)) { | ||
365 | VObject *each = nextVObject(&i); | ||
366 | if (!strcasecmp(id,each->id)) | ||
367 | return each; | ||
368 | } | ||
369 | return (VObject*)0; | ||
370 | } | ||
371 | |||
372 | VObject* addGroup(VObject *o, const char *g) | ||
373 | { | ||
374 | /* | ||
375 | a.b.c | ||
376 | --> | ||
377 | prop(c) | ||
378 | prop(VCGrouping=b) | ||
379 | prop(VCGrouping=a) | ||
380 | */ | ||
381 | char *dot = strrchr(g,'.'); | ||
382 | if (dot) { | ||
383 | VObject *p, *t; | ||
384 | char *gs, *n = dot+1; | ||
385 | gs = dupStr(g,0);/* so we can write to it. */ | ||
386 | /* used to be | ||
387 | * t = p = addProp_(o,lookupProp_(n)); | ||
388 | */ | ||
389 | t = p = addProp_(o,lookupProp(n)); | ||
390 | dot = strrchr(gs,'.'); | ||
391 | *dot = 0; | ||
392 | do { | ||
393 | dot = strrchr(gs,'.'); | ||
394 | if (dot) { | ||
395 | n = dot+1; | ||
396 | *dot=0; | ||
397 | } | ||
398 | else | ||
399 | n = gs; | ||
400 | /* property(VCGroupingProp=n); | ||
401 | *and the value may have VCGrouping property | ||
402 | */ | ||
403 | t = addProp(t,VCGroupingProp); | ||
404 | setVObjectStringZValue(t,lookupProp_(n)); | ||
405 | } while (n != gs); | ||
406 | deleteStr(gs); | ||
407 | return p; | ||
408 | } | ||
409 | else | ||
410 | return addProp_(o,lookupProp(g)); | ||
411 | } | ||
412 | |||
413 | VObject* 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 | |||
421 | VObject* addPropSizedValue_(VObject *o, const char *p, const char *v, | ||
422 | unsigned int size) | ||
423 | { | ||
424 | VObject *prop; | ||
425 | prop = addProp(o,p); | ||
426 | setValueWithSize_(prop, (void*)v, size); | ||
427 | return prop; | ||
428 | } | ||
429 | |||
430 | VObject* addPropSizedValue(VObject *o, const char *p, const char *v, | ||
431 | unsigned int size) | ||
432 | { | ||
433 | return addPropSizedValue_(o,p,dupStr(v,size),size); | ||
434 | } | ||
435 | |||
436 | |||
437 | |||
438 | /*---------------------------------------------------------------------- | ||
439 | The following pretty print a VObject | ||
440 | ----------------------------------------------------------------------*/ | ||
441 | |||
442 | static void printVObject_(FILE *fp, VObject *o, int level); | ||
443 | |||
444 | static void indent(FILE *fp, int level) | ||
445 | { | ||
446 | int i; | ||
447 | for (i=0;i<level*4;i++) { | ||
448 | fputc(' ', fp); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | static 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 | |||
498 | static 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 | |||
511 | static 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 | |||
526 | void printVObject(FILE *fp,VObject *o) | ||
527 | { | ||
528 | printVObject_(fp,o,0); | ||
529 | } | ||
530 | |||
531 | void 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 | |||
540 | void 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 | |||
552 | void 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 | |||
586 | void 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 | |||
601 | static StrItem *strTbl[STRTBLSIZE]; | ||
602 | |||
603 | static 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 | |||
613 | const 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 | |||
633 | void 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 | |||
662 | void 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 | |||
679 | struct 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 | |||
690 | static const char *adrFields[] = { | ||
691 | VCPostalBoxProp, | ||
692 | VCExtAddressProp, | ||
693 | VCStreetAddressProp, | ||
694 | VCCityProp, | ||
695 | VCRegionProp, | ||
696 | VCPostalCodeProp, | ||
697 | VCCountryNameProp, | ||
698 | 0 | ||
699 | }; | ||
700 | |||
701 | static const char *nameFields[] = { | ||
702 | VCFamilyNameProp, | ||
703 | VCGivenNameProp, | ||
704 | VCAdditionalNamesProp, | ||
705 | VCNamePrefixesProp, | ||
706 | VCNameSuffixesProp, | ||
707 | NULL | ||
708 | }; | ||
709 | |||
710 | static const char *orgFields[] = { | ||
711 | VCOrgNameProp, | ||
712 | VCOrgUnitProp, | ||
713 | VCOrgUnit2Prop, | ||
714 | VCOrgUnit3Prop, | ||
715 | VCOrgUnit4Prop, | ||
716 | NULL | ||
717 | }; | ||
718 | |||
719 | static 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 | |||
730 | static const char *DAlarmFields[] = { | ||
731 | VCRunTimeProp, | ||
732 | VCSnoozeTimeProp, | ||
733 | VCRepeatCountProp, | ||
734 | VCDisplayStringProp, | ||
735 | 0 | ||
736 | }; | ||
737 | |||
738 | static const char *MAlarmFields[] = { | ||
739 | VCRunTimeProp, | ||
740 | VCSnoozeTimeProp, | ||
741 | VCRepeatCountProp, | ||
742 | VCEmailAddressProp, | ||
743 | VCNoteProp, | ||
744 | 0 | ||
745 | }; | ||
746 | |||
747 | static const char *PAlarmFields[] = { | ||
748 | VCRunTimeProp, | ||
749 | VCSnoozeTimeProp, | ||
750 | VCRepeatCountProp, | ||
751 | VCProcedureNameProp, | ||
752 | 0 | ||
753 | }; | ||
754 | |||
755 | static 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 | |||
918 | static 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 | |||
932 | const 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 | |||
946 | const 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 | ||
966 | typedef 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 | |||
980 | static 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 { | ||
989 | stuff: | ||
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 | |||
1011 | static void appendcOFile(OFile *fp, char c) | ||
1012 | { | ||
1013 | if (fp->fail) return; | ||
1014 | if (fp->fp) { | ||
1015 | fputc(c,fp->fp); | ||
1016 | } | ||
1017 | else { | ||
1018 | stuff: | ||
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 | |||
1038 | static void appendcOFile_(OFile *fp, char c) | ||
1039 | { | ||
1040 | if (fp->fail) return; | ||
1041 | if (fp->fp) { | ||
1042 | fputc(c,fp->fp); | ||
1043 | } | ||
1044 | else { | ||
1045 | stuff: | ||
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 | |||
1063 | static 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 | |||
1074 | static 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 | |||
1085 | static 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 | |||
1095 | static 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 | |||
1106 | static 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. */ | ||
1149 | static 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 | |||
1164 | static void writeVObject_(OFile *fp, VObject *o); | ||
1165 | |||
1166 | static 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 | |||
1210 | static 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 | |||
1227 | static 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 | |||
1242 | static 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 | |||
1252 | static 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 | |||
1307 | static 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 | |||
1331 | void writeVObject(FILE *fp, VObject *o) | ||
1332 | { | ||
1333 | OFile ofp; | ||
1334 | initOFile(&ofp,fp); | ||
1335 | writeVObject_(&ofp,o); | ||
1336 | } | ||
1337 | |||
1338 | void 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 | |||
1347 | void 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 | |||
1359 | char* 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 | |||
1369 | char* 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 | ----------------------------------------------------------------------*/ | ||
1385 | wchar_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 | |||
1408 | int uStrLen(const wchar_t *u) | ||
1409 | { | ||
1410 | int i = 0; | ||
1411 | while (*u != (wchar_t)0) { u++; i++; } | ||
1412 | return i; | ||
1413 | } | ||
1414 | |||
1415 | char* 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 | ||
3 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
4 | |||
5 | For purposes of this license notice, the term Licensors shall mean, | ||
6 | collectively, Apple Computer, Inc., AT&T Corp., International | ||
7 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
8 | The term Licensor shall mean any of the Licensors. | ||
9 | |||
10 | Subject to acceptance of the following conditions, permission is hereby | ||
11 | granted by Licensors without the need for written agreement and without | ||
12 | license or royalty fees, to use, copy, modify and distribute this | ||
13 | software for any purpose. | ||
14 | |||
15 | The above copyright notice and the following four paragraphs must be | ||
16 | reproduced in all copies of this software and any software including | ||
17 | this software. | ||
18 | |||
19 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE | ||
20 | ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR | ||
21 | MODIFICATIONS. | ||
22 | |||
23 | IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, | ||
24 | INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT | ||
25 | OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
26 | DAMAGE. | ||
27 | |||
28 | EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, | ||
29 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE | ||
30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
31 | PURPOSE. | ||
32 | |||
33 | The software is provided with RESTRICTED RIGHTS. Use, duplication, or | ||
34 | disclosure by the government are subject to restrictions set forth in | ||
35 | DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. | ||
36 | |||
37 | ***************************************************************************/ | ||
38 | |||
39 | /* | ||
40 | |||
41 | The vCard/vCalendar C interface is implemented in the set | ||
42 | of files as follows: | ||
43 | |||
44 | vcc.y, yacc source, and vcc.c, the yacc output you will use | ||
45 | implements the core parser | ||
46 | |||
47 | vobject.c implements an API that insulates the caller from | ||
48 | the parser and changes in the vCard/vCalendar BNF | ||
49 | |||
50 | port.h defines compilation environment dependent stuff | ||
51 | |||
52 | vcc.h and vobject.h are header files for their .c counterparts | ||
53 | |||
54 | vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions | ||
55 | which you may find useful. | ||
56 | |||
57 | test.c is a standalone test driver that exercises some of | ||
58 | the features of the APIs provided. Invoke test.exe on a | ||
59 | VCARD/VCALENDAR input text file and you will see the pretty | ||
60 | print output of the internal representation (this pretty print | ||
61 | output should give you a good idea of how the internal | ||
62 | representation looks like -- there is one such output in the | ||
63 | following too). Also, a file with the .out suffix is generated | ||
64 | to show that the internal representation can be written back | ||
65 | in the original text format. | ||
66 | |||
67 | For more information on this API see the readme.txt file | ||
68 | which accompanied this distribution. | ||
69 | |||
70 | Also visit: | ||
71 | |||
72 | http://www.versit.com | ||
73 | http://www.ralden.com | ||
74 | |||
75 | */ | ||
76 | |||
77 | |||
78 | #ifndef __VOBJECT_H__ | ||
79 | #define __VOBJECT_H__ 1 | ||
80 | |||
81 | |||
82 | #include "port.h" | ||
83 | #include <stdlib.h> | ||
84 | #include <stdio.h> | ||
85 | |||
86 | #if defined(__CPLUSPLUS__) || defined(__cplusplus) | ||
87 | extern "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 | |||
259 | typedef struct VObject VObject; | ||
260 | |||
261 | typedef 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 | |||
270 | struct VObject { | ||
271 | VObject *next; | ||
272 | const char *id; | ||
273 | VObject *prop; | ||
274 | unsigned short valType; | ||
275 | ValueItem val; | ||
276 | }; | ||
277 | |||
278 | typedef struct StrItem StrItem; | ||
279 | |||
280 | struct StrItem { | ||
281 | StrItem *next; | ||
282 | const char *s; | ||
283 | unsigned int refCnt; | ||
284 | }; | ||
285 | |||
286 | typedef struct VObjectIterator { | ||
287 | VObject* start; | ||
288 | VObject* next; | ||
289 | } VObjectIterator; | ||
290 | |||
291 | extern VObject* newVObject(const char *id); | ||
292 | extern void deleteVObject(VObject *p); | ||
293 | extern char* dupStr(const char *s, unsigned int size); | ||
294 | extern void deleteStr(const char *p); | ||
295 | extern void unUseStr(const char *s); | ||
296 | |||
297 | extern void setVObjectName(VObject *o, const char* id); | ||
298 | extern void setVObjectStringZValue(VObject *o, const char *s); | ||
299 | extern void setVObjectStringZValue_(VObject *o, const char *s); | ||
300 | extern void setVObjectUStringZValue(VObject *o, const wchar_t *s); | ||
301 | extern void setVObjectUStringZValue_(VObject *o, const wchar_t *s); | ||
302 | extern void setVObjectIntegerValue(VObject *o, unsigned int i); | ||
303 | extern void setVObjectLongValue(VObject *o, unsigned long l); | ||
304 | extern void setVObjectAnyValue(VObject *o, void *t); | ||
305 | extern VObject* setValueWithSize(VObject *prop, void *val, unsigned int size); | ||
306 | extern VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size); | ||
307 | |||
308 | extern const char* vObjectName(VObject *o); | ||
309 | extern const char* vObjectStringZValue(VObject *o); | ||
310 | extern const wchar_t* vObjectUStringZValue(VObject *o); | ||
311 | extern unsigned int vObjectIntegerValue(VObject *o); | ||
312 | extern unsigned long vObjectLongValue(VObject *o); | ||
313 | extern void* vObjectAnyValue(VObject *o); | ||
314 | extern VObject* vObjectVObjectValue(VObject *o); | ||
315 | extern void setVObjectVObjectValue(VObject *o, VObject *p); | ||
316 | |||
317 | extern VObject* addVObjectProp(VObject *o, VObject *p); | ||
318 | extern VObject* addProp(VObject *o, const char *id); | ||
319 | extern VObject* addProp_(VObject *o, const char *id); | ||
320 | extern VObject* addPropValue(VObject *o, const char *p, const char *v); | ||
321 | extern VObject* addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size); | ||
322 | extern VObject* addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size); | ||
323 | extern VObject* addGroup(VObject *o, const char *g); | ||
324 | extern void addList(VObject **o, VObject *p); | ||
325 | |||
326 | extern VObject* isAPropertyOf(VObject *o, const char *id); | ||
327 | |||
328 | extern VObject* nextVObjectInList(VObject *o); | ||
329 | extern void initPropIterator(VObjectIterator *i, VObject *o); | ||
330 | extern int moreIteration(VObjectIterator *i); | ||
331 | extern VObject* nextVObject(VObjectIterator *i); | ||
332 | |||
333 | extern char* writeMemVObject(char *s, int *len, VObject *o); | ||
334 | extern char* writeMemVObjects(char *s, int *len, VObject *list); | ||
335 | |||
336 | extern const char* lookupStr(const char *s); | ||
337 | extern void cleanStrTbl(); | ||
338 | |||
339 | extern void cleanVObject(VObject *o); | ||
340 | extern void cleanVObjects(VObject *list); | ||
341 | |||
342 | extern const char* lookupProp(const char* str); | ||
343 | extern const char* lookupProp_(const char* str); | ||
344 | |||
345 | extern wchar_t* fakeUnicode(const char *ps, int *bytes); | ||
346 | extern int uStrLen(const wchar_t *u); | ||
347 | extern char* fakeCString(const wchar_t *u); | ||
348 | |||
349 | extern void printVObjectToFile(char *fname,VObject *o); | ||
350 | extern void printVObjectsToFile(char *fname,VObject *list); | ||
351 | extern void writeVObjectToFile(char *fname, VObject *o); | ||
352 | extern void writeVObjectsToFile(char *fname, VObject *list); | ||
353 | |||
354 | extern 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 | |||
372 | extern const char** fieldedProp; | ||
373 | |||
374 | extern void printVObject(FILE *fp,VObject *o); | ||
375 | extern void writeVObject(FILE *fp, VObject *o); | ||
376 | |||
377 | |||
378 | #if defined(__CPLUSPLUS__) || defined(__cplusplus) | ||
379 | } | ||
380 | #endif | ||
381 | |||
382 | #endif /* __VOBJECT_H__ */ | ||
383 | |||
384 | |||