[PATCH] Expense conduit




hi,

i spent the last two days hacking an expense conduit together. it is
still a rather simple minded conduit - it does a 'copy_from_pilot' and
writes the records as CSVs in one file per category. however, it
already has most of the functionality that i need from it. one could
think of also syncing to gnumeric or gnucash or something like that
sometime in the future. 

playing around with this conduit, a couple of issues came up: 

	- what is the default Sync directory if the user does not 
	specify where? i chose ~/pilot/Expense - the 'pilot' coming
	from the backup conduit. 

	- do we just use g_error and g_warning if errors occur inside
	the conduit while syncing? shouldn't there be a more uniform 
	dialog box, so that it is absolutely clear that the error has 
	to do with gnome-pilot?

	- can anyone think of a nicer 'filepermissions' interface than
	numeric values? 

	- some other stuff, but i forgot... time for bed? 

anyway, below is the patch. the patch modifies the configure.in and
conduits/Makefile.am files and has the new conduits/expense
directory.

have fun and don't spend too much money trying it - if you do, you 
can do it in 25 predefined currencies:

static gchar *ExpenseCurrencyName[] = { "AU$", "S", "BF", "R$", "$CN",
"DKK", "Mk", "FRF", "DM", "HK$", "ISK", "IEP", "L.", "Y", "Flux",
"MXP", "NLG", "$NZ", "NOK", "Pts", "SEK", "CHF", "GBP", "$", "EU" };

and if that is not enough there are also 4 custom ones..... :->

cheers, 
patrick.

-------------------------------------------o-------------------------------
Patrick Decowski                           |
24-507                                     |    Home:      (617)625-9352
Massachusetts Institute of Technology      |    Cell:      (617)308-6737
77 Massachusetts Ave                       |    Office:    (617)253-1779
Cambridge, MA 02139-4307                   |    Fax:       (617)253-1755
-------------------------------------------o-------------------------------
http://web.mit.edu/decowski/www/home.html  |    e-mail: decowski@mit.edu
-------------------------------------------o-------------------------------

diff -uNr gnome-pilot/conduits/Makefile.am gnome-pilot-expense/conduits/Makefile.am
--- gnome-pilot/conduits/Makefile.am	Thu Oct 21 13:31:45 1999
+++ gnome-pilot-expense/conduits/Makefile.am	Mon Nov  8 00:39:03 1999
@@ -1,4 +1,4 @@
-always_built_SUBDIRS =  file backup email memo_file
+always_built_SUBDIRS =  file backup email memo_file expense
 
 SUBDIRS = $(always_built_SUBDIRS)
 
diff -uNr gnome-pilot/conduits/expense/.cvsignore gnome-pilot-expense/conduits/expense/.cvsignore
--- gnome-pilot/conduits/expense/.cvsignore	Wed Dec 31 19:00:00 1969
+++ gnome-pilot-expense/conduits/expense/.cvsignore	Sun Nov  7 18:03:00 1999
@@ -0,0 +1,7 @@
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+expense-conduit-control-applet
diff -uNr gnome-pilot/conduits/expense/AUTHORS gnome-pilot-expense/conduits/expense/AUTHORS
--- gnome-pilot/conduits/expense/AUTHORS	Wed Dec 31 19:00:00 1969
+++ gnome-pilot-expense/conduits/expense/AUTHORS	Sun Nov  7 23:53:05 1999
@@ -0,0 +1 @@
+Patrick Decowski <decowski@mit.edu>
diff -uNr gnome-pilot/conduits/expense/ChangeLog gnome-pilot-expense/conduits/expense/ChangeLog
--- gnome-pilot/conduits/expense/ChangeLog	Wed Dec 31 19:00:00 1969
+++ gnome-pilot-expense/conduits/expense/ChangeLog	Sun Nov  7 23:59:10 1999
@@ -0,0 +1,11 @@
+1999-11-07 Patrick Decowski <decowski@mit.edu>
+
+	* expense_conduit.c, expense_conduit.h, expense-control-capplet.c:
+	many bug fixes and improvements, added file & dir permissions by 
+	basically stealing vadim's code from the memo_file conduit. also added
+	capability of deciphering currencies from the pilot. bumped the
+	version to 0.2.
+	
+1999-11-06 Patrick Decowski <decowski@mit.edu>
+
+	* Start of development on the expense conduit. version 0.1
\ No newline at end of file
diff -uNr gnome-pilot/conduits/expense/Makefile.am gnome-pilot-expense/conduits/expense/Makefile.am
--- gnome-pilot/conduits/expense/Makefile.am	Wed Dec 31 19:00:00 1969
+++ gnome-pilot-expense/conduits/expense/Makefile.am	Fri Nov  5 12:54:15 1999
@@ -0,0 +1,44 @@
+INCLUDES = -I$(includedir) -I../../gpilotd $(GNOME_INCLUDEDIR) $(PISOCK_INCLUDEDIR)
+
+expense_conduitsdir=$(libdir)/gnome-pilot/conduits
+
+expense_conduits_LTLIBRARIES = \
+	libexpense_conduit.la
+
+libexpense_conduit_la_SOURCES = \
+	expense_conduit.c
+
+libexpense_conduit_la_LIBADD = \
+	$(PISOCK_LIBDIR) $(PISOCK_LIBS) \
+	$(GNOME_LIBDIR) \
+	$(GNOME_LIBS)
+
+
+bin_PROGRAMS = expense-conduit-control-applet
+
+expense_conduit_control_applet_SOURCES = expense-conduit-control-applet.c
+
+expense_conduit_control_applet_LDADD = \
+	$(CAPPLET_LIBS)  \
+	$(GNOME_LIBDIR) \
+	../../gpilotd/libgpilotd.la \
+	../../gpilotd/libgpilotdconduitmgmt.la \
+	../../gpilotd/libgconduit.la \
+	$(GNOME_CAPPLET_LIBS) \
+	$(PISOCK_LIBDIR) $(PISOCK_LIBS) \
+	$(GNOMEUI_LIBS) \
+	$(INTLLIBS) 
+
+
+ccenterdir = $(datadir)/control-center
+Rootdir = $(ccenterdir)
+PalmPilotdir = $(ccenterdir)/Peripherals/PalmPilot
+Conduitsdir = $(PalmPilotdir)/Conduits
+
+Conduits_DATA = expense-conduit-control-applet.desktop
+
+EXTRA_DIST = \
+	$(Conduits_DATA)
+
+install-data-local:
+	$(mkinstalldirs) $(Conduitsdir)
diff -uNr gnome-pilot/conduits/expense/expense-conduit-control-applet.c gnome-pilot-expense/conduits/expense/expense-conduit-control-applet.c
--- gnome-pilot/conduits/expense/expense-conduit-control-applet.c	Wed Dec 31 19:00:00 1969
+++ gnome-pilot-expense/conduits/expense/expense-conduit-control-applet.c	Sun Nov  7 23:05:26 1999
@@ -0,0 +1,551 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* Control applet ("capplet") for the gnome-pilot expense conduit,          */
+/* based on                                                                 */
+/* gpilotd control applet ('capplet') for use with the GNOME control center */
+
+#include <pwd.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <gnome.h>
+
+#include <config.h>
+#include <capplet-widget.h>
+
+#include <gpilotd/gpilotd-conduit-mgmt.h>
+#include <gpilotd/gpilotd-app.h>
+#include <gpilotd/gpilotd-app-dummy-callbacks.h>
+
+#include "expense_conduit.h"
+
+/* tell changes callbacks to ignore changes or not */
+static gboolean ignore_changes=FALSE;
+
+/* capplet widget */
+static GtkWidget *capplet=NULL;
+
+/* host/device/pilot configuration windows */
+GtkWidget *cfgOptionsWindow=NULL;
+GtkWidget *cfgStateWindow=NULL;
+GtkWidget *dialogWindow=NULL;
+
+gboolean activated,org_activation_state;
+GnomePilotConduitMgmt *conduit;
+ConduitCfg *origState = NULL;
+ConduitCfg *curState = NULL;
+
+static void doTrySettings(GtkWidget *widget, gpointer dummy);
+static void doRevertSettings(GtkWidget *widget, gpointer dummy);
+static void doSaveSettings(GtkWidget *widget, gpointer dummy);
+static void doCancelSettings(GtkWidget *widget, gpointer dummy);
+
+static void readOptionsCfg(GtkWidget *w, ConduitCfg *state);
+static void setOptionsCfg(GtkWidget *w, ConduitCfg *state);
+static void readStateCfg(GtkWidget *w, ConduitCfg *state);
+static void setStateCfg(GtkWidget *w, ConduitCfg *state);
+
+gint pilotId;
+CORBA_Environment ev;
+
+#define DATE_OPTIONS_COUNT 4
+typedef struct {
+        gchar *name;
+        char *format;
+} DateSetting_t;
+
+static DateSetting_t date_options[] = { { N_("Day/Month/Year"), "%d/%m/%Y"}, 
+                                       { N_("Month/Day/Year"), "%m/%d/%Y"}, 
+                                       { N_("Since 1970-01-01 (in sec)"), "%s"}, 
+                                       { N_("Local format"), "%x"}
+};
+
+#define WRITEOUT_OPTIONS_COUNT 2
+typedef struct {
+        gchar *name;
+        enum ExpenseOutputFormat format;
+} WriteoutSetting_t;
+
+static WriteoutSetting_t writeout_options[] = { { N_("Simple"), eSimpleFormat},
+                                                { N_("Complex"), eComplexFormat} };
+
+static void
+setSettings(ConduitCfg* conduitCfg)
+{
+        if(activated)
+                gpilotd_conduit_mgmt_enable(conduit,pilotId,GnomePilotConduitSyncTypeSynchronize);
+        else
+                gpilotd_conduit_mgmt_disable(conduit,pilotId);
+        save_configuration(conduitCfg);
+}
+
+static void
+doTrySettings(GtkWidget *widget, gpointer dummy)
+{
+        readStateCfg(cfgStateWindow, curState);
+        readOptionsCfg(cfgOptionsWindow, curState);
+        setSettings(curState);
+}
+
+static void
+doSaveSettings(GtkWidget *widget, gpointer dummy)
+{
+        doTrySettings(widget, curState);
+}
+
+
+static void
+doRevertSettings(GtkWidget *widget, gpointer dummy)
+{
+        activated = org_activation_state;
+        destroy_configuration(&curState);
+        curState = dupe_configuration(origState);
+        setOptionsCfg(cfgOptionsWindow, curState);
+        setStateCfg(cfgStateWindow, curState);
+        setSettings(curState);
+}
+
+static void
+doCancelSettings(GtkWidget *widget, gpointer dummy)
+{
+        setSettings(origState);
+}
+
+/* Don't allow any spaces */
+static void
+insert_ignore_space_cb (GtkEditable    *editable, const gchar    *text,
+                        gint len, gint *position, void *data)
+{
+        gint i;
+        gchar *curname;
+
+        curname = gtk_entry_get_text(GTK_ENTRY(editable));
+        if (*curname == '\0' && len > 0) {
+                if (isspace(text[0])) {
+                        gtk_signal_emit_stop_by_name(GTK_OBJECT(editable), "insert_text");
+                        return;
+                }
+        } else {
+                for (i=0; i<len; i++) {
+                        if (isspace(text[i])) {
+                                gtk_signal_emit_stop_by_name(GTK_OBJECT(editable), 
+                                                             "insert_text");
+                                return;
+                        }
+                }
+        }
+}
+
+static void
+insert_numeric_cb(GtkEditable    *editable, const gchar    *text,
+                  gint len, gint *position, void *data)
+{
+	gint i;
+
+	for (i=0; i<len; i++) {
+		if (!isdigit(text[i])) {
+			gtk_signal_emit_stop_by_name(GTK_OBJECT(editable), "insert_text");
+			return;
+		}
+	}
+}
+
+/* option menu callback for changing dates */
+static void
+datesetting_cb(GtkMenuItem *widget, gpointer data)
+{
+        curState->dateFormat = g_strdup((gchar*)data);
+        if(!ignore_changes)
+                capplet_widget_state_changed(CAPPLET_WIDGET(capplet), TRUE);
+}
+
+/* option menu callback for writing out */
+static void
+writeoutsetting_cb(GtkMenuItem *widget, gpointer data)
+{
+        curState->outputFormat = *(enum ExpenseOutputFormat*) data;
+        if(!ignore_changes)
+                capplet_widget_state_changed(CAPPLET_WIDGET(capplet), TRUE);
+}
+
+/* make the ok/try/cancel buttons active */
+static void
+statechange_cb(GtkEditable    *editable, const gchar    *text,
+                 gint            length, gint           *position,
+                 void *data)
+{
+        if (!ignore_changes)
+                capplet_widget_state_changed(CAPPLET_WIDGET(capplet), TRUE);
+}
+
+	
+void about_cb (GtkWidget *widget, gpointer data) 
+{
+        GtkWidget *about;
+        const gchar *authors[] = {_("Patrick Decowski <decowski@mit.edu>"),NULL};
+  
+        about = gnome_about_new(_("Gpilotd Expense conduit"), VERSION,
+                                _("(C) 1999 the Free Software Foundation"),
+                                authors,
+                                _("Configuration utility for the Expense conduit.\n"
+                                  "The Expense conduit is responsible for getting "
+                                  "expenses records from the pilot"),
+                                _("gnome-unknown.xpm"));
+        gtk_widget_show (about);
+        
+        return;
+}
+
+static void toggled_cb(GtkWidget *widget, gpointer data) 
+{
+        if(!ignore_changes) {
+                gtk_widget_set_sensitive(cfgOptionsWindow,GTK_TOGGLE_BUTTON(widget)->active);
+                capplet_widget_state_changed(CAPPLET_WIDGET(capplet), TRUE);
+        }
+}
+
+static GtkWidget
+*createStateCfgWindow(void)
+{
+        GtkWidget *vbox, *table;
+        GtkWidget *entry, *label;
+        GtkWidget *button;
+
+        vbox = gtk_vbox_new(FALSE, GNOME_PAD);
+
+        table = gtk_table_new(2, 2, FALSE);
+        gtk_table_set_row_spacings(GTK_TABLE(table), 4);
+        gtk_table_set_col_spacings(GTK_TABLE(table), 10);
+        gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, GNOME_PAD);
+
+        label = gtk_label_new(_("Enabled"));
+        gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1,2);
+        
+        button = gtk_check_button_new();
+        gtk_object_set_data(GTK_OBJECT(vbox), "conduit_on_off", button);
+        gtk_signal_connect(GTK_OBJECT(button), "toggled",
+                           GTK_SIGNAL_FUNC(toggled_cb),
+                           NULL);
+        gtk_table_attach_defaults(GTK_TABLE(table), button, 1, 2, 1,2);
+
+        return vbox;
+}
+
+
+static void
+setStateCfg(GtkWidget *widget,ConduitCfg *cfg)
+{
+        GtkWidget *button;
+        gchar num[40];
+
+        button = gtk_object_get_data(GTK_OBJECT(widget), "conduit_on_off");
+
+        g_assert(button!=NULL);
+
+        ignore_changes = TRUE;
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),activated);
+        gtk_widget_set_sensitive(cfgOptionsWindow,GTK_TOGGLE_BUTTON(button)->active);
+        ignore_changes = FALSE;
+}
+
+
+static void
+readStateCfg(GtkWidget *widget,ConduitCfg *cfg)
+{
+        GtkWidget *button;
+
+        button  = gtk_object_get_data(GTK_OBJECT(widget), "conduit_on_off");
+        
+        g_assert(button!=NULL);
+
+        activated = GTK_TOGGLE_BUTTON(button)->active;
+}
+
+typedef struct _FieldInfo FieldInfo;
+struct _FieldInfo
+{
+	gchar    *name;
+	gchar    *label_data;
+	gchar    *obj_data;
+	gpointer  insert_func;
+};
+
+
+FieldInfo fields[] = { { N_("Expense Directory"), NULL, "ExpenseDir", insert_ignore_space_cb},
+                       { N_("Directory Mode"), NULL, "DirMode", insert_numeric_cb},
+                       { N_("File Mode"), NULL, "FileMode", insert_numeric_cb}, 
+                       { NULL, NULL, NULL, NULL}
+};
+
+
+static GtkWidget
+*createCfgWindow(void)
+{
+	GtkWidget *vbox, *table;
+	GtkWidget *entry, *label;
+        GtkWidget *menuItem, *optionMenu;
+        GtkMenu   *menu;
+
+        int i, count, widget_offset;
+
+	vbox = gtk_vbox_new(FALSE, GNOME_PAD);
+
+	table = gtk_table_new(2, 5, FALSE);
+	gtk_table_set_row_spacings(GTK_TABLE(table), 4);
+	gtk_table_set_col_spacings(GTK_TABLE(table), 10);
+	gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, GNOME_PAD);
+
+        /* set the date format */
+        label = gtk_label_new(_("Date Format"));
+        gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
+
+        menu = GTK_MENU(gtk_menu_new());
+        for (i = 0; i < DATE_OPTIONS_COUNT; i++) {
+                menuItem = gtk_menu_item_new_with_label(_(date_options[i].name));
+                gtk_widget_show(menuItem);
+                gtk_signal_connect(GTK_OBJECT(menuItem),"activate",
+                                   GTK_SIGNAL_FUNC(datesetting_cb), 
+                                   date_options[i].format); 
+                gtk_menu_append(menu, menuItem);
+        }
+
+        optionMenu = gtk_option_menu_new(); 
+        gtk_option_menu_set_menu(GTK_OPTION_MENU(optionMenu),GTK_WIDGET(menu));
+        gtk_signal_connect(GTK_OBJECT(menu), "selection-done",
+                           GTK_SIGNAL_FUNC(statechange_cb),
+                           NULL);
+
+        gtk_table_attach_defaults(GTK_TABLE(table), optionMenu, 1, 2, 1, 2);
+        gtk_object_set_data(GTK_OBJECT(vbox), "DateFormat", optionMenu);
+
+        /* set the writeout format */
+        label = gtk_label_new(_("Output Format"));
+        gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
+
+        menu = GTK_MENU(gtk_menu_new());
+        for (i = 0; i < WRITEOUT_OPTIONS_COUNT; i++) {
+                menuItem = gtk_menu_item_new_with_label(_(writeout_options[i].name));
+                gtk_widget_show(menuItem);
+                gtk_signal_connect(GTK_OBJECT(menuItem),"activate",
+                                   GTK_SIGNAL_FUNC(writeoutsetting_cb), 
+                                   &writeout_options[i].format); 
+                gtk_menu_append(menu, menuItem);
+        }
+
+        optionMenu = gtk_option_menu_new(); 
+        gtk_option_menu_set_menu(GTK_OPTION_MENU(optionMenu),GTK_WIDGET(menu));
+        gtk_signal_connect(GTK_OBJECT(menu), "selection-done",
+                           GTK_SIGNAL_FUNC(statechange_cb),
+                           NULL);
+
+        gtk_table_attach_defaults(GTK_TABLE(table), optionMenu, 1, 2, 2, 3);
+        gtk_object_set_data(GTK_OBJECT(vbox), "OutputFormat", optionMenu);
+
+        /* ugh, so we have an asymmetry here: above is done in paste&copy fashion 
+           and below, we do it nicely with structs and stuff */  
+
+        /* do the dir & modes */
+
+	/* how many fields do we have */
+	while(fields[count].name!=0) count++;
+
+        widget_offset = 3;
+	for(i = 0; i < count; i++) {
+		label = gtk_label_new(_(fields[i].name));
+		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 
+                                 widget_offset+i, widget_offset+i+1, 0,0,0,0);
+		if(fields[i].label_data!=NULL) {
+			gtk_object_set_data(GTK_OBJECT(vbox), fields[i].label_data, label);
+		}
+		entry = gtk_entry_new_with_max_length(128);
+		gtk_object_set_data(GTK_OBJECT(vbox), fields[i].obj_data, entry);
+		gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 
+                                 widget_offset+i, widget_offset+i+1, 0,0,0,0);
+		gtk_signal_connect(GTK_OBJECT(entry), "insert_text",
+				   GTK_SIGNAL_FUNC(fields[i].insert_func),
+				   NULL);
+		gtk_signal_connect_after(GTK_OBJECT(entry), "insert_text",
+					 GTK_SIGNAL_FUNC(statechange_cb),
+					 NULL);
+		gtk_signal_connect_after(GTK_OBJECT(entry), "delete_text",
+					 GTK_SIGNAL_FUNC(statechange_cb),
+					 NULL);
+	}
+	
+
+	return vbox;
+}
+
+static void
+setOptionsCfg(GtkWidget *pilotcfg, ConduitCfg *state)
+{
+	GtkWidget *DateFormat, *OutputFormat, *ExpenseDir, *DirMode, *FileMode;
+        gchar buf[8];
+
+        int i;
+
+	DateFormat = gtk_object_get_data(GTK_OBJECT(pilotcfg), "DateFormat");
+	OutputFormat = gtk_object_get_data(GTK_OBJECT(pilotcfg), "OutputFormat");
+	ExpenseDir = gtk_object_get_data(GTK_OBJECT(pilotcfg), "ExpenseDir");
+	DirMode = gtk_object_get_data(GTK_OBJECT(pilotcfg), "DirMode");
+	FileMode = gtk_object_get_data(GTK_OBJECT(pilotcfg), "FileMode");
+
+	g_assert(DateFormat != NULL);
+	g_assert(OutputFormat != NULL);
+	g_assert(ExpenseDir != NULL);
+	g_assert(DirMode != NULL);
+	g_assert(FileMode != NULL);
+                
+	ignore_changes = TRUE;
+
+	gtk_entry_set_text(GTK_ENTRY(ExpenseDir), state->dir);
+	g_snprintf(buf, 7, "0%o", state->dirMode);
+	gtk_entry_set_text(GTK_ENTRY(DirMode),buf);
+	g_snprintf(buf, 7, "0%o", state->fileMode);
+	gtk_entry_set_text(GTK_ENTRY(FileMode),buf);
+
+        /* find the entry in the option menu. if not found, default to the last */
+        for(i = 0; i < DATE_OPTIONS_COUNT && g_strncasecmp(state->dateFormat, date_options[i].format, 20) != 0; i++);
+        gtk_option_menu_set_history(GTK_OPTION_MENU(DateFormat), i);
+
+        for(i = 0; i < WRITEOUT_OPTIONS_COUNT && state->outputFormat != writeout_options[i].format; i++);
+        gtk_option_menu_set_history(GTK_OPTION_MENU(OutputFormat), i);
+
+	ignore_changes = FALSE;
+}
+
+static void
+readOptionsCfg(GtkWidget *pilotcfg, ConduitCfg *state)
+{
+	GtkWidget *ExpenseDir, *DirMode, *FileMode;;
+
+	ExpenseDir = gtk_object_get_data(GTK_OBJECT(pilotcfg), "ExpenseDir");
+	DirMode = gtk_object_get_data(GTK_OBJECT(pilotcfg), "DirMode");
+	FileMode = gtk_object_get_data(GTK_OBJECT(pilotcfg), "FileMode");
+
+        state->dir = g_strdup(gtk_entry_get_text(GTK_ENTRY(ExpenseDir)));
+        state->dirMode = strtol(gtk_entry_get_text(GTK_ENTRY(DirMode)), NULL, 0);
+        state->fileMode = strtol(gtk_entry_get_text(GTK_ENTRY(FileMode)), NULL, 0);
+
+        /* state of dateFormat, outputFormat changed in datesetting_cb */
+}
+
+static void
+pilot_capplet_setup(void)
+{
+        GtkWidget *frame, *table;
+
+        capplet = capplet_widget_new();
+
+        table = gtk_table_new(1, 2, FALSE);
+        gtk_container_border_width(GTK_CONTAINER(table), GNOME_PAD);
+        gtk_container_add(GTK_CONTAINER(capplet), table); 
+
+        frame = gtk_frame_new(_("Conduit state"));
+        gtk_container_border_width(GTK_CONTAINER(frame), GNOME_PAD_SMALL);
+        gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 1, 0, 1);
+        cfgStateWindow = createStateCfgWindow();
+        gtk_container_add(GTK_CONTAINER(frame), cfgStateWindow);
+
+        frame = gtk_frame_new(_("Expense options"));
+        gtk_container_border_width(GTK_CONTAINER(frame), GNOME_PAD_SMALL);
+        gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 1, 1, 2);
+        cfgOptionsWindow = createCfgWindow();
+        gtk_container_add(GTK_CONTAINER(frame), cfgOptionsWindow);
+        
+        gtk_signal_connect(GTK_OBJECT(capplet), "try",
+                           GTK_SIGNAL_FUNC(doTrySettings), NULL);
+        gtk_signal_connect(GTK_OBJECT(capplet), "revert",
+                           GTK_SIGNAL_FUNC(doRevertSettings), NULL);
+        gtk_signal_connect(GTK_OBJECT(capplet), "ok",
+                           GTK_SIGNAL_FUNC(doSaveSettings), NULL);
+        gtk_signal_connect(GTK_OBJECT(capplet), "cancel",
+                           GTK_SIGNAL_FUNC(doCancelSettings), NULL);
+        gtk_signal_connect(GTK_OBJECT(capplet), "help",
+                           GTK_SIGNAL_FUNC(about_cb), NULL);
+
+
+        setStateCfg(cfgStateWindow, curState);
+        setOptionsCfg(cfgOptionsWindow, curState);
+
+        gtk_widget_show_all(capplet);
+}
+
+void run_error_dialog(gchar *mesg,...) 
+{
+        char tmp[80];
+        va_list ap;
+
+        va_start(ap,mesg);
+        vsnprintf(tmp,79,mesg,ap);
+        dialogWindow = gnome_message_box_new(mesg,GNOME_MESSAGE_BOX_ERROR,GNOME_STOCK_BUTTON_OK,NULL);
+        gnome_dialog_run_and_close(GNOME_DIALOG(dialogWindow));
+        va_end(ap);
+}
+
+
+gint get_pilot_id_from_gpilotd() 
+{
+	gint *pilots;
+	int i;
+  
+	i=0;
+	gpilotd_get_pilot_ids(&pilots);
+	if(pilots) {
+		while(pilots[i]!=-1) { g_message("pilot %d = \"%d\"",i,pilots[i]); i++; }
+		if(i==0) {
+			run_error_dialog(_("No pilot configured, please choose the\n'Pilot Link Properties' capplet first."));
+			return -1;
+		} else {
+			if(i==1) 
+				return pilots[0];
+			else {
+				g_message("too many pilots...");
+				return pilots[0];
+			}
+		}
+	} else {
+		run_error_dialog(_("No pilot configured, please choose the\n'Pilot Link Properties' capplet first."));
+		return -1;
+	}  
+}
+
+int
+main( int argc, char *argv[] )
+{
+        /* we're a capplet */
+        gnome_capplet_init ("Expense conduit control applet", NULL, argc, argv, 
+                            NULL,
+                            0, NULL);
+
+        /* get pilot name from gpilotd */
+        /* 1. initialize the gpilotd connection */
+        if (gpilotd_init(&argc,argv)!=0) {
+                run_error_dialog(_("Cannot initialze the GnomePilot Daemon"));
+                g_error(_("Cannot initialze the GnomePilot Daemon"));
+                return -1;
+        }
+    
+        /* 2 connect to gpilotd */
+        if (gpilotd_connect()!=0) {
+                run_error_dialog(_("Cannot connect to the GnomePilot Daemon"));
+                g_error(_("Cannot connect to the GnomePilot Daemon"));
+                return -1;
+        }
+    
+        pilotId = get_pilot_id_from_gpilotd();
+        if(pilotId==-1) return -1;
+
+        /* put all code to set things up in here */
+
+        load_configuration(&origState,pilotId);
+        curState = dupe_configuration(origState);
+        conduit = gpilotd_conduit_mgmt_new("expense_conduit");
+
+        org_activation_state = activated = gpilotd_conduit_mgmt_is_enabled(conduit,pilotId);
+    
+        pilot_capplet_setup();
+
+
+        /* done setting up, now run main loop */
+        capplet_gtk_main();
+        return 0;
+}    
diff -uNr gnome-pilot/conduits/expense/expense-conduit-control-applet.desktop gnome-pilot-expense/conduits/expense/expense-conduit-control-applet.desktop
--- gnome-pilot/conduits/expense/expense-conduit-control-applet.desktop	Wed Dec 31 19:00:00 1969
+++ gnome-pilot-expense/conduits/expense/expense-conduit-control-applet.desktop	Fri Nov  5 12:54:22 1999
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Name=Expense conduit 
+Comment=Configure the Expense conduit
+Exec=expense-conduit-control-applet --cap-id=1
+Terminal=0
+Type=Application
diff -uNr gnome-pilot/conduits/expense/expense_conduit.c gnome-pilot-expense/conduits/expense/expense_conduit.c
--- gnome-pilot/conduits/expense/expense_conduit.c	Wed Dec 31 19:00:00 1969
+++ gnome-pilot-expense/conduits/expense/expense_conduit.c	Mon Nov  8 00:04:10 1999
@@ -0,0 +1,278 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/* expense conduit, based on read-expense */
+
+#include <glib.h>
+#include <gnome.h>
+
+#include <pi-source.h>
+#include <pi-socket.h>
+#include <pi-dlp.h>
+#include <pi-version.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <utime.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <signal.h>
+#include <time.h>
+
+#include <gnome-pilot-conduit.h>
+#include <gnome-pilot-conduit-standard.h>
+#include <expense_conduit.h>
+
+#define CONDUIT_VERSION "0.2"
+
+/* Following depend on the ordering in pi-expense.h ! */
+static gchar *ExpenseTypeName[] = { "Airfare", "Breakfast", "Bus", "BusinessMeals", "CarRental", 
+                                    "Dinner", "Entertainment", "Fax", "Gas", "Gifts", "Hotel", 
+                                    "Incidentals","Laundry", "Limo", "Lodging", "Lunch", "Mileage", 
+                                    "Other", "Parking", "Postage", "Snack", "Subway", "Supplies", 
+                                    "Taxi", "Telephone", "Tips", "Tolls", "Train" };
+
+static gchar *ExpensePaymentName[] = { "AmEx", "Cash", "Check", "CreditCard", "MasterCard", 
+                                       "PrePaid", "VISA", "Unfiled" };
+
+/* these values are hardcoded in the palm expense appl. does it differ for non-us palms??? */
+static gchar *ExpenseCurrencyName[] = { "AU$", "S", "BF", "R$", "$CN", "DKK", "Mk", "FRF", "DM", 
+                                        "HK$", "ISK", "IEP", "L.", "Y", "Flux", "MXP", "NLG", 
+                                        "$NZ", "NOK", "Pts", "SEK", "CHF", "GBP", "$", "EU" };
+
+static void load_config( ConduitCfg **c, guint32 pilotId ) 
+{
+        load_configuration( c, pilotId );
+}
+
+/* from pilot-xfer */
+static void protect_name(char *d, char *s) 
+{
+	while(*s) {
+		switch(*s) {
+		case '/': *(d++) = '='; *(d++) = '2'; *(d++) = 'F'; break;
+		case '=': *(d++) = '='; *(d++) = '3'; *(d++) = 'D'; break;
+		case '\x0A': *(d++) = '='; *(d++) = '0'; *(d++) = 'A'; break;
+		case '\x0D': *(d++) = '='; *(d++) = '0'; *(d++) = 'D'; break;
+			/*case ' ': *(d++) = '='; *(d++) = '2'; *(d++) = '0'; break;*/
+		default: 
+			if(*s < ' ') {
+				gchar tmp[6];
+				g_snprintf(tmp,5,"=%2X",(unsigned char)*s);
+				*(d++) = tmp[0]; *(d++) = tmp[1]; *(d++) = tmp[2];
+			} else
+				*(d++) = *s;
+			break;
+		}
+		++s;
+	}
+	*d = '\0';
+}
+
+/** 
+    generates a pathname for a category 
+ */
+gchar *category_path(int category, GnomePilotConduit *c) 
+{
+	static gchar filename[FILENAME_MAX];
+	gchar buf[64];
+	
+	if(category==16) 
+		strcpy(buf,"Archived");
+	else
+		protect_name(buf,GET_CONDUIT_DATA(c)->ai.category.name[category]);
+  
+	g_snprintf(filename,FILENAME_MAX-1,"%s/%s",
+		   GET_CONFIG(c)->dir,
+		   buf);
+	     
+	return filename;
+}
+
+int writeout_record(int fd, struct Expense *record, GnomePilotConduit *c)
+{
+        char entry[0xffff];
+    
+        const int kDateStrSize = 30;
+        char DateStr[kDateStrSize];
+        char *Currency;
+
+        strftime(DateStr, kDateStrSize, GET_CONFIG(c)->dateFormat, &record->date);
+
+        if(record->currency < 24)
+                Currency = ExpenseCurrencyName[record->currency];
+        /* handle the euro*/ 
+        else if(record->currency == 133)
+                Currency = ExpenseCurrencyName[24];
+        /* handle the custom currencies */
+        else if(record->currency >= 128 && record->currency < 133) 
+                Currency = GET_CONDUIT_DATA(c)->ai.currencies[record->currency-128].symbol;
+        else
+                g_error("Unknown Currency Symbol");
+
+        switch(GET_CONFIG(c)->outputFormat) {
+        case eSimpleFormat:
+                sprintf(entry, "%s, %s, %s, %s, %s\n", DateStr, ExpenseTypeName[record->type], ExpensePaymentName[record->payment], Currency, record->amount ? record->amount: "<None>");
+                break;
+        case eComplexFormat:
+        default:
+                sprintf(entry, "Date: %s, Type: %s, Payment: %s, Currency: %s, Amount: '%s', Vendor: '%s', City: '%s', Attendees: '%s', Note: '%s'\n", DateStr, ExpenseTypeName[record->type], ExpensePaymentName[record->payment], Currency, record->amount ?
 record->amount: "<None>", record->vendor ? record->vendor: "<None>", record->city ? record->city: "<None>", record->attendees ? record->attendees: "<None>", record->note ? record->note: "<None>");
+        }
+
+#ifdef EC_DEBUG
+        fprintf(stderr, "%s\n", entry);
+#endif
+        if(write(fd, entry, strlen(entry)) == -1) {
+                perror("writeout_record");
+                return -1;
+        }
+}
+
+/* Parts of this routine is shamelessly stolen from read-expenses.c from the pilot-link 
+package, Copyright (c) 1997, Kenneth Albanowski
+*/
+static gint copy_from_pilot( GnomePilotConduit *c, GnomePilotDBInfo *dbi )
+{
+        int dbHandle;
+        guchar buffer[0xffff];
+
+        struct ExpenseAppInfo *tai;
+        struct ExpensePref *tp;
+
+        int i;
+        int ret;
+        int filehandle[17];
+
+        tai = &(GET_CONDUIT_DATA(c)->ai);
+        tp = &(GET_CONDUIT_DATA(c)->pref);
+
+        g_message ("Expense Conduit v.%s", CONDUIT_VERSION);
+
+        if(dlp_OpenDB(dbi->pilot_socket, 0, 0x80|0x40, "ExpenseDB", &dbHandle) < 0) {
+                g_error("Unable to open ExpenseDB");
+                return -1;
+        }
+
+    
+        unpack_ExpensePref(tp, buffer, 0xffff);
+
+#ifdef EC_DEBUG
+        fprintf(stderr, "Orig prefs, %d bytes:\n", ret);
+        fprintf(stderr, "Expense prefs, current category %d, default category %d\n",
+                tp->currentCategory, tp->defaultCategory);
+        fprintf(stderr, "  Note font %d, Show all categories %d, Show currency %d, Save backup %d\n",
+                tp->noteFont, tp->showAllCategories, tp->showCurrency, tp->saveBackup);
+        fprintf(stderr, "  Allow quickfill %d, Distance unit %d, Currencies:\n",
+                tp->allowQuickFill, tp->unitOfDistance);
+        for(i = 0; i < 7; i++) {
+                fprintf(stderr, " %d", tp->currencies[i]);
+        }
+        fprintf(stderr, "\n");
+#endif /* EC_DEBUG */
+
+        ret = dlp_ReadAppBlock(dbi->pilot_socket, dbHandle, 0, buffer, 0xffff);
+    
+        unpack_ExpenseAppInfo(tai, buffer, 0xffff);
+
+#ifdef EC_DEBUG
+        fprint (stderr, "Orig length %d, new length %d, orig data:\n", ret, i);
+        fprintf(stderr, "New data:\n");
+    
+        fprintf(stderr, "Expense app info, sort order %d\n", tai->sortOrder);
+        for(i = 0; i < 4; i++)
+                fprintf(stderr, " Currency %d, name '%s', symbol '%s', rate '%s'\n", i, 
+                        tai->currencies[i].name, tai->currencies[i].symbol, tai->currencies[i].rate);
+#endif /* EC_DEBUG */
+
+        /* make the directory */
+        if(mkdir(GET_CONFIG(c)->dir, GET_CONFIG(c)->dirMode) < 0) {
+                if(errno != EEXIST) {
+                        g_warning ("Unable to create directory:\n\t%s\n", GET_CONFIG(c)->dir);
+                        return -1;
+                }
+        }
+        
+        /* open one file for every category in Expense */
+        for(i = 0; i < 17; i++) {
+                if(*tai->category.name[i] != '\0') {
+                        LOG("Opening for cat %d: %s\n", i, category_path(i, c));
+                        if((filehandle[i] = creat(category_path(i, c), GET_CONFIG(c)->fileMode))== -1) {
+                                LOG("copy_from_pilot: error in opening %s", category_path(i, c));
+                                perror("");
+                                return -1;
+                        }
+                } else {
+                        filehandle[i] = -1;
+                }
+        }
+
+        /* loop through all the records */
+        for (i = 0; ; i++) {
+                struct Expense t;
+                int attr, category, len;
+
+                len = dlp_ReadRecordByIndex(dbi->pilot_socket, dbHandle, i, buffer, 0, 0, &attr, &category);
+                
+                /* at the end of all the records? */
+                if(len < 0)
+                        break;
+                /* Skip deleted records */
+                if((attr & dlpRecAttrDeleted) || (attr & dlpRecAttrArchived))
+                        continue;
+
+                unpack_Expense(&t, buffer, len);
+                writeout_record(filehandle[category], &t, c);
+                free_Expense(&t);
+        }
+
+        /* close all the opened filehandles */
+        for(i = 0; i < 17; i++)
+                if(filehandle[i] != -1)
+                        close(filehandle[i]);
+        
+        dlp_ResetLastSyncPC( dbi->pilot_socket );
+        /* Close the database */
+        dlp_CloseDB(dbi->pilot_socket, dbHandle);
+        
+        return( 0 );
+}
+
+static gint synchronize( GnomePilotConduit *c, GnomePilotDBInfo *dbi ) {
+        copy_from_pilot( c, dbi );
+}
+
+GnomePilotConduit *conduit_get_gpilot_conduit( guint32 pilotId ) 
+{
+        GtkObject *retval;
+        ConduitCfg *cc;
+        ConduitData *cd = g_new0(ConduitData, 1);
+
+        retval = gnome_pilot_conduit_standard_new("ExpenseDB", Expense_Creator);
+        gnome_pilot_conduit_construct(GNOME_PILOT_CONDUIT(retval),"Expense");
+        g_assert(retval != NULL);
+        gtk_signal_connect(retval, "copy_from_pilot", (GtkSignalFunc)copy_from_pilot ,NULL);
+        /*
+          gtk_signal_connect(retval, "copy_to_pilot", (GtkSignalFunc) ,NULL);
+          gtk_signal_connect(retval, "merge_to_pilot", (GtkSignalFunc) ,NULL);
+          gtk_signal_connect(retval, "merge_from_pilot", (GtkSignalFunc) ,NULL);
+        */
+        gtk_signal_connect(retval, "synchronize", (GtkSignalFunc)synchronize ,NULL);
+        
+        load_config(&cc, pilotId );
+        gtk_object_set_data(retval,"conduit_config",(gpointer)cc);
+        gtk_object_set_data(retval,"conduit_data",(gpointer)cd);
+        
+        return GNOME_PILOT_CONDUIT(retval); 
+}
+
+void conduit_destroy_gpilot_conduit( GnomePilotConduit *c ) 
+{
+        ConduitCfg *cc;
+        ConduitData  *cd;
+  
+        cc = GET_CONFIG(c);
+        cd = GET_CONDUIT_DATA(c);
+
+        destroy_configuration( &cc );
+        gtk_object_destroy(GTK_OBJECT(c));
+}
+
diff -uNr gnome-pilot/conduits/expense/expense_conduit.h gnome-pilot-expense/conduits/expense/expense_conduit.h
--- gnome-pilot/conduits/expense/expense_conduit.h	Wed Dec 31 19:00:00 1969
+++ gnome-pilot-expense/conduits/expense/expense_conduit.h	Sun Nov  7 23:47:37 1999
@@ -0,0 +1,136 @@
+#ifndef __EXPENSE_CONDUIT_H__
+#define __EXPENSE_CONDUIT_H__
+
+#include <unistd.h>
+#include <pi-expense.h>
+
+
+enum ExpenseOutputFormat { 
+  eSimpleFormat, eComplexFormat
+};
+
+typedef struct ConduitCfg {
+  gchar *dir;
+  gchar *dateFormat;
+  mode_t dirMode;
+  mode_t fileMode;
+  enum ExpenseOutputFormat outputFormat;
+
+  guint32 pilotId;
+  pid_t child;
+} ConduitCfg;
+
+typedef struct ConduitData {
+  struct ExpenseAppInfo ai;
+  struct ExpensePref pref;
+  GnomePilotDBInfo *dbi;
+} ConduitData;
+
+#define GET_CONFIG(c) ((ConduitCfg*)(gtk_object_get_data(GTK_OBJECT(c),"conduit_config")))
+#define GET_CONDUIT_DATA(c) ((ConduitData*)gtk_object_get_data(GTK_OBJECT(c),"conduit_data"))
+
+#define EC_DEBUG
+#ifdef EC_DEBUG
+#define LOG(format,args...) g_log (G_LOG_DOMAIN, \
+                                   G_LOG_LEVEL_MESSAGE, \
+                                   "expense: "##format, ##args)
+#else
+#define LOG(format,args...)
+#endif
+
+static void 
+load_configuration(ConduitCfg **c,guint32 pilotId) 
+{
+	gchar *prefix;
+	gchar *tempbuf;
+
+	g_assert(c!=NULL);
+	*c = g_new0(ConduitCfg,1);
+	(*c)->child = -1;
+
+	prefix = g_strdup_printf("/gnome-pilot.d/expense-conduit/Pilot_%u/",pilotId);
+  
+	gnome_config_push_prefix(prefix);
+	(*c)->dir = gnome_config_get_string( "dir=");
+	(*c)->dateFormat = gnome_config_get_string( "date_format=%x");
+	(*c)->outputFormat = gnome_config_get_int("output_format=0");
+	tempbuf = gnome_config_get_string("dir mode=0700");
+	(*c)->dirMode =(mode_t)strtol(tempbuf,NULL,0);
+	g_free(tempbuf);
+	tempbuf = gnome_config_get_string("file mode=0600");
+	(*c)->fileMode =(mode_t)strtol(tempbuf,NULL,0);
+	g_free(tempbuf);
+
+	gnome_config_pop_prefix();
+
+	(*c)->pilotId = pilotId;
+
+	/* make a default directory if nothing was defined */
+	if((*c)->dir[0] == '\0') {
+	  char file_name[FILENAME_MAX];
+	  g_snprintf (file_name, FILENAME_MAX, "%s/pilot/Expense", g_get_home_dir());
+	  g_free((*c)->dir);
+	  (*c)->dir = g_strdup(file_name);
+	}
+	g_free(prefix);
+}
+
+
+static void 
+save_configuration(ConduitCfg *c) 
+{
+	gchar *prefix;
+
+	g_assert(c!=NULL);
+
+	prefix = g_strdup_printf("/gnome-pilot.d/expense-conduit/Pilot_%u/",c->pilotId);
+
+#ifdef EC_DEBUG
+	fprintf(stderr,"expense_conduit: savecfg: prefix = %s\n",prefix);
+#endif
+
+	gnome_config_push_prefix(prefix);
+	gnome_config_set_string("dir", c->dir);
+	gnome_config_set_string("date_format", c->dateFormat);
+	gnome_config_set_int("output_format", c->outputFormat);
+	g_snprintf(prefix,255,"0%o", c->dirMode);
+	gnome_config_set_string("dir mode", prefix);
+	g_snprintf(prefix,255,"0%o", c->fileMode);
+	gnome_config_set_string("file mode", prefix);
+
+	gnome_config_pop_prefix();
+
+	gnome_config_sync();
+	gnome_config_drop_all();
+	g_free(prefix);
+}
+
+static ConduitCfg*
+dupe_configuration(ConduitCfg *c) {
+	ConduitCfg *retval;
+	g_assert(c!=NULL);
+	retval = g_new0(ConduitCfg,1);
+	retval->dir = g_strdup(c->dir);
+	retval->dateFormat = g_strdup(c->dateFormat);
+	retval->outputFormat = c->outputFormat;
+	retval->dirMode = c->dirMode;
+	retval->fileMode = c->fileMode;
+
+	retval->pilotId = c->pilotId;
+
+	return retval;
+}
+
+/** this method frees all data from the conduit config */
+static void 
+destroy_configuration(ConduitCfg **c) 
+{
+	g_assert(c!=NULL);
+	g_assert(*c!=NULL);
+	g_free( (*c)->dir);
+	g_free( (*c)->dateFormat);
+	g_free(*c);
+	*c = NULL;
+}
+
+#endif /* __EXPENSE_CONDUIT_H__ */
diff -uNr gnome-pilot/configure.in gnome-pilot-expense/configure.in
--- gnome-pilot/configure.in	Fri Nov  5 07:12:36 1999
+++ gnome-pilot-expense/configure.in	Mon Nov  8 00:38:32 1999
@@ -99,6 +99,7 @@
 conduits/address/Makefile
 conduits/email/Makefile
 conduits/memo_file/Makefile
+conduits/expense/Makefile
 dnl admin/Makefile
 capplet/Makefile
 utils/Makefile



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]