Hi folks I had a quick look over the mailing list archives recently. After seeing some questions about the mail conduit I thought I'd chuck out the patch I have been working on for people to play with/break. I haven't quite finished it yet but what programmer ever does? It is a bit of a monster, I can split if people really want me to. Basically it: * fixes a trivial bug with the mailbox copy * removes the pasting operator in the LOG macro to reduce warnings * examines the existing Palm inbox and eliminate duplicate e-mails * adds GUI configuration of all functionality (except mh mailboxes). Over the next few days I intend to add support for: * mh GUI config * use a file selector to pick mailboxes * {MAYBE] add tooltips Cheers Daniel --xx-- On Tue, 2002-04-30 at 19:29, Daniel Thompson wrote: > Hi folks > > I have just started to use the gnome-pilot sendmail conduit with my Palm > M125. I've been having a few problems with it and so I have been diving > in here and there and fixing it (in 8 lines it can be made a lot more > usable!). > > I'd quite like to contribute the changes I am making back at some point > so I have the following questions. > > a) is anyone else working on the sendmail conduit? if no I will give it > a bit of a spring clean. > b) as part of the spring clean I should like to add a configuration GUI > to it, which is the best conduit to treat as a reference. > c) is anyone able/willing to act as a 'CVS gateway' for me. > > Cheers > > Daniel > --xx-- > > -- > Daniel Thompson (Merlin) <d thompson gmx net> > > If at first you don't succeed then sky diving is probably not for you. -- Daniel Thompson (Merlin) <d thompson gmx net> If at first you don't succeed then sky diving is probably not for you.
Index: gnome-pilot-conduits/email/email_conduit.c =================================================================== RCS file: /cvs/gnome/gnome-pilot-conduits/email/email_conduit.c,v retrieving revision 1.16 diff -u -r1.16 email_conduit.c --- gnome-pilot-conduits/email/email_conduit.c 25 Apr 2002 16:42:37 -0000 1.16 +++ gnome-pilot-conduits/email/email_conduit.c 5 May 2002 20:33:44 -0000 @@ -27,7 +27,7 @@ #ifdef EC_DEBUG #define LOG(format,args...) g_log (G_LOG_DOMAIN, \ G_LOG_LEVEL_MESSAGE, \ - "email: "##format, ##args) + "email: " format, ##args) #else #define LOG(format,args...) #endif @@ -52,13 +52,70 @@ (*c)->sendAction = gnome_config_get_string( "send_action=file"); (*c)->mhDirectory = gnome_config_get_string( "mh_directory" ); (*c)->mboxFile = gnome_config_get_string ( "mbox_file" ); - (*c)->receiveAction = gnome_config_get_string( "receive_action=file" ); + (*c)->receiveAction = gnome_config_get_string( "receive_action=copy" ); gnome_config_pop_prefix(); (*c)->pilotId = pilotId; g_free(prefix); } +static void +save_configuration(ConduitCfg *c) +{ + gchar *prefix; + + g_assert(c!=NULL); + + prefix = g_strdup_printf("/gnome-pilot.d/email-conduit/Pilot_%u/",c->pilotId); + + gnome_config_push_prefix(prefix); + gnome_config_set_string("sendmail", c->sendmail); + gnome_config_set_string("from_address", c->fromAddr); + gnome_config_set_string("send_action", c->sendAction); + gnome_config_set_string("mh_directory", c->mhDirectory); + gnome_config_set_string("mbox_file", c->mboxFile); + gnome_config_set_string("receive_action", c->receiveAction); + gnome_config_pop_prefix(); + gnome_config_sync(); + gnome_config_drop_all(); + + g_free(prefix); +} + +static void +copy_configuration(ConduitCfg *d, ConduitCfg *c) +{ + g_return_if_fail(c!=NULL); + g_return_if_fail(d!=NULL); + + /* it is always safe to free NULL pointers with [g_]free */ + g_free(d->sendmail); + g_free(d->fromAddr); + g_free(d->sendAction); + g_free(d->mhDirectory); + g_free(d->mboxFile); + g_free(d->receiveAction); + + d->sendmail = g_strdup(c->sendmail); + d->fromAddr = g_strdup(c->fromAddr); + d->sendAction = g_strdup(c->sendAction); + d->mhDirectory = g_strdup(c->mhDirectory); + d->mboxFile = g_strdup(c->mboxFile); + d->receiveAction = g_strdup(c->receiveAction); + + d->pilotId = c->pilotId; +} + +static ConduitCfg* +dupe_configuration(ConduitCfg *c) +{ + ConduitCfg *d; + g_return_val_if_fail(c!=NULL,NULL); + d = g_new0(ConduitCfg,1); + copy_configuration(d,c); + return d; +} + /** this method frees all data from the conduit config */ static void destroy_configuration(ConduitCfg **c) @@ -75,7 +132,6 @@ *c = NULL; } - void markline( char *msg ) { while( (*msg) != '\n' && (*msg) != 0 ) { @@ -149,6 +205,20 @@ } } +/* helper function to identify identical e-mails */ +static gint match_mail(gconstpointer a, gconstpointer b) +{ + MailDBRecord *c = (MailDBRecord *) a; + MailDBRecord *d = (MailDBRecord *) b; + + LOG("matching records [%d vs. %d]", c->size, d->size); + if (c->size != d->size) { + return 1; + } + + return memcmp(c->buffer, d->buffer, c->size); +} + static gboolean write_message_to_pilot (GnomePilotConduit *c, GnomePilotDBInfo *dbi, int dbHandle, char *buffer, int msg_num) @@ -157,6 +227,9 @@ int h; struct Mail t; int len; + GList *inbox_list; + GList *field; + MailDBRecord needle; t.to = NULL; t.from = NULL; @@ -200,6 +273,21 @@ t.body = strdup( msg ); len = pack_Mail( &t, buffer, 0xffff ); + + /* if this mail already exists in the Palms inbox then skip this mail */ + needle.size = len; + needle.buffer = buffer; + inbox_list = (GList*) gtk_object_get_data(GTK_OBJECT(c), "inbox_list"); + field = g_list_find_custom(inbox_list, &needle, match_mail); + if (field) { + /* remove the mail from the list as we've already seen it */ + inbox_list = g_list_remove_link(inbox_list, field); + gtk_object_set_data(GTK_OBJECT(c),"inbox_list",(gpointer)inbox_list); + free(field->data); + g_list_free_1(field); + LOG("Skipping message (already on Palm device)"); + return TRUE; + } if ( dlp_WriteRecord( dbi->pilot_socket, dbHandle, 0, 0, 0, buffer, len, 0 ) > 0 ) { @@ -220,6 +308,7 @@ int i; int rec; int dupe; + GList *inbox_list; g_message ("SendMail Conduit v %s",CONDUIT_VERSION); @@ -367,6 +456,42 @@ free_Mail( &t ); } + /* read in all the existing records on the Palm so that we can + * spot duplicate mails + */ + inbox_list = (GList*) gtk_object_get_data(GTK_OBJECT(c), "inbox_list"); + if ( strcmp( GET_CONFIG(c)->receiveAction, "copy" ) == 0 || + strcmp( GET_CONFIG(c)->receiveAction, "mirror" ) == 0 ) { + for ( i = 0; ; i++ ) { + int attr, length, size; + recordid_t recID; + MailDBRecord *record; + + /* iterate through records in category 0 (Inbox) ... */ + length = dlp_ReadNextRecInCategory( dbi->pilot_socket, dbHandle, 0, + buffer, &recID, 0, &size, &attr); + if ( length < 0 ) { + break; + } + + /* ... and store them in the inbox_list */ + record = (MailDBRecord *) malloc(sizeof(*record) + length); + record->recID = recID; + record->size = length; + record->buffer = ((guchar *) record) + sizeof(*record); + memcpy(record->buffer, buffer, length); + inbox_list = g_list_append(inbox_list, record); + LOG("storing record %d", recID); + } + } + + /* the above loop is likely to change the value of inbox_list so we + * must put it back + */ + gtk_object_set_data(GTK_OBJECT(c),"inbox_list",(gpointer)inbox_list); + + + if ( GET_CONFIG(c)->mhDirectory ) { #ifdef EC_DEBUG fprintf( stderr, "Reading inbound mail from %s\n", @@ -433,10 +558,7 @@ if ( GET_CONFIG(c)->mboxFile ) { FILE *f; -#ifdef EC_DEBUG - fprintf( stderr, "Reading inbound mail from %s\n", - GET_CONFIG(c)->mboxFile ); -#endif + LOG( "Reading inbound mail from %s", GET_CONFIG(c)->mboxFile ); f = fopen (GET_CONFIG (c)->mboxFile, "r"); @@ -447,12 +569,9 @@ } for( i = 1; !feof (f); i++ ) { int len; - int l; char *p; -#ifdef EC_DEBUG - fprintf( stderr, "Processing message %d", i ); -#endif + LOG( "Processing message %d", i ); len = 0; while ( ( len < sizeof(buffer) ) && ( ( p = fgets ( (char *)(buffer+len), @@ -467,7 +586,7 @@ buffer[len] = 0; len = 0; - if ( l < 0 ) { + if ( len < 0 ) { fprintf( stderr, "Error processing message %d\n", i ); break; } @@ -484,6 +603,19 @@ } } + /* in mirror mode the Palm inbox is a literal copy of the + * host's mbox, in this case we must remove any items + * remaining on the inbox_list + */ + if ( strcmp( GET_CONFIG(c)->receiveAction, "mirror" ) == 0 ) { + GList *elem = (GList*) gtk_object_get_data(GTK_OBJECT(c), "inbox_list"); + for (; elem != NULL; elem = elem->next) { + MailDBRecord *record = (MailDBRecord *) elem->data; + LOG("purging out of date record %d", record->recID); + dlp_DeleteRecord( dbi->pilot_socket, dbHandle, 0, record->recID ); + } + } + free_MailAppInfo( &tai ); dlp_ResetLastSyncPC( dbi->pilot_socket ); @@ -496,34 +628,255 @@ return( synchronize( c, dbi ) ); } +static GtkWidget +*createCfgWindow (GnomePilotConduit* conduit) +{ + GtkWidget *vbox, *table; + GtkWidget *label, *widget; + GtkWidget *menu, *group, *menuItem; + + 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); + + /* send_action option menu */ + label = gtk_label_new(_("Send Action")); + widget = gtk_option_menu_new (); + menu = gtk_menu_new(); + menuItem = gtk_menu_item_new_with_label (_("Delete from PDA")); + gtk_object_set_data(GTK_OBJECT(menuItem), "short", "delete"); + gtk_object_set_data(GTK_OBJECT(widget), "delete", (gpointer) 0); + gtk_menu_append (GTK_MENU (menu), GTK_WIDGET (menuItem)); + menuItem = gtk_menu_item_new_with_label (_("File on PDA")); + gtk_object_set_data(GTK_OBJECT(menuItem), "short", "file"); + gtk_object_set_data(GTK_OBJECT(widget), "file", (gpointer) 1); + gtk_menu_append (GTK_MENU (menu), GTK_WIDGET (menuItem)); + gtk_option_menu_set_menu (GTK_OPTION_MENU (widget), GTK_WIDGET (menu)); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); + gtk_table_attach_defaults(GTK_TABLE(table), widget, 1, 2, 0, 1); + gtk_object_set_data(GTK_OBJECT(vbox), "send_action", widget); + + /* from_address entry */ + label = gtk_label_new(_("From:")); + widget = gtk_entry_new_with_max_length(128); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + gtk_table_attach_defaults(GTK_TABLE(table), widget, 1, 2, 1, 2); + gtk_object_set_data(GTK_OBJECT(vbox), "from_address", widget); + + /* sendmail entry */ + label = gtk_label_new(_("Sendmail command")); + widget = gtk_entry_new_with_max_length(128); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3); + gtk_table_attach_defaults(GTK_TABLE(table), widget, 1, 2, 2, 3); + gtk_object_set_data(GTK_OBJECT(vbox), "sendmail", widget); + + /* receive_action option menu */ + label = gtk_label_new (_("Receive Action")); + widget = gtk_option_menu_new (); + menu = gtk_menu_new (); + menuItem = gtk_menu_item_new_with_label (_("Copy from Inbox")); + gtk_object_set_data(GTK_OBJECT(menuItem), "short", "copy"); + gtk_object_set_data(GTK_OBJECT(widget), "copy", (gpointer) 0); + gtk_menu_append (GTK_MENU (menu), GTK_WIDGET (menuItem)); + menuItem = gtk_menu_item_new_with_label (_("Delete from Inbox")); + gtk_object_set_data(GTK_OBJECT(menuItem), "short", "delete"); + gtk_object_set_data(GTK_OBJECT(widget), "delete", (gpointer) 1); + gtk_menu_append (GTK_MENU (menu), GTK_WIDGET (menuItem)); + menuItem = gtk_menu_item_new_with_label (_("Mirror Inbox")); + gtk_object_set_data(GTK_OBJECT(menuItem), "short", "mirror"); + gtk_object_set_data(GTK_OBJECT(widget), "mirror", (gpointer) 2); + gtk_menu_append (GTK_MENU (menu), GTK_WIDGET (menuItem)); + gtk_option_menu_set_menu (GTK_OPTION_MENU (widget), GTK_WIDGET (menu)); + gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, 3, 4); + gtk_table_attach_defaults(GTK_TABLE(table), widget, 1, 2, 3, 4); + gtk_object_set_data(GTK_OBJECT(vbox), "receive_action", widget); + + /* mbox_file entry */ + label = gtk_label_new(_("Copy mail from")); + widget = gtk_entry_new_with_max_length(128); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 4, 5); + gtk_table_attach_defaults(GTK_TABLE(table), widget, 1, 2, 4, 5); + gtk_object_set_data(GTK_OBJECT(vbox), "mbox_file", widget); + + return vbox; +} + +static void +setOptionsCfg(GtkWidget *cfg, ConduitCfg *c) +{ + GtkWidget *send_action, *from_address, *sendmail, *receive_action, *mbox_file; + GtkWidget *menuItem; + guint id; + + /* fetch all the controls from the cfg window */ + send_action = gtk_object_get_data(GTK_OBJECT(cfg), "send_action"); + from_address = gtk_object_get_data(GTK_OBJECT(cfg), "from_address"); + sendmail = gtk_object_get_data(GTK_OBJECT(cfg), "sendmail"); + receive_action = gtk_object_get_data(GTK_OBJECT(cfg), "receive_action"); + mbox_file = gtk_object_get_data(GTK_OBJECT(cfg), "mbox_file"); + + id = (guint) gtk_object_get_data(GTK_OBJECT(send_action), c->sendAction); + gtk_option_menu_set_history(GTK_OPTION_MENU(send_action), id); + + gtk_entry_set_text(GTK_ENTRY(from_address), (c->fromAddr ? c->fromAddr : "")); + gtk_entry_set_text(GTK_ENTRY(sendmail), (c->sendmail ? c->sendmail : "")); + + id = (guint) gtk_object_get_data(GTK_OBJECT(receive_action), c->receiveAction); + gtk_option_menu_set_history(GTK_OPTION_MENU(receive_action), id); + + gtk_entry_set_text(GTK_ENTRY(mbox_file), (c->mboxFile ? c->mboxFile : "")); +} + +static void +readOptionsCfg(GtkWidget *cfg, ConduitCfg *c) +{ + GtkWidget *send_action, *from_address, *sendmail, *receive_action, *mbox_file; + GtkWidget *menu, *menuItem; + gchar *str; + + /* fetch all the controls from the cfg window */ + send_action = gtk_object_get_data(GTK_OBJECT(cfg), "send_action"); + from_address = gtk_object_get_data(GTK_OBJECT(cfg), "from_address"); + sendmail = gtk_object_get_data(GTK_OBJECT(cfg), "sendmail"); + receive_action = gtk_object_get_data(GTK_OBJECT(cfg), "receive_action"); + mbox_file = gtk_object_get_data(GTK_OBJECT(cfg), "mbox_file"); + + menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(send_action)); + menuItem = gtk_menu_get_active(GTK_MENU(menu)); + str = g_strdup(gtk_object_get_data(GTK_OBJECT(menuItem), "short")); + g_free(c->sendAction); + c->sendAction = str; + + str = gtk_editable_get_chars(GTK_EDITABLE(from_address), 0, -1); + if (0 == strcmp(str, "")) { + g_free(str); + str = NULL; + } + g_free(c->fromAddr); + c->fromAddr = str; + + str = gtk_editable_get_chars(GTK_EDITABLE(sendmail), 0, -1); + if (0 == strcmp(str, "")) { + g_free(str); + str = NULL; + } + g_free(c->sendmail); + c->sendmail = str; + + menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(receive_action)); + menuItem = gtk_menu_get_active(GTK_MENU(menu)); + str = g_strdup(gtk_object_get_data(GTK_OBJECT(menuItem), "short")); + g_free(c->receiveAction); + c->receiveAction = str; + + str = gtk_editable_get_chars(GTK_EDITABLE(mbox_file), 0, -1); + if (0 == strcmp(str, "")) { + g_free(str); + str = NULL; + } + g_free(c->mboxFile); + c->mboxFile = str; +} + +static gint +create_settings_window (GnomePilotConduit *conduit, GtkWidget *parent, gpointer data) +{ + GtkWidget *cfgWindow; + cfgWindow = createCfgWindow(conduit); + gtk_container_add(GTK_CONTAINER(parent),cfgWindow); + gtk_widget_show_all(cfgWindow); + + gtk_object_set_data(GTK_OBJECT(conduit),OBJ_DATA_CONFIG_WINDOW,cfgWindow); + setOptionsCfg(GET_CONDUIT_WINDOW(conduit),GET_CONFIG(conduit)); + + return 0; +} + +static void +display_settings (GnomePilotConduit *conduit, gpointer data) +{ + setOptionsCfg(GET_CONDUIT_WINDOW(conduit),GET_CONFIG(conduit)); +} + +static void +save_settings (GnomePilotConduit *conduit, gpointer data) +{ + readOptionsCfg(GET_CONDUIT_WINDOW(conduit),GET_CONFIG(conduit)); + save_configuration(GET_CONFIG(conduit)); +} + +static void +revert_settings (GnomePilotConduit *conduit, gpointer data) +{ + ConduitCfg *cfg,*cfg2; + + cfg2= GET_OLDCONFIG(conduit); + cfg = GET_CONFIG(conduit); + save_configuration(cfg2); + copy_configuration(cfg,cfg2); + setOptionsCfg(GET_CONDUIT_WINDOW(conduit),cfg); +} + GnomePilotConduit *conduit_get_gpilot_conduit( guint32 pilotId ) { GtkObject *retval; - ConduitCfg *cc; + ConduitCfg *cfg1, *cfg2; retval = gnome_pilot_conduit_standard_new("MailDB",0x6d61696c, NULL); g_assert(retval != NULL); + + /* conduit signals */ /* 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, "copy_to_pilot", (GtkSignalFunc) ,NULL); + gtk_signal_connect(retval, "merge_to_pilot", (GtkSignalFunc) ,NULL); gtk_signal_connect(retval, "merge_from_pilot", (GtkSignalFunc)synchronize ,NULL); */ gtk_signal_connect(retval, "synchronize", (GtkSignalFunc)synchronize ,NULL); - load_configuration(&cc, pilotId ); - gtk_object_set_data(retval,"conduit_config",(gpointer)cc); + /* GUI signals */ + gtk_signal_connect (retval, + GNOME_PILOT_CONDUIT_SIGNAL_CREATE_SETTINGS_WINDOW (create_settings_window), + NULL); + gtk_signal_connect (retval, + GNOME_PILOT_CONDUIT_SIGNAL_DISPLAY_SETTINGS (display_settings), + NULL); + gtk_signal_connect (retval, + GNOME_PILOT_CONDUIT_SIGNAL_SAVE_SETTINGS (save_settings), + NULL); + gtk_signal_connect (retval, + GNOME_PILOT_CONDUIT_SIGNAL_REVERT_SETTINGS (revert_settings), + NULL); + + load_configuration(&cfg1, pilotId ); + cfg2 = dupe_configuration(cfg1); + gtk_object_set_data(retval,OBJ_DATA_CONFIG,(gpointer)cfg1); + gtk_object_set_data(retval,OBJ_DATA_OLDCONFIG,(gpointer)cfg2); + return GNOME_PILOT_CONDUIT(retval); } - void conduit_destroy_gpilot_conduit( GnomePilotConduit *c ) { - ConduitCfg *cc; + ConduitCfg *cfg1, *cfg2; + GList *inbox_list, *list; - cc = GET_CONFIG(c); - destroy_configuration( &cc ); + cfg1 = GET_CONFIG(c); + cfg2 = GET_OLDCONFIG(c); + destroy_configuration( &cfg1 ); + destroy_configuration( &cfg2 ); + + inbox_list = (GList*) gtk_object_get_data(GTK_OBJECT(c), "inbox_list"); + for (list = inbox_list; list != NULL; list = list->next) { + free(list->data); + } + g_list_free(inbox_list); + inbox_list = NULL; + gtk_object_destroy(GTK_OBJECT(c)); } Index: gnome-pilot-conduits/email/email_conduit.h =================================================================== RCS file: /cvs/gnome/gnome-pilot-conduits/email/email_conduit.h,v retrieving revision 1.11 diff -u -r1.11 email_conduit.h --- gnome-pilot-conduits/email/email_conduit.h 5 Aug 2000 02:02:23 -0000 1.11 +++ gnome-pilot-conduits/email/email_conduit.h 5 May 2002 20:33:44 -0000 @@ -3,6 +3,10 @@ #ifndef __EMAIL_CONDUIT_H__ #define __EMAIL_CONDUIT_H__ +#define OBJ_DATA_CONFIG "conduit_config" +#define OBJ_DATA_OLDCONFIG "conduit_oldconfig" +#define OBJ_DATA_CONFIG_WINDOW "config_window" + typedef struct ConduitCfg { gchar *sendmail; gchar *fromAddr; @@ -14,6 +18,14 @@ pid_t child; } ConduitCfg; -#define GET_CONFIG(c) ((ConduitCfg*)(gtk_object_get_data(GTK_OBJECT(c),"conduit_config"))) +typedef struct MailDBRecord { + int recID; + int size; + guchar *buffer; +} MailDBRecord; + +#define GET_CONFIG(c) ((ConduitCfg*)(gtk_object_get_data(GTK_OBJECT(c),OBJ_DATA_CONFIG))) +#define GET_OLDCONFIG(c) ((ConduitCfg*)(gtk_object_get_data(GTK_OBJECT(c),OBJ_DATA_OLDCONFIG))) +#define GET_CONDUIT_WINDOW(s) ((GtkWidget*)gtk_object_get_data(GTK_OBJECT(s),OBJ_DATA_CONFIG_WINDOW)) #endif
Attachment:
signature.asc
Description: This is a digitally signed message part