# vtodo.cc

    00001 //
    00002 // \file        vtodo.cc
    00003 //              Conversion routines for vtodos (VCALENDAR, etc)
    00004 //
    00005
    00006 /*
    00007     Copyright (C) 2008-2009, Nicolas VIVIEN
    00008     Copyright (C) 2006-2011, Net Direct Inc. (http://www.netdirect.ca/)
    00009
    00010     This program is free software; you can redistribute it and/or modify
    00011     it under the terms of the GNU General Public License as published by
    00012     the Free Software Foundation; either version 2 of the License, or
    00013     (at your option) any later version.
    00014
    00015     This program is distributed in the hope that it will be useful,
    00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00018
    00019     See the GNU General Public License in the COPYING file at the
    00020     root directory of this project for more details.
    00021 */
    00022
    00023 #include "vtodo.h"
    00024 //#include "trace.h"
    00025 #include <stdint.h>
    00026 #include <stdlib.h>
    00027 #include <glib.h>
    00028 #include <string.h>
    00029 #include <sstream>
    00030
    00031 namespace Barry { namespace Sync {
    00032
    00033 //////////////////////////////////////////////////////////////////////////////
    00034 // Utility functions
    00035
    00036 namespace {
    00037         static void ToLower(std::string &str)
    00038         {
    00039                 size_t i = 0;
    00040                 while( i < str.size() ) {
    00041                         str[i] = tolower(str[i]);
    00042                         i++;
    00043                 }
    00044         }
    00045 }
    00046
    00047 //////////////////////////////////////////////////////////////////////////////
    00048 // vTodo
    00049
    00050 vTodo::vTodo(vTimeConverter &vtc)
    00051         : m_vtc(vtc)
    00052         , m_gTodoData(0)
    00053 {
    00054 }
    00055
    00056 vTodo::~vTodo()
    00057 {
    00058         if( m_gTodoData ) {
    00059                 g_free(m_gTodoData);
    00060         }
    00061 }
    00062
    00063 bool vTodo::HasMultipleVTodos() const
    00064 {
    00065         int count = 0;
    00066         b_VFormat *format = const_cast<b_VFormat*>(Format());
    00067         GList *attrs = format ? b_vformat_get_attributes(format) : 0;
    00068         for( ; attrs; attrs = attrs->next ) {
    00069                 b_VFormatAttribute *attr = (b_VFormatAttribute*) attrs->data;
    00070                 if( strcasecmp(b_vformat_attribute_get_name(attr), "BEGIN") == 0 &&
    00071                     strcasecmp(b_vformat_attribute_get_nth_value(attr, 0), "VTODO") == 0 )
    00072                 {
    00073                         count++;
    00074                 }
    00075         }
    00076         return count > 1;
    00077 }
    00078
    00079
    00080 // Main conversion routine for converting from Barry::Task to
    00081 // a vTodo string of data.
    00082 const std::string& vTodo::ToTask(const Barry::Task &task)
    00083 {
    00084 //      Trace trace("vTodo::ToTask");
    00085         std::ostringstream oss;
    00086         task.Dump(oss);
    00087 //      trace.logf("ToTask, initial Barry record: %s", oss.str().c_str());
    00088
    00089         // start fresh
    00090         Clear();
    00091         SetFormat( b_vformat_new() );
    00092         if( !Format() )
    00093                 throw ConvertError("resource error allocating vformat");
    00094
    00095         // store the Barry object we're working with
    00096         m_BarryTask = task;
    00097
    00098         // begin building vCalendar data
    00099         AddAttr(NewAttr("PRODID", "-//OpenSync//NONSGML Barry Task Record//EN"));
    00100         AddAttr(NewAttr("BEGIN", "VTODO"));
    00101         AddAttr(NewAttr("SEQUENCE", "0"));
    00102         AddAttr(NewAttr("SUMMARY", task.Summary.c_str()));
    00103         AddAttr(NewAttr("DESCRIPTION", task.Notes.c_str()));
    00104         AddAttr(NewAttr("CATEGORIES", ToStringList(task.Categories).c_str()));
    00105
    00106         // Status
    00107         if (task.StatusFlag == Barry::Task::InProgress)
    00108                 AddAttr(NewAttr("STATUS", "IN-PROCESS"));
    00109         else if (task.StatusFlag == Barry::Task::Completed)
    00110                 AddAttr(NewAttr("STATUS", "COMPLETED"));
    00111         else if (task.StatusFlag == Barry::Task::Deferred)
    00112                 AddAttr(NewAttr("STATUS", "CANCELLED"));
    00113         else if (task.StatusFlag == Barry::Task::Waiting)
    00114                 AddAttr(NewAttr("STATUS", "NEEDS-ACTION"));
    00115
    00116         // Priority
    00117         if (task.PriorityFlag == Barry::Task::High)
    00118                 AddAttr(NewAttr("PRIORITY", "3"));
    00119         else if (task.PriorityFlag == Barry::Task::Normal)
    00120                 AddAttr(NewAttr("PRIORITY", "5"));
    00121         else
    00122                 AddAttr(NewAttr("PRIORITY", "7"));
    00123
    00124         // StartTime
    00125         if( task.StartTime ) {
    00126                 AddAttr(NewAttr("DTSTART",
    00127                         m_vtc.unix2vtime(&task.StartTime).c_str()));
    00128         }
    00129
    00130         // DueTime DueFlag
    00131         if( task.DueDateFlag ) {
    00132                 AddAttr(NewAttr("DUE",
    00133                         m_vtc.unix2vtime(&task.DueTime).c_str()));
    00134         }
    00135
    00136         // FIXME - add a truly globally unique "UID" string?
    00137
    00138         AddAttr(NewAttr("END", "VTODO"));
    00139
    00140         // generate the raw VTODO data
    00141         m_gTodoData = b_vformat_to_string(Format(), VFORMAT_TODO_20);
    00142         m_vTodoData = m_gTodoData;
    00143
    00144 //      trace.logf("ToTask, resulting vtodo data: %s", m_vTodoData.c_str());
    00145         return m_vTodoData;
    00146 }
    00147
    00148 // Main conversion routine for converting from vTodo data string
    00149 // to a Barry::Task object.
    00150 const Barry::Task& vTodo::ToBarry(const char *vtodo, uint32_t RecordId)
    00151 {
    00152         using namespace std;
    00153
    00154 //      Trace trace("vTodo::ToBarry");
    00155 //      trace.logf("ToBarry, working on vtodo data: %s", vtodo);
    00156
    00157         // we only handle vTodo data with one vtodo block
    00158         if( HasMultipleVTodos() )
    00159                 throw ConvertError("vCalendar data contains more than one VTODO block, unsupported");
    00160
    00161         // start fresh
    00162         Clear();
    00163
    00164         // store the vTodo raw data
    00165         m_vTodoData = vtodo;
    00166
    00167         // create format parser structures
    00168         SetFormat( b_vformat_new_from_string(vtodo) );
    00169         if( !Format() )
    00170                 throw ConvertError("resource error allocating vtodo");
    00171
    00172         string summary = GetAttr("SUMMARY", "/vtodo");
    00173 //      trace.logf("SUMMARY attr retrieved: %s", summary.c_str());
    00174         if( summary.size() == 0 ) {
    00175                 summary = "<blank subject>";
    00176 //              trace.logf("ERROR: bad data, blank SUMMARY: %s", vtodo);
    00177         }
    00178
    00179         string notes = GetAttr("DESCRIPTION", "/vtodo");
    00180 //      trace.logf("DESCRIPTION attr retrieved: %s", notes.c_str());
    00181
    00182         string status = GetAttr("STATUS", "/vtodo");
    00183 //      trace.logf("STATUS attr retrieved: %s", status.c_str());
    00184
    00185         string priority = GetAttr("PRIORITY", "/vtodo");
    00186 //      trace.logf("PRIORITY attr retrieved: %s", priority.c_str());
    00187
    00188         string start = GetAttr("DTSTART", "/vtodo");
    00189 //      trace.logf("DTSTART attr retrieved: %s", start.c_str());
    00190
    00191         string due = GetAttr("DUE", "/vtodo");
    00192 //      trace.logf("DUE attr retrieved: %s", due.c_str());
    00193
    00194
    00195         //
    00196         // Now, run checks and convert into Barry object
    00197         //
    00198
    00199         // FIXME - we are assuming that any non-UTC timestamps
    00200         // in the vcalendar record will be in the current timezone...
    00201         // This is wrong!  fix this later.
    00202         //
    00203         // Also, we current ignore any time zone
    00204         // parameters that might be in the vcalendar format... this
    00205         // must be fixed.
    00206         //
    00207
    00208         Barry::Task &rec = m_BarryTask;
    00209         rec.SetIds(Barry::Task::GetDefaultRecType(), RecordId);
    00210
    00211         // Categories
    00212
    00213         rec.Categories = GetValueVector("CATEGORIES","/vtodo");
    00214
    00215         // SUMMARY & DESCRIPTION fields
    00216         rec.Summary = summary;
    00217         rec.Notes = notes;
    00218
    00219         // STATUS field
    00220         if (status.size()) {
    00221                 ToLower(status);
    00222
    00223                 const char *s = status.c_str();
    00224
    00225                 if (strstr(s, "in-process"))
    00226                         rec.StatusFlag = Barry::Task::InProgress;
    00227                 else if (strstr(s, "completed"))
    00228                         rec.StatusFlag = Barry::Task::Completed;
    00229                 else if (strstr(s, "cancelled"))
    00230                         rec.StatusFlag = Barry::Task::Deferred;
    00231                 else if (strstr(s, "needs-action"))
    00232                         rec.StatusFlag = Barry::Task::Waiting;
    00233                 else
    00234                         rec.StatusFlag = Barry::Task::NotStarted;
    00235         }
    00236
    00237         // PRIORITY field
    00238         if (priority.size()) {
    00239                 ToLower(priority);
    00240
    00241                 const char *s = priority.c_str();
    00242
    00243                 const int val = atoi(s);
    00244
    00245                 if (val < 4)
    00246                         rec.PriorityFlag = Barry::Task::High;
    00247                 else if (val < 7)
    00248                         rec.PriorityFlag = Barry::Task::Normal;
    00249                 else
    00250                         rec.PriorityFlag = Barry::Task::Low;
    00251         }
    00252
    00253
    00254         // STARTTIME & DUETIME
    00255         if (start.size()) {
    00256                 rec.StartTime = m_vtc.vtime2unix(start.c_str());
    00257         }
    00258
    00259         if (due.size()) {
    00260                 rec.DueDateFlag = true;
    00261                 rec.DueTime = m_vtc.vtime2unix(due.c_str());
    00262         }
    00263
    00264         std::ostringstream oss;
    00265         m_BarryTask.Dump(oss);
    00266 //      trace.logf("ToBarry, resulting Barry record: %s", oss.str().c_str());
    00267         return m_BarryTask;
    00268 }
    00269
    00270 // Transfers ownership of m_gTaskData to the caller.
    00271 char* vTodo::ExtractVTodo()
    00272 {
    00273         char *ret = m_gTodoData;
    00274         m_gTodoData = 0;
    00275         return ret;
    00276 }
    00277
    00278 void vTodo::Clear()
    00279 {
    00280         vBase::Clear();
    00281         m_vTodoData.clear();
    00282         m_BarryTask.Clear();
    00283
    00284         if( m_gTodoData ) {
    00285                 g_free(m_gTodoData);
    00286                 m_gTodoData = 0;
    00287         }
    00288 }
    00289
    00290 }} // namespace Barry::Sync
    00291