3 /// Conversion routines for vtodos (VCALENDAR, etc)
7 Copyright (C) 2008-2009, Nicolas VIVIEN
8 Copyright (C) 2006-2012, Net Direct Inc. (http://www.netdirect.ca/)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
31 namespace Barry
{ namespace Sync
{
33 //////////////////////////////////////////////////////////////////////////////
37 static void ToLower(std::string
&str
)
40 while( i
< str
.size() ) {
41 str
[i
] = tolower(str
[i
]);
47 //////////////////////////////////////////////////////////////////////////////
50 vTodo::vTodo(vTimeConverter
&vtc
)
63 bool vTodo::HasMultipleVTodos() const
66 b_VFormat
*format
= const_cast<b_VFormat
*>(Format());
67 GList
*attrs
= format
? b_vformat_get_attributes(format
) : 0;
68 for( ; attrs
; attrs
= attrs
->next
) {
69 b_VFormatAttribute
*attr
= (b_VFormatAttribute
*) attrs
->data
;
70 if( strcasecmp(b_vformat_attribute_get_name(attr
), "BEGIN") == 0 &&
71 strcasecmp(b_vformat_attribute_get_nth_value(attr
, 0), "VTODO") == 0 )
80 // Main conversion routine for converting from Barry::Task to
81 // a vTodo string of data.
82 const std::string
& vTodo::ToTask(const Barry::Task
&task
)
84 // Trace trace("vTodo::ToTask");
85 std::ostringstream oss
;
87 // trace.logf("ToTask, initial Barry record: %s", oss.str().c_str());
91 SetFormat( b_vformat_new() );
93 throw ConvertError("resource error allocating vformat");
95 // store the Barry object we're working with
98 // RFC section 4.8.7.2 requires DTSTAMP in all VEVENT, VTODO,
99 // VJOURNAL, and VFREEBUSY calendar components, and it must be
100 // in UTC. DTSTAMP holds the timestamp of when the iCal object itself
101 // was created, not when the object was created in the device or app.
102 // So, find out what time it is "now".
103 time_t now
= time(NULL
);
105 // begin building vCalendar data
106 AddAttr(NewAttr("PRODID", "-//OpenSync//NONSGML Barry Task Record//EN"));
107 AddAttr(NewAttr("BEGIN", "VTODO"));
108 AddAttr(NewAttr("DTSTAMP", m_vtc
.unix2vtime(&now
).c_str())); // see note above
109 AddAttr(NewAttr("SEQUENCE", "0"));
110 AddAttr(NewAttr("SUMMARY", task
.Summary
.c_str()));
111 AddAttr(NewAttr("DESCRIPTION", task
.Notes
.c_str()));
112 AddAttr(NewAttr("CATEGORIES", ToStringList(task
.Categories
).c_str()));
115 if (task
.StatusFlag
== Barry::Task::InProgress
)
116 AddAttr(NewAttr("STATUS", "IN-PROCESS"));
117 else if (task
.StatusFlag
== Barry::Task::Completed
)
118 AddAttr(NewAttr("STATUS", "COMPLETED"));
119 else if (task
.StatusFlag
== Barry::Task::Deferred
)
120 AddAttr(NewAttr("STATUS", "CANCELLED"));
121 else if (task
.StatusFlag
== Barry::Task::Waiting
)
122 AddAttr(NewAttr("STATUS", "NEEDS-ACTION"));
125 if (task
.PriorityFlag
== Barry::Task::High
)
126 AddAttr(NewAttr("PRIORITY", "3"));
127 else if (task
.PriorityFlag
== Barry::Task::Normal
)
128 AddAttr(NewAttr("PRIORITY", "5"));
130 AddAttr(NewAttr("PRIORITY", "7"));
133 if( task
.StartTime
.Time
) {
134 AddAttr(NewAttr("DTSTART",
135 m_vtc
.unix2vtime(&task
.StartTime
.Time
).c_str()));
139 if( task
.DueDateFlag
) {
140 AddAttr(NewAttr("DUE",
141 m_vtc
.unix2vtime(&task
.DueTime
.Time
).c_str()));
144 // FIXME - add a truly globally unique "UID" string?
146 AddAttr(NewAttr("END", "VTODO"));
148 // generate the raw VTODO data
149 m_gTodoData
= b_vformat_to_string(Format(), VFORMAT_TODO_20
);
150 m_vTodoData
= m_gTodoData
;
152 // trace.logf("ToTask, resulting vtodo data: %s", m_vTodoData.c_str());
156 // Main conversion routine for converting from vTodo data string
157 // to a Barry::Task object.
158 const Barry::Task
& vTodo::ToBarry(const char *vtodo
, uint32_t RecordId
)
162 // Trace trace("vTodo::ToBarry");
163 // trace.logf("ToBarry, working on vtodo data: %s", vtodo);
165 // we only handle vTodo data with one vtodo block
166 if( HasMultipleVTodos() )
167 throw ConvertError("vCalendar data contains more than one VTODO block, unsupported");
172 // store the vTodo raw data
175 // create format parser structures
176 SetFormat( b_vformat_new_from_string(vtodo
) );
178 throw ConvertError("resource error allocating vtodo");
180 string summary
= GetAttr("SUMMARY", "/vtodo");
181 // trace.logf("SUMMARY attr retrieved: %s", summary.c_str());
182 if( summary
.size() == 0 ) {
183 summary
= "<blank subject>";
184 // trace.logf("ERROR: bad data, blank SUMMARY: %s", vtodo);
187 string notes
= GetAttr("DESCRIPTION", "/vtodo");
188 // trace.logf("DESCRIPTION attr retrieved: %s", notes.c_str());
190 string status
= GetAttr("STATUS", "/vtodo");
191 // trace.logf("STATUS attr retrieved: %s", status.c_str());
193 string priority
= GetAttr("PRIORITY", "/vtodo");
194 // trace.logf("PRIORITY attr retrieved: %s", priority.c_str());
196 string start
= GetAttr("DTSTART", "/vtodo");
197 // trace.logf("DTSTART attr retrieved: %s", start.c_str());
199 string due
= GetAttr("DUE", "/vtodo");
200 // trace.logf("DUE attr retrieved: %s", due.c_str());
204 // Now, run checks and convert into Barry object
207 // FIXME - we are assuming that any non-UTC timestamps
208 // in the vcalendar record will be in the current timezone...
209 // This is wrong! fix this later.
211 // Also, we current ignore any time zone
212 // parameters that might be in the vcalendar format... this
216 Barry::Task
&rec
= m_BarryTask
;
217 rec
.SetIds(Barry::Task::GetDefaultRecType(), RecordId
);
221 rec
.Categories
= GetValueVector("CATEGORIES","/vtodo");
223 // SUMMARY & DESCRIPTION fields
224 rec
.Summary
= summary
;
231 const char *s
= status
.c_str();
233 if (strstr(s
, "in-process"))
234 rec
.StatusFlag
= Barry::Task::InProgress
;
235 else if (strstr(s
, "completed"))
236 rec
.StatusFlag
= Barry::Task::Completed
;
237 else if (strstr(s
, "cancelled"))
238 rec
.StatusFlag
= Barry::Task::Deferred
;
239 else if (strstr(s
, "needs-action"))
240 rec
.StatusFlag
= Barry::Task::Waiting
;
242 rec
.StatusFlag
= Barry::Task::NotStarted
;
246 if (priority
.size()) {
249 const char *s
= priority
.c_str();
251 const int val
= atoi(s
);
254 rec
.PriorityFlag
= Barry::Task::High
;
256 rec
.PriorityFlag
= Barry::Task::Normal
;
258 rec
.PriorityFlag
= Barry::Task::Low
;
262 // STARTTIME & DUETIME
264 rec
.StartTime
.Time
= m_vtc
.vtime2unix(start
.c_str());
268 rec
.DueDateFlag
= true;
269 rec
.DueTime
.Time
= m_vtc
.vtime2unix(due
.c_str());
272 std::ostringstream oss
;
273 m_BarryTask
.Dump(oss
);
274 // trace.logf("ToBarry, resulting Barry record: %s", oss.str().c_str());
278 // Transfers ownership of m_gTaskData to the caller.
279 char* vTodo::ExtractVTodo()
281 char *ret
= m_gTodoData
;
298 }} // namespace Barry::Sync