1 /*
2  *  xfce4-mailwatch-plugin - a mail notification applet for the xfce4 panel
3  *  Copyright (c) 2005 Pasi Orovuo <pasi.ov@gmail.com>
4  *  Copyright (c) 2008 Brian Tarricone <bjt23@cornell.edu>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License ONLY.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 
32 #ifdef HAVE_SYS_STAT_H
33 #include <sys/stat.h>
34 #endif
35 
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 
40 #ifdef HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif
43 
44 #ifdef HAVE_ERRNO_H
45 #include <errno.h>
46 #endif
47 
48 #include <gtk/gtk.h>
49 
50 #include <libxfce4util/libxfce4util.h>
51 #include <libxfce4ui/libxfce4ui.h>
52 
53 #include "mailwatch.h"
54 
55 #define XFCE_MAILWATCH_MH_MAILBOX( p )      ( (XfceMailwatchMHMailbox *) p )
56 #define BORDER          ( 8 )
57 
58 #define MH_PLUGIN_NAME  "mh-maildir-plugin"
59 /* For now these ain't user configurable (from gui) - Should they be? */
60 #define MH_PROFILE      ( ".mh_profile" )
61 #define MH_SEQUENCES    ( ".mh_sequences" )
62 #define MH_INBOX        ( "inbox" )
63 #define MH_UNSEEN_SEQ   ( "unseen" )
64 
65 typedef struct {
66     XfceMailwatchMailbox    *xfce_mailwatch_mailbox;
67     XfceMailwatch           *mailwatch;
68 
69     gchar                   *mh_profile_fn;
70     time_t                  mh_profile_ctime;
71     gchar                   *mh_sequences_fn;
72     time_t                  mh_sequences_ctime;
73     gchar                   *unseen_sequence; /* This should be a list as there can be multiple? */
74 
75     guint                   timeout;
76     guint                   last_update;
77 
78     gint                    running;
79     gpointer                thread;  /* (GThread *) */
80     guint                   check_id;
81 } XfceMailwatchMHMailbox;
82 
83 typedef struct {
84     gchar                   *component;
85     gchar                   *value;
86 } MHProfileEntry;
87 
88 static void
mh_profile_free(GList * list)89 mh_profile_free( GList *list )
90 {
91     GList       *li;
92 
93     DBG( " " );
94 
95     for ( li = g_list_first( list ); li != NULL; li = g_list_next( li ) ) {
96         MHProfileEntry     *entry = li->data;
97 
98         g_free( entry->component );
99         g_free( entry->value );
100     }
101     g_list_free( list );
102 }
103 
104 #ifdef DEBUG
105 static void
mh_profile_print(GList * profile)106 mh_profile_print( GList *profile )
107 {
108     GList       *li;
109 
110     for ( li = g_list_first( profile ); li != NULL; li = g_list_next( li ) ) {
111         MHProfileEntry     *e = li->data;
112 
113         DBG( "%s: %s", e->component, e->value );
114     }
115 }
116 #endif /* DEBUG */
117 
118 static MHProfileEntry *
mh_profile_entry_create_new(const char * line)119 mh_profile_entry_create_new( const char *line )
120 {
121     MHProfileEntry *entry = NULL;
122     gchar                       **v;
123 
124     v = g_strsplit( line, ":", 2 );
125 
126     if ( v && v[0] && v[1] ) {
127         entry = g_new0( MHProfileEntry, 1 );
128 
129         entry->component    = g_strstrip( v[0] );
130         entry->value        = g_strstrip( v[1] );
131 
132         g_free( v );
133     }
134     else {
135         g_strfreev( v );
136     }
137     return ( entry );
138 }
139 
140 static gchar *
mh_profile_readline(XfceMailwatchMHMailbox * mh,const gchar * mh_profile,GIOChannel * ioc)141 mh_profile_readline( XfceMailwatchMHMailbox *mh, const gchar *mh_profile, GIOChannel *ioc )
142 {
143     gchar           *line = NULL, *curline;
144     gsize           nread, newline;
145     GIOStatus       status;
146     GError          *error = NULL;
147 
148     g_return_val_if_fail( ioc != NULL, NULL );
149 
150     status = g_io_channel_read_line( ioc, &curline,
151                                      &nread, &newline,
152                                      &error );
153     while ( status == G_IO_STATUS_NORMAL ) {
154         gchar       c;
155 
156         curline[newline] = 0;
157 
158         if ( !*curline ) {
159             /* An mh profile shouldn't contain blank lines. Ignore 'em */
160             g_free( curline );
161         }
162         else {
163             if ( !line ) {
164                 if ( g_ascii_isspace( *curline ) ) {
165                     /* The profile isn't right, ignore */
166                     curline = g_strstrip( curline );
167                 }
168 
169                 line = curline;
170             }
171             else {
172                 gchar       *p;
173 
174                 curline = g_strstrip( curline );
175 
176                 p = g_strconcat( line, curline, NULL );
177 
178                 g_free( line );
179                 g_free( curline );
180 
181                 line = p;
182             }
183 
184             if ( g_io_channel_read_chars( ioc, &c, 1, &nread, NULL ) == G_IO_STATUS_NORMAL ) {
185                 if ( !g_ascii_isspace( c ) || g_ascii_iscntrl( c ) ) {
186                     /* g_ascii_iscntrl() is supposed to catch newlines */
187                     g_io_channel_seek_position( ioc, -1, G_SEEK_CUR, NULL );
188                     break;
189                 }
190             }
191         }
192 
193         status = g_io_channel_read_line( ioc, &curline,
194                                          &nread, &newline,
195                                          &error );
196     }
197 
198     if ( status == G_IO_STATUS_ERROR ) {
199         xfce_mailwatch_log_message( mh->mailwatch, XFCE_MAILWATCH_MAILBOX( mh ),
200                                     XFCE_MAILWATCH_LOG_WARNING,
201                                     "Error reading file %s: %s",
202                                     mh_profile, error->message );
203 
204         g_error_free( error );
205     }
206 
207     return ( line );
208 }
209 
210 static GList *
mh_profile_read(XfceMailwatchMHMailbox * mh,const gchar * mh_profile)211 mh_profile_read( XfceMailwatchMHMailbox *mh, const gchar *mh_profile )
212 {
213     GIOChannel      *ioc;
214     GError          *error = NULL;
215     gchar           *line = NULL;
216     GList           *li = NULL;
217 
218     DBG( "-->>" );
219 
220     ioc = g_io_channel_new_file( mh_profile, "r", &error );
221     if ( !ioc ) {
222         xfce_mailwatch_log_message( mh->mailwatch, XFCE_MAILWATCH_MAILBOX( mh ),
223                                     XFCE_MAILWATCH_LOG_ERROR,
224                                     "Failed to open file %s: %s",
225                                     mh_profile, error->message );
226         g_error_free( error );
227         return ( NULL );
228     }
229     g_io_channel_set_encoding( ioc, NULL, NULL );
230 
231     while ( ( line = mh_profile_readline( mh, mh_profile, ioc ) ) ) {
232         MHProfileEntry          *entry;
233 
234         entry = mh_profile_entry_create_new( line );
235         if ( entry ) {
236             li = g_list_prepend( li, entry );
237         }
238         else {
239             xfce_mailwatch_log_message( mh->mailwatch, XFCE_MAILWATCH_MAILBOX( mh ),
240                     XFCE_MAILWATCH_LOG_WARNING,
241                     _( "Malformed line %s in %s ignored." ), line, mh_profile );
242         }
243         g_free( line );
244     }
245 
246     g_io_channel_shutdown( ioc, FALSE, NULL );
247     g_io_channel_unref( ioc );
248 
249     DBG( "<<--" );
250     return ( li );
251 }
252 
253 static gint
mh_profile_entry_compare(gconstpointer a,gconstpointer b)254 mh_profile_entry_compare( gconstpointer a, gconstpointer b )
255 {
256     const MHProfileEntry    *e = a;
257 
258     DBG( "%s <-> %s", e->component, (const gchar *) b );
259 
260     return ( g_ascii_strcasecmp( e->component, b ) );
261 }
262 
263 static gchar *
mh_profile_entry_get_value(GList * profile,const gchar * component)264 mh_profile_entry_get_value( GList *profile, const gchar *component )
265 {
266     MHProfileEntry          *entry;
267     GList                   *li;
268 
269     DBG( "--> %s", component );
270 
271     li = g_list_find_custom( profile, component, mh_profile_entry_compare );
272     if ( !li ) {
273         DBG( "NULL" );
274         return ( NULL );
275     }
276     entry = li->data;
277 
278     g_assert( entry != NULL );
279 
280     return ( g_strdup( entry->value ) );
281 }
282 
283 static gchar *
mh_get_profile_filename(void)284 mh_get_profile_filename( void )
285 {
286     const gchar *env;
287     gchar       *mh_profile;
288 
289     env = g_getenv( "MH" );
290     if ( env ) {
291         if ( !g_path_is_absolute( env ) ) {
292             gchar       *curdir = g_get_current_dir();
293 
294             mh_profile = g_build_filename( curdir, env, NULL );
295 
296             g_free( curdir );
297         }
298         else {
299             mh_profile = g_strdup( env );
300         }
301     }
302     else {
303         mh_profile = g_build_filename( g_get_home_dir(), MH_PROFILE, NULL );
304     }
305     return ( mh_profile );
306 }
307 
308 static void
mh_read_config(XfceMailwatchMHMailbox * mh)309 mh_read_config( XfceMailwatchMHMailbox *mh )
310 {
311     gchar       *mh_path = NULL, *mh_inbox = NULL;
312     gchar       *mh_sequences = NULL, *tmpptr = NULL;
313     GList       *profile;
314 
315     DBG( "-->>" );
316 
317     if ( mh->mh_sequences_fn ) {
318         g_free( mh->mh_sequences_fn );
319         mh->mh_sequences_fn = NULL;
320     }
321     if ( mh->unseen_sequence ) {
322         g_free( mh->unseen_sequence );
323         mh->unseen_sequence = NULL;
324     }
325 
326     if ( !mh->mh_profile_fn ) {
327         mh->mh_profile_fn = mh_get_profile_filename();
328     }
329 
330     profile = mh_profile_read( mh, mh->mh_profile_fn );
331     if ( !profile ) {
332         DBG( "Profile == NULL" );
333         return;
334     }
335 
336 #ifdef DEBUG
337     mh_profile_print( profile );
338 #endif
339 
340     mh_path = mh_profile_entry_get_value( profile, "Path" );
341     if ( !mh_path ) {
342         mh_profile_free( profile );
343         return;
344     }
345 
346     if ( !g_path_is_absolute( mh_path ) ) {
347         tmpptr = g_build_filename( g_get_home_dir(), mh_path, NULL );
348         g_free( mh_path );
349         mh_path = tmpptr;
350     }
351 
352     mh_inbox = mh_profile_entry_get_value( profile, "Inbox" );
353     mh_sequences = mh_profile_entry_get_value( profile, "mh-sequences" );
354 
355     mh->unseen_sequence = mh_profile_entry_get_value( profile, "Unseen-Sequence" );
356 
357     mh->mh_sequences_fn = g_build_filename( mh_path,
358             mh_inbox ? mh_inbox : MH_INBOX,
359             mh_sequences ? mh_sequences : MH_SEQUENCES,
360             NULL );
361 
362     g_free( mh_path );
363     if ( mh_inbox ) {
364         g_free( mh_inbox );
365     }
366     if ( mh_sequences ) {
367         g_free( mh_sequences );
368     }
369     mh_profile_free( profile );
370 }
371 
372 static void
mh_check_mail(XfceMailwatchMHMailbox * mh)373 mh_check_mail( XfceMailwatchMHMailbox *mh )
374 {
375     struct stat     st;
376 
377     DBG( "-->>" );
378 
379     if ( !mh->mh_profile_fn ) {
380         mh->mh_profile_fn = mh_get_profile_filename();
381     }
382 
383     if ( stat( mh->mh_profile_fn, &st ) == 0 ) {
384         if ( st.st_ctime != mh->mh_profile_ctime ) {
385             mh_read_config( mh );
386             mh->mh_profile_ctime = st.st_ctime;
387         }
388     }
389     else {
390         xfce_mailwatch_log_message( mh->mailwatch, XFCE_MAILWATCH_MAILBOX( mh ),
391                                     XFCE_MAILWATCH_LOG_WARNING,
392                                     _( "Failed to get status of file %s: %s" ),
393                                     mh->mh_profile_fn, strerror( errno ) );
394     }
395 
396     if ( !mh->mh_sequences_fn ) {
397         return;
398     }
399 
400     if ( stat( mh->mh_sequences_fn, &st ) < 0 ) {
401         xfce_mailwatch_log_message( mh->mailwatch, XFCE_MAILWATCH_MAILBOX( mh ),
402                                     XFCE_MAILWATCH_LOG_ERROR,
403                                     _( "Failed to get status of file %s: %s" ),
404                                     mh->mh_sequences_fn, strerror( errno ) );
405     }
406     else {
407         if ( st.st_ctime != mh->mh_sequences_ctime ) {
408             GList           *seqlist;
409             gchar           *unseen;
410             gulong          num_new = 0;
411 
412             mh->mh_sequences_ctime = st.st_ctime;
413 
414             seqlist = mh_profile_read( mh, mh->mh_sequences_fn );
415 
416 #ifdef DEBUG
417             mh_profile_print( seqlist );
418 #endif
419 
420             unseen = mh_profile_entry_get_value( seqlist,
421                     mh->unseen_sequence ? mh->unseen_sequence : MH_UNSEEN_SEQ  );
422             mh_profile_free( seqlist );
423             if ( unseen ) {
424                 gchar       **v;
425                 guint       i;
426 
427                 v = g_strsplit_set( unseen, " \t\r\n", 0 );
428                 g_free( unseen );
429 
430                 for ( i = 0; v[i] != NULL; i++ ) {
431                     gchar       *q = NULL;
432                     gulong      l1, l2;
433 
434                     l1 = strtoul( v[i], &q, 10 );
435                     if ( q && *q ) {
436                         q++;
437 
438                         l2 = strtoul( q, NULL, 10 );
439                         if ( l2 ) {
440                             l1 = 1 + l2 - l1;
441                         }
442                         else {
443                             /* In this case some sort of error occured */
444                             l1 = 1;
445                         }
446                     }
447                     else {
448                         l1 = 1;
449                     }
450 
451                     num_new += l1;
452                 }
453                 g_strfreev( v );
454             }
455             xfce_mailwatch_signal_new_messages( mh->mailwatch, XFCE_MAILWATCH_MAILBOX( mh ), num_new );
456         }
457     }
458 
459     DBG( "<<--" );
460 }
461 
462 static gpointer
mh_main_thread(gpointer data)463 mh_main_thread( gpointer data )
464 {
465     XfceMailwatchMHMailbox  *mh = XFCE_MAILWATCH_MH_MAILBOX( data );
466 
467     while( !g_atomic_pointer_get( &mh->thread ) && g_atomic_int_get( &mh->running ) )
468         g_thread_yield();
469 
470     if( g_atomic_int_get( &mh->running ) )
471         mh_check_mail( mh );
472 
473     g_atomic_pointer_set( &mh->thread, NULL );
474     return ( NULL );
475 }
476 
477 static gboolean
mh_check_mail_timeout(gpointer data)478 mh_check_mail_timeout(gpointer data)
479 {
480     XfceMailwatchMHMailbox *mh = XFCE_MAILWATCH_MH_MAILBOX( data );
481     GThread                *th;
482 
483     if( g_atomic_pointer_get( &mh->thread ) ) {
484         xfce_mailwatch_log_message( mh->mailwatch,
485                                     XFCE_MAILWATCH_MAILBOX( mh ),
486                                     XFCE_MAILWATCH_LOG_WARNING,
487                                     _( "Previous thread hasn't exited yet, not checking mail this time." ) );
488         return TRUE;
489     }
490 
491     th = g_thread_try_new( NULL, mh_main_thread, mh, NULL );
492     g_atomic_pointer_set( &mh->thread, th );
493 
494     return TRUE;
495 }
496 
497 static XfceMailwatchMailbox *
mh_new(XfceMailwatch * mailwatch,XfceMailwatchMailboxType * type)498 mh_new( XfceMailwatch *mailwatch, XfceMailwatchMailboxType *type )
499 {
500     XfceMailwatchMHMailbox  *mh;
501 
502     DBG( "entering" );
503 
504     mh = g_new0( XfceMailwatchMHMailbox, 1 );
505 
506     mh->mailwatch       = mailwatch;
507     mh->timeout         = XFCE_MAILWATCH_DEFAULT_TIMEOUT;
508 
509     return ( XFCE_MAILWATCH_MAILBOX( mh ) );
510 }
511 
512 static void
mh_restore_param_list(XfceMailwatchMailbox * mailbox,GList * params)513 mh_restore_param_list( XfceMailwatchMailbox *mailbox, GList *params )
514 {
515     XfceMailwatchMHMailbox  *mh = XFCE_MAILWATCH_MH_MAILBOX( mailbox );
516     GList                   *li;
517 
518     DBG( "-->>" );
519 
520     for ( li = g_list_first( params ); li != NULL; li = g_list_next( li ) ) {
521         XfceMailwatchParam  *param = li->data;
522 
523         if ( !strcmp( param->key, "timeout" ) ) {
524             mh->timeout = (guint) atol( param->value );
525         }
526     }
527 }
528 
529 static GList *
mh_save_param_list(XfceMailwatchMailbox * mailbox)530 mh_save_param_list( XfceMailwatchMailbox *mailbox )
531 {
532     XfceMailwatchMHMailbox  *mh = XFCE_MAILWATCH_MH_MAILBOX( mailbox );
533     XfceMailwatchParam      *param;
534     GList                   *params = NULL;
535 
536     DBG( "-->>" );
537 
538     param           = g_new( XfceMailwatchParam, 1 );
539     param->key      = g_strdup( "timeout" );
540     param->value    = g_strdup_printf( "%u", mh->timeout );
541     params = g_list_prepend( params, param );
542 
543     return ( params );
544 }
545 
546 static void
mh_timeout_changed_cb(GtkWidget * spinner,XfceMailwatchMHMailbox * mh)547 mh_timeout_changed_cb( GtkWidget *spinner, XfceMailwatchMHMailbox *mh )
548 {
549     guint value = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spinner ) ) * 60;
550 
551     DBG( "-->>" );
552 
553     if( value == mh->timeout )
554         return;
555 
556     mh->timeout = value;
557 
558     if( g_atomic_int_get( &mh->running ) ) {
559         if( mh->check_id )
560             g_source_remove( mh->check_id );
561         mh->check_id = g_timeout_add( mh->timeout * 1000,
562                                       mh_check_mail_timeout,
563                                       mh );
564     }
565 }
566 
567 static GtkContainer *
mh_get_setup_page(XfceMailwatchMailbox * mailbox)568 mh_get_setup_page( XfceMailwatchMailbox *mailbox )
569 {
570     XfceMailwatchMHMailbox  *mh = XFCE_MAILWATCH_MH_MAILBOX( mailbox );
571     GtkWidget               *vbox, *hbox;
572     GtkWidget               *label, *spinner;
573 
574     vbox = gtk_box_new( GTK_ORIENTATION_VERTICAL, BORDER );
575     gtk_widget_show( vbox );
576 
577     hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, BORDER );
578     gtk_widget_show( hbox );
579     gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
580 
581     label = gtk_label_new( _( "The configuration of this plugin is read from\n"
582                               "the default mh maildir profile file ~/.mh_profile" ) );
583     gtk_widget_show( label );
584     gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 );
585 
586     hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, BORDER );
587     gtk_widget_show( hbox );
588     gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
589 
590     label = gtk_label_new_with_mnemonic( _( "_Interval:" ) );
591     gtk_widget_show( label );
592     gtk_label_set_xalign( GTK_LABEL( label ), 1.0 );
593     gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 );
594 
595     spinner = gtk_spin_button_new_with_range( 1.0, 1440.0, 1.0 );
596     gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spinner ), TRUE );
597     gtk_spin_button_set_wrap( GTK_SPIN_BUTTON( spinner ), FALSE );
598     gtk_spin_button_set_value( GTK_SPIN_BUTTON( spinner ), mh->timeout / 60 );
599     gtk_widget_show( spinner );
600     gtk_box_pack_start( GTK_BOX( hbox ), spinner, FALSE, FALSE, 0 );
601     g_signal_connect( G_OBJECT( spinner ), "value-changed",
602             G_CALLBACK( mh_timeout_changed_cb ), mh );
603     gtk_label_set_mnemonic_widget( GTK_LABEL( label ), spinner );
604 
605     label = gtk_label_new( _( "minute(s)." ) );
606     gtk_widget_show( label );
607     gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 );
608 
609     return ( GTK_CONTAINER( vbox ) );
610 }
611 
612 static void
mh_force_update_cb(XfceMailwatchMailbox * mailbox)613 mh_force_update_cb( XfceMailwatchMailbox *mailbox )
614 {
615     XfceMailwatchMHMailbox     *mh = XFCE_MAILWATCH_MH_MAILBOX( mailbox );
616 
617     DBG( " " );
618 
619     if( !g_atomic_pointer_get( &mh->thread ) ) {
620         gboolean restart = FALSE;
621 
622         if( mh->check_id ) {
623             g_source_remove( mh->check_id );
624             restart = TRUE;
625         }
626 
627         mh_check_mail_timeout( mh );
628 
629         if( restart ) {
630             mh->check_id = g_timeout_add( mh->timeout * 1000,
631                                           mh_check_mail_timeout,
632                                           mh );
633         }
634     }
635 }
636 
637 static void
mh_set_activated_cb(XfceMailwatchMailbox * mailbox,gboolean activate)638 mh_set_activated_cb( XfceMailwatchMailbox *mailbox, gboolean activate )
639 {
640     XfceMailwatchMHMailbox *mh = XFCE_MAILWATCH_MH_MAILBOX( mailbox );
641 
642     DBG( " " );
643 
644     if( activate == g_atomic_int_get( &mh->running ) )
645         return;
646 
647     if( activate ) {
648         g_atomic_int_set( &mh->running, TRUE );
649         mh->check_id = g_timeout_add( mh->timeout * 1000, mh_check_mail_timeout, mh );
650     } else {
651         g_atomic_int_set( &mh->running, FALSE );
652         g_source_remove( mh->check_id );
653         mh->check_id = 0;
654     }
655 }
656 
657 static void
mh_free(XfceMailwatchMailbox * mailbox)658 mh_free( XfceMailwatchMailbox *mailbox )
659 {
660     XfceMailwatchMHMailbox  *mh = XFCE_MAILWATCH_MH_MAILBOX( mailbox );
661 
662     DBG( "-->>" );
663 
664     mh_set_activated_cb( mailbox, FALSE );
665     while( g_atomic_pointer_get( &mh->thread ) )
666         g_thread_yield();
667 
668     if ( mh->mh_profile_fn ) {
669         g_free( mh->mh_profile_fn );
670     }
671     if ( mh->mh_sequences_fn ) {
672         g_free( mh->mh_sequences_fn );
673     }
674     if ( mh->unseen_sequence ) {
675         g_free( mh->unseen_sequence );
676     }
677 
678     g_free( mh );
679 }
680 
681 XfceMailwatchMailboxType builtin_mailbox_type_mh = {
682     "mh-maildir",
683     N_( "Local MH mail folder" ),
684     N_( "MH plugin watches local MH folders for new mail" ),
685     mh_new,
686     mh_set_activated_cb,
687     mh_force_update_cb,
688     mh_get_setup_page,
689     mh_restore_param_list,
690     mh_save_param_list,
691     mh_free
692 };
693 
694