Folks,
Sorry about the very rapid changes :) The attached patch augments my
previous patch to add category support for memos as well.
John.
diff --git a/opensync-plugin-0.4x/src/vbase.cc b/opensync-plugin-0.4x/src/vbase.cc
index b0824ef..cf0f5e2 100644
--- a/opensync-plugin-0.4x/src/vbase.cc
+++ b/opensync-plugin-0.4x/src/vbase.cc
@@ -291,6 +291,38 @@ std::string vBase::GetAttr(const char *attrname, const char *block)
return ret;
}
+std::vector<std::string> vBase::GetValueVector(const char * attrname, const char * block)
+{
+ Trace trace("vBase::GetValueVector");
+ trace.logf("getting value vector for: %s", attrname);
+
+ std::vector<std::string> ret;
+ const char *value = 0;
+ bool needs_freeing = false;
+
+ b_VFormatAttribute *attr = b_vformat_find_attribute(m_format, attrname, 0, block);
+ if( attr ) {
+ if( b_vformat_attribute_is_single_valued(attr) ) {
+ value = b_vformat_attribute_get_value(attr);
+ needs_freeing = true;
+ } else {
+ // nasty, but avoids tweaking vformat.
+ int idx=0;
+ do {
+ value=b_vformat_attribute_get_nth_value(attr,idx++);
+ if(value) {
+ ret.push_back(value);
+ }
+ } while(value);
+ }
+ }
+
+ if( needs_freeing )
+ g_free((char *)value);
+
+ return ret;
+}
+
vAttr vBase::GetAttrObj(const char *attrname, int nth, const char *block)
{
Trace trace("vBase::GetAttrObj");
@@ -299,3 +331,50 @@ vAttr vBase::GetAttrObj(const char *attrname, int nth, const char *block)
return vAttr(b_vformat_find_attribute(m_format, attrname, nth, block));
}
+std::vector<std::string> vBase::Tokenize(const std::string& str, const char delim)
+{
+ std::vector<std::string> tokens;
+ std::string::size_type delimPos = 0, tokenPos = 0, pos = 0;
+
+ if(str.length()<1) {
+ return tokens;
+ }
+
+ while(1) {
+ delimPos = str.find_first_of(delim, pos);
+ tokenPos = str.find_first_not_of(delim, pos);
+
+ if(std::string::npos != delimPos) {
+ if(std::string::npos != tokenPos) {
+ if(tokenPos<delimPos) {
+ tokens.push_back(str.substr(pos,delimPos-pos));
+ } else {
+ tokens.push_back("");
+ }
+ } else {
+ tokens.push_back("");
+ }
+ pos = delimPos+1;
+ } else {
+ if(std::string::npos != tokenPos){
+ tokens.push_back(str.substr(pos));
+ } else {
+ tokens.push_back("");
+ }
+ break;
+ }
+ }
+ return tokens;
+}
+
+std::string vBase::ToStringList(const std::vector<std::string>& list, const char delim)
+{
+ std::string str;
+ for(unsigned int idx=0;idx<list.size();idx++) {
+ if(idx) {
+ str+=delim;
+ }
+ str += list[idx];
+ }
+ return str;
+}
diff --git a/opensync-plugin-0.4x/src/vbase.h b/opensync-plugin-0.4x/src/vbase.h
index e8cfd6c..3acf32c 100644
--- a/opensync-plugin-0.4x/src/vbase.h
+++ b/opensync-plugin-0.4x/src/vbase.h
@@ -23,6 +23,7 @@
#define __BARRY_SYNC_VBASE_H__
#include <string>
+#include <vector>
#include <stdexcept>
#include "vformat.h"
@@ -193,7 +194,12 @@ protected:
void AddParam(vAttrPtr &attr, const char *name, const char *value);
std::string GetAttr(const char *attrname, const char *block = 0);
+ std::vector<std::string> GetValueVector(const char * attrname, const char * block=0);
vAttr GetAttrObj(const char *attrname, int nth = 0, const char *block = 0);
+
+ std::vector<std::string> Tokenize(const std::string& str, const char delim=',');
+ std::string ToStringList(const std::vector<std::string>& list, const char delim=',');
+
};
#endif
diff --git a/opensync-plugin-0.4x/src/vevent.cc b/opensync-plugin-0.4x/src/vevent.cc
index dba4d0d..96dd29d 100644
--- a/opensync-plugin-0.4x/src/vevent.cc
+++ b/opensync-plugin-0.4x/src/vevent.cc
@@ -59,43 +59,6 @@ unsigned short vCalendar::GetWeekDayIndex(const char *dayname)
return 0;
}
-std::vector<std::string> vCalendar::GetDOWList(const std::string& str)
-{
- std::vector<std::string> tokens;
- std::string::size_type delimPos = 0, tokenPos = 0, pos = 0;
-
- if(str.length()<1) {
- return tokens;
- }
-
- while(1) {
- delimPos = str.find_first_of(',', pos);
- tokenPos = str.find_first_not_of(',', pos);
-
- if(std::string::npos != delimPos) {
- if(std::string::npos != tokenPos) {
- if(tokenPos<delimPos) {
- tokens.push_back(str.substr(pos,delimPos-pos));
- } else {
- tokens.push_back("");
- }
- } else {
- tokens.push_back("");
- }
- pos = delimPos+1;
- } else {
- if(std::string::npos != tokenPos){
- tokens.push_back(str.substr(pos));
- } else {
- tokens.push_back("");
- }
- break;
- }
- }
- return tokens;
-}
-
-
unsigned short vCalendar::GetMonthWeekNumFromBYDAY(const std::string& ByDay)
{
return atoi(ByDay.substr(0,ByDay.length()-2).c_str());
@@ -356,7 +319,7 @@ void vCalendar::RecurToBarryCal(vAttr& rrule, time_t starttime)
cal.RecurringType=Calendar::Week;
// we must have a dayofweek entry
if(args.find(string("BYDAY"))!=args.end()) {
- std::vector<std::string> v=GetDOWList(args["BYDAY"]);
+ std::vector<std::string> v=Tokenize(args["BYDAY"]);
// iterate along our vector and convert
for(unsigned int idx=0;idx<v.size();idx++) {
cal.WeekDays|=pmap[v[idx]];
diff --git a/opensync-plugin-0.4x/src/vevent.h b/opensync-plugin-0.4x/src/vevent.h
index 0e8423e..1ff681d 100644
--- a/opensync-plugin-0.4x/src/vevent.h
+++ b/opensync-plugin-0.4x/src/vevent.h
@@ -48,7 +48,6 @@ class vCalendar : public vBase
static const char *WeekDays[7];
- std::vector<std::string> GetDOWList(const std::string& str);
unsigned short GetMonthWeekNumFromBYDAY(const std::string& ByDay);
unsigned short GetWeekDayIndexFromBYDAY(const std::string& ByDay);
diff --git a/opensync-plugin-0.4x/src/vjournal.cc b/opensync-plugin-0.4x/src/vjournal.cc
index 405e62d..57edac9 100644
--- a/opensync-plugin-0.4x/src/vjournal.cc
+++ b/opensync-plugin-0.4x/src/vjournal.cc
@@ -89,6 +89,8 @@ const std::string& vJournal::ToMemo(const Barry::Memo &memo)
AddAttr(NewAttr("SEQUENCE", "0"));
AddAttr(NewAttr("SUMMARY", memo.Title.c_str()));
AddAttr(NewAttr("DESCRIPTION", memo.Body.c_str()));
+ AddAttr(NewAttr("CATEGORIES",ToStringList(memo.Categories).c_str()));
+
// FIXME - add a truly globally unique "UID" string?
@@ -147,6 +149,7 @@ const Barry::Memo& vJournal::ToBarry(const char *vjournal, uint32_t RecordId)
rec.Title = title;
rec.Body = body;
+ rec.Categories=GetValueVector("CATEGORIES","/vjournal");
std::ostringstream oss;
m_BarryMemo.Dump(oss);
@@ -321,4 +324,3 @@ bool VJournalConverter::CommitRecordData(BarryEnvironment *env, unsigned int dbI
return true;
}
-
diff --git a/opensync-plugin-0.4x/src/vjournal.h b/opensync-plugin-0.4x/src/vjournal.h
index c2c9672..a2b2a7e 100644
--- a/opensync-plugin-0.4x/src/vjournal.h
+++ b/opensync-plugin-0.4x/src/vjournal.h
@@ -33,6 +33,7 @@
// forward declarations
class BarryEnvironment;
+
//
// vJournal
//
diff --git a/opensync-plugin-0.4x/src/vtodo.cc b/opensync-plugin-0.4x/src/vtodo.cc
index 1cb17a1..8261431 100644
--- a/opensync-plugin-0.4x/src/vtodo.cc
+++ b/opensync-plugin-0.4x/src/vtodo.cc
@@ -101,6 +101,7 @@ const std::string& vTodo::ToTask(const Barry::Task &task)
AddAttr(NewAttr("SEQUENCE", "0"));
AddAttr(NewAttr("SUMMARY", task.Summary.c_str()));
AddAttr(NewAttr("DESCRIPTION", task.Notes.c_str()));
+ AddAttr(NewAttr("CATEGORIES",ToStringList(task.Categories).c_str()));
// Status
if (task.StatusFlag == Barry::Task::InProgress)
@@ -190,6 +191,7 @@ const Barry::Task& vTodo::ToBarry(const char *vtodo, uint32_t RecordId)
string due = GetAttr("DUE", "/vtodo");
trace.logf("DUE attr retrieved: %s", due.c_str());
+
//
// Now, run checks and convert into Barry object
//
@@ -209,6 +211,10 @@ const Barry::Task& vTodo::ToBarry(const char *vtodo, uint32_t RecordId)
Barry::Task &rec = m_BarryTask;
rec.SetIds(Barry::Task::GetDefaultRecType(), RecordId);
+ // Categories
+
+ rec.Categories=GetValueVector("CATEGORIES","/vtodo");
+
// SUMMARY & DESCRIPTION fields
rec.Summary = summary;
rec.Notes = notes;
diff --git a/src/r_memo.cc b/src/r_memo.cc
index 5fe55d1..52fb2fe 100644
--- a/src/r_memo.cc
+++ b/src/r_memo.cc
@@ -47,7 +47,7 @@ namespace Barry {
static FieldLink<Memo> MemoFieldLinks[] = {
{ MEMFC_TITLE, "Title", 0, 0, &Memo::Title, 0, 0, 0, 0, true },
{ MEMFC_BODY, "Body", 0, 0, &Memo::Body, 0, 0, 0, 0, true },
- { MEMFC_CATEGORY, "Category", 0, 0, &Memo::Category, 0, 0, 0, 0, true },
+// { MEMFC_CATEGORY, "Category", 0, 0, &Memo::Category, 0, 0, 0, 0, true },
{ MEMFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
};
@@ -102,6 +102,18 @@ const unsigned char* Memo::ParseField(const unsigned char *begin,
}
}
}
+ // handle special cases
+ switch( field->type )
+ {
+ case MEMFC_CATEGORY:
+ {
+ std::string catstring = ParseFieldString(field);
+ if( ic )
+ catstring = ic->FromBB(catstring);
+ CategoryStr2List(catstring,Categories);
+ }
+ return begin;
+ }
// if still not handled, add to the Unknowns list
UnknownField uf;
@@ -144,6 +156,14 @@ void Memo::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
// tack on the 'm' memo type field first
BuildField(data, offset, MEMFC_MEMO_TYPE, 'm');
+ // Categories
+
+ if(Categories.size()>0) {
+ string store;
+ CategoryList2Str(Categories, store);
+ BuildField(data, offset, MEMFC_CATEGORY, store);
+ }
+
// cycle through the type table
for( FieldLink<Memo> *b = MemoFieldLinks;
b->type != MEMFC_END;
@@ -184,7 +204,6 @@ void Memo::Dump(std::ostream &os) const
<< " (" << (unsigned int)RecType << ")\n";
os << " Title: " << Title << "\n";
os << " Body: " << Body << "\n";
- os << " Category: " << Category << "\n";
os << Unknowns;
os << "\n\n";
@@ -194,12 +213,62 @@ void Memo::Clear()
{
Title.clear();
Body.clear();
- Category.clear();
+ Categories.clear();
MemoType = 0;
Unknowns.clear();
}
+void Memo::CategoryStr2List(const std::string &str,Barry::CategoryList &list)
+{
+ // start fresh
+
+ list.clear();
+
+ if( !str.size() )
+ return;
+
+ // parse the comma-delimited string to a list, stripping away
+ // any white space around each category name
+ string::size_type start = 0, end = 0, delim = str.find(',', start);
+ while( start != string::npos ) {
+ if( delim == string::npos )
+ end = str.size() - 1;
+ else
+ end = delim - 1;
+
+ // strip surrounding whitespace
+ while( str[start] == ' ' )
+ start++;
+ while( end && str[end] == ' ' )
+ end--;
+
+ if( start <= end ) {
+ string token = str.substr(start, end-start+1);
+ list.push_back(token);
+ }
+
+ // next
+ start = delim;
+ if( start != string::npos )
+ start++;
+ delim = str.find(',', start);
+ }
+}
+
+void Memo::CategoryList2Str(const Barry::CategoryList &list, std::string &str)
+{
+ str.clear();
+
+ Barry::CategoryList::const_iterator i = list.begin();
+ for( ; i != list.end(); ++i ) {
+ if( str.size() )
+ str += ",";
+ str += *i;
+ }
+}
+
+
} // namespace Barry
diff --git a/src/r_memo.h b/src/r_memo.h
index 0652a38..3b6c2e4 100644
--- a/src/r_memo.h
+++ b/src/r_memo.h
@@ -34,6 +34,8 @@ namespace Barry {
// forward declarations
class IConverter;
+typedef std::vector<std::string> CategoryList;
+
class BXEXPORT Memo
{
public:
@@ -45,7 +47,7 @@ public:
uint8_t MemoType;
std::string Title;
std::string Body;
- std::string Category;
+ CategoryList Categories;
UnknownsType Unknowns;
@@ -53,6 +55,14 @@ public:
const unsigned char* ParseField(const unsigned char *begin,
const unsigned char *end, const IConverter *ic = 0);
+protected:
+ // these two are common with Contact and duplicated. TODO: Should really make them
+ // functions, or hive them off up the object hierarchy. But there is no hierarchy
+
+ static void CategoryStr2List(const std::string &str, Barry::CategoryList &list);
+ static void CategoryList2Str(const Barry::CategoryList &list, std::string &str);
+
+
public:
Memo();
~Memo();
diff --git a/src/r_task.cc b/src/r_task.cc
index cc821ae..dffadc1 100644
--- a/src/r_task.cc
+++ b/src/r_task.cc
@@ -105,7 +105,7 @@ static FieldLink<Task> TaskFieldLinks[] = {
{ TSKFC_START_TIME, "Start Time", 0, 0, 0, 0, &Task::StartTime, 0, 0, false },
{ TSKFC_DUE_TIME, "Due Time", 0, 0, 0, 0, &Task::DueTime, 0, 0, false },
{ TSKFC_ALARM_TIME, "Alarm Time", 0, 0, 0, 0, &Task::AlarmTime, 0, 0, false },
- { TSKFC_CATEGORIES, "Categories", 0, 0, &Task::Categories, 0, 0, 0, 0, false },
+// { TSKFC_CATEGORIES, "Categories", 0, 0, &Task::Categories, 0, 0, 0, 0, false },
{ TSKFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false },
};
@@ -202,8 +202,16 @@ const unsigned char* Task::ParseField(const unsigned char *begin,
AlarmType = AlarmProto2Rec(field->u.raw[0]);
}
return begin;
+
+ case TSKFC_CATEGORIES:
+ {
+ std::string catstring = ParseFieldString(field);
+ if( ic )
+ catstring = ic->FromBB(catstring);
+ CategoryStr2List(catstring,Categories);
+ }
+ return begin;
}
-
// base class handles recurring data
if( RecurBase::ParseField(field->type, field->u.raw, btohs(field->size), ic) )
return begin;
@@ -287,6 +295,14 @@ void Task::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
}
}
}
+
+ // Categories
+
+ if(Categories.size()>0) {
+ string store;
+ CategoryList2Str(Categories, store);
+ BuildField(data, offset, TSKFC_CATEGORIES, store);
+ }
// and finally save unknowns
UnknownsType::const_iterator
@@ -432,5 +448,55 @@ void Task::Dump(std::ostream &os) const
os << "\n\n";
}
+void Task::CategoryStr2List(const std::string &str,Barry::CategoryList &list)
+{
+ // start fresh
+
+ list.clear();
+
+ if( !str.size() )
+ return;
+
+ // parse the comma-delimited string to a list, stripping away
+ // any white space around each category name
+ string::size_type start = 0, end = 0, delim = str.find(',', start);
+ while( start != string::npos ) {
+ if( delim == string::npos )
+ end = str.size() - 1;
+ else
+ end = delim - 1;
+
+ // strip surrounding whitespace
+ while( str[start] == ' ' )
+ start++;
+ while( end && str[end] == ' ' )
+ end--;
+
+ if( start <= end ) {
+ string token = str.substr(start, end-start+1);
+ list.push_back(token);
+ }
+
+ // next
+ start = delim;
+ if( start != string::npos )
+ start++;
+ delim = str.find(',', start);
+ }
+}
+
+void Task::CategoryList2Str(const Barry::CategoryList &list, std::string &str)
+{
+ str.clear();
+
+ Barry::CategoryList::const_iterator i = list.begin();
+ for( ; i != list.end(); ++i ) {
+ if( str.size() )
+ str += ",";
+ str += *i;
+ }
+}
+
+
} // namespace Barry
diff --git a/src/r_task.h b/src/r_task.h
index c6b9a54..41decb1 100644
--- a/src/r_task.h
+++ b/src/r_task.h
@@ -35,6 +35,8 @@ namespace Barry {
// forward declarations
class IConverter;
+typedef std::vector<std::string> CategoryList;
+
class BXEXPORT Task : public RecurBase
{
public:
@@ -46,7 +48,7 @@ public:
uint8_t TaskType;
std::string Summary;
std::string Notes;
- std::string Categories;
+ CategoryList Categories;
std::string UID;
time_t StartTime;
@@ -95,6 +97,12 @@ protected:
static StatusFlagType StatusProto2Rec(uint8_t s);
static uint8_t StatusRec2Proto(StatusFlagType s);
+
+ // these two are common with Contact and duplicated. TODO: Should really make them
+ // functions, or hive them off up the object hierarchy. But there is no hierarchy
+
+ static void CategoryStr2List(const std::string &str, Barry::CategoryList &list);
+ static void CategoryList2Str(const Barry::CategoryList &list, std::string &str);
public:
Task();
diff --git a/src/record.cc b/src/record.cc
index ffce4c0..335cd71 100644
--- a/src/record.cc
+++ b/src/record.cc
@@ -620,9 +620,10 @@ void Date::ToTm(struct tm *timep) const
std::string Date::ToYYYYMMDD() const
{
std::ostringstream oss;
- oss << setw(4) << Year
- << setw(2) << Month + 1
- << setw(2) << Day;
+ // setfill and setw not sticky.
+ oss << setw(4) << setfill('0') << Year
+ << setw(2) << setfill('0') << Month + 1
+ << setw(2) << setfill('0') << Day;
return oss.str();
}
@@ -635,9 +636,10 @@ std::string Date::ToYYYYMMDD() const
std::string Date::ToBBString() const
{
std::ostringstream oss;
- oss << setw(2) << Day
- << Month + 1
- << Year;
+ // setw() ain't 'sticky'!
+ oss << setw(2) << setfill('0') << Day << '/'
+ << setw(2) << setfill('0') << Month + 1 << '/'
+ << setw(2) << setfill('0') << Year;
return oss.str();
}
------------------------------------------------------------------------------
The NEW KODAK i700 Series Scanners deliver under ANY circumstances! Your
production scanning environment may not be a perfect world - but thanks to
Kodak, there's a perfect scanner to get the job done! With the NEW KODAK i700
Series Scanner you'll get full speed at 300 dpi even with all image
processing features enabled. http://p.sf.net/sfu/kodak-com
_______________________________________________
Barry-devel mailing list
Barry-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/barry-devel