menu: added new Keywords tag to .desktop files
[barry.git] / src / vtodo.cc
blob27d60c460f5473419ef531414d7b2a8f7d9a5ea6
1 ///
2 /// \file vtodo.cc
3 /// Conversion routines for vtodos (VCALENDAR, etc)
4 ///
6 /*
7 Copyright (C) 2008-2009, Nicolas VIVIEN
8 Copyright (C) 2006-2013, 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.
23 #include "i18n.h"
24 #include "vtodo.h"
25 //#include "trace.h"
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <glib.h>
29 #include <string.h>
30 #include <sstream>
32 namespace Barry { namespace Sync {
34 //////////////////////////////////////////////////////////////////////////////
35 // Utility functions
37 namespace {
38 static void ToLower(std::string &str)
40 size_t i = 0;
41 while( i < str.size() ) {
42 str[i] = tolower(str[i]);
43 i++;
48 //////////////////////////////////////////////////////////////////////////////
49 // vTodo
51 vTodo::vTodo(vTimeConverter &vtc)
52 : m_vtc(vtc)
53 , m_gTodoData(0)
57 vTodo::~vTodo()
59 if( m_gTodoData ) {
60 g_free(m_gTodoData);
64 bool vTodo::HasMultipleVTodos() const
66 int count = 0;
67 b_VFormat *format = const_cast<b_VFormat*>(Format());
68 GList *attrs = format ? b_vformat_get_attributes(format) : 0;
69 for( ; attrs; attrs = attrs->next ) {
70 b_VFormatAttribute *attr = (b_VFormatAttribute*) attrs->data;
71 if( strcasecmp(b_vformat_attribute_get_name(attr), "BEGIN") == 0 &&
72 strcasecmp(b_vformat_attribute_get_nth_value(attr, 0), "VTODO") == 0 )
74 count++;
77 return count > 1;
81 // Main conversion routine for converting from Barry::Task to
82 // a vTodo string of data.
83 const std::string& vTodo::ToTask(const Barry::Task &task)
85 // Trace trace("vTodo::ToTask");
86 std::ostringstream oss;
87 task.Dump(oss);
88 // trace.logf("ToTask, initial Barry record: %s", oss.str().c_str());
90 // start fresh
91 Clear();
92 SetFormat( b_vformat_new() );
93 if( !Format() )
94 throw ConvertError(_("resource error allocating vformat"));
96 // store the Barry object we're working with
97 m_BarryTask = task;
99 // RFC section 4.8.7.2 requires DTSTAMP in all VEVENT, VTODO,
100 // VJOURNAL, and VFREEBUSY calendar components, and it must be
101 // in UTC. DTSTAMP holds the timestamp of when the iCal object itself
102 // was created, not when the object was created in the device or app.
103 // So, find out what time it is "now".
104 time_t now = time(NULL);
106 // begin building vCalendar data
107 AddAttr(NewAttr("PRODID", "-//OpenSync//NONSGML Barry Task Record//EN"));
108 AddAttr(NewAttr("BEGIN", "VTODO"));
109 AddAttr(NewAttr("DTSTAMP", m_vtc.unix2vtime(&now).c_str())); // see note above
110 AddAttr(NewAttr("SEQUENCE", "0"));
111 AddAttr(NewAttr("SUMMARY", task.Summary.c_str()));
112 AddAttr(NewAttr("DESCRIPTION", task.Notes.c_str()));
113 AddAttr(NewAttr("CATEGORIES", ToStringList(task.Categories).c_str()));
115 // Status
116 if (task.StatusFlag == Barry::Task::InProgress)
117 AddAttr(NewAttr("STATUS", "IN-PROCESS"));
118 else if (task.StatusFlag == Barry::Task::Completed)
119 AddAttr(NewAttr("STATUS", "COMPLETED"));
120 else if (task.StatusFlag == Barry::Task::Deferred)
121 AddAttr(NewAttr("STATUS", "CANCELLED"));
122 else if (task.StatusFlag == Barry::Task::Waiting)
123 AddAttr(NewAttr("STATUS", "NEEDS-ACTION"));
125 // Priority
126 if (task.PriorityFlag == Barry::Task::High)
127 AddAttr(NewAttr("PRIORITY", "3"));
128 else if (task.PriorityFlag == Barry::Task::Normal)
129 AddAttr(NewAttr("PRIORITY", "5"));
130 else
131 AddAttr(NewAttr("PRIORITY", "7"));
133 // StartTime
134 if( task.StartTime.Time ) {
135 AddAttr(NewAttr("DTSTART",
136 m_vtc.unix2vtime(&task.StartTime.Time).c_str()));
139 // DueTime DueFlag
140 if( task.DueTime.IsValid() ) {
141 AddAttr(NewAttr("DUE",
142 m_vtc.unix2vtime(&task.DueTime.Time).c_str()));
145 // FIXME - add a truly globally unique "UID" string?
147 AddAttr(NewAttr("END", "VTODO"));
149 // generate the raw VTODO data
150 m_gTodoData = b_vformat_to_string(Format(), VFORMAT_TODO_20);
151 m_vTodoData = m_gTodoData;
153 // trace.logf("ToTask, resulting vtodo data: %s", m_vTodoData.c_str());
154 return m_vTodoData;
157 // Main conversion routine for converting from vTodo data string
158 // to a Barry::Task object.
159 const Barry::Task& vTodo::ToBarry(const char *vtodo, uint32_t RecordId)
161 using namespace std;
163 // Trace trace("vTodo::ToBarry");
164 // trace.logf("ToBarry, working on vtodo data: %s", vtodo);
166 // we only handle vTodo data with one vtodo block
167 if( HasMultipleVTodos() )
168 throw ConvertError(_("vCalendar data contains more than one VTODO block, unsupported"));
170 // start fresh
171 Clear();
173 // store the vTodo raw data
174 m_vTodoData = vtodo;
176 // create format parser structures
177 SetFormat( b_vformat_new_from_string(vtodo) );
178 if( !Format() )
179 throw ConvertError(_("resource error allocating vtodo"));
181 string summary = GetAttr("SUMMARY", "/vtodo");
182 // trace.logf("SUMMARY attr retrieved: %s", summary.c_str());
183 if( summary.size() == 0 ) {
184 summary = "<blank subject>";
185 // trace.logf("ERROR: bad data, blank SUMMARY: %s", vtodo);
188 string notes = GetAttr("DESCRIPTION", "/vtodo");
189 // trace.logf("DESCRIPTION attr retrieved: %s", notes.c_str());
191 string status = GetAttr("STATUS", "/vtodo");
192 // trace.logf("STATUS attr retrieved: %s", status.c_str());
194 string priority = GetAttr("PRIORITY", "/vtodo");
195 // trace.logf("PRIORITY attr retrieved: %s", priority.c_str());
197 string start = GetAttr("DTSTART", "/vtodo");
198 // trace.logf("DTSTART attr retrieved: %s", start.c_str());
200 string due = GetAttr("DUE", "/vtodo");
201 // trace.logf("DUE attr retrieved: %s", due.c_str());
205 // Now, run checks and convert into Barry object
208 // FIXME - we are assuming that any non-UTC timestamps
209 // in the vcalendar record will be in the current timezone...
210 // This is wrong! fix this later.
212 // Also, we current ignore any time zone
213 // parameters that might be in the vcalendar format... this
214 // must be fixed.
217 Barry::Task &rec = m_BarryTask;
218 rec.SetIds(Barry::Task::GetDefaultRecType(), RecordId);
220 // Categories
222 rec.Categories = GetValueVector("CATEGORIES","/vtodo");
224 // SUMMARY & DESCRIPTION fields
225 rec.Summary = summary;
226 rec.Notes = notes;
228 // STATUS field
229 if (status.size()) {
230 ToLower(status);
232 const char *s = status.c_str();
234 if (strstr(s, "in-process"))
235 rec.StatusFlag = Barry::Task::InProgress;
236 else if (strstr(s, "completed"))
237 rec.StatusFlag = Barry::Task::Completed;
238 else if (strstr(s, "cancelled"))
239 rec.StatusFlag = Barry::Task::Deferred;
240 else if (strstr(s, "needs-action"))
241 rec.StatusFlag = Barry::Task::Waiting;
242 else
243 rec.StatusFlag = Barry::Task::NotStarted;
246 // PRIORITY field
247 if (priority.size()) {
248 ToLower(priority);
250 const char *s = priority.c_str();
252 const int val = atoi(s);
254 if (val < 4)
255 rec.PriorityFlag = Barry::Task::High;
256 else if (val < 7)
257 rec.PriorityFlag = Barry::Task::Normal;
258 else
259 rec.PriorityFlag = Barry::Task::Low;
263 // STARTTIME & DUETIME
264 if (start.size()) {
265 rec.StartTime.Time = m_vtc.vtime2unix(start.c_str());
268 if (due.size()) {
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());
275 return m_BarryTask;
278 // Transfers ownership of m_gTaskData to the caller.
279 char* vTodo::ExtractVTodo()
281 char *ret = m_gTodoData;
282 m_gTodoData = 0;
283 return ret;
286 void vTodo::Clear()
288 vBase::Clear();
289 m_vTodoData.clear();
290 m_BarryTask.Clear();
292 if( m_gTodoData ) {
293 g_free(m_gTodoData);
294 m_gTodoData = 0;
298 }} // namespace Barry::Sync