]> git.deb.at Git - pkg/abook.git/blob - abook.c
print some error messages to sterr instead of stdout
[pkg/abook.git] / abook.c
1 /*
2  * $Id$
3  *
4  * by JH <jheinonen@users.sourceforge.net>
5  *
6  * Copyright (C) Jaakko Heinonen
7  */
8
9 #include <string.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <sys/stat.h>
13 #include <signal.h>
14 #include <fcntl.h>
15 #ifdef HAVE_CONFIG_H
16 #       include "config.h"
17 #endif
18 #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
19 #       include <locale.h>
20 #endif
21 #include "abook.h"
22 #include "ui.h"
23 #include "database.h"
24 #include "list.h"
25 #include "filter.h"
26 #include "edit.h"
27 #include "misc.h"
28 #include "options.h"
29 #include "getname.h"
30
31 static void             init_abook();
32 static void             set_filenames();
33 static void             free_filenames();
34 static void             parse_command_line(int argc, char **argv);
35 static void             show_usage();
36 static void             mutt_query(char *str);
37 static void             init_mutt_query();
38 static void             quit_mutt_query();
39 static void             convert(char *srcformat, char *srcfile,
40                                 char *dstformat, char *dstfile);
41 static void             add_email(int);
42
43 char *datafile = NULL;
44 char *rcfile = NULL;
45
46 static void
47 init_abook()
48 {
49         set_filenames();
50         init_options();
51
52         signal(SIGKILL, quit_abook);
53         signal(SIGTERM, quit_abook);
54         
55         if( init_ui() )
56                 exit(1);
57         
58         umask(DEFAULT_UMASK);
59
60         /*
61          * this is very ugly for now
62          */
63         /*if( options_get_int("datafile", "autosave") )*/
64
65         if( load_database(datafile) == 2 ) {
66                 char *tmp = strconcat(getenv("HOME"),
67                                 "/" DATAFILE, NULL);
68
69                 if( safe_strcmp(tmp, datafile) ) {
70                         refresh_screen();
71                         statusline_msg("Sorry, the specified file does "
72                                 "not appear to be a valid abook addressbook");
73                         statusline_msg("Will open default addressbook...");
74                         free(datafile);
75                         datafile = tmp;
76                         load_database(datafile);
77                 } else
78                         free(tmp);
79         }
80
81         refresh_screen();
82 }
83
84 void
85 quit_abook()
86 {
87         if( options_get_int("autosave") )
88                 save_database();
89         else if( statusline_ask_boolean("Save database", TRUE) )
90                 save_database();
91
92         close_config();
93         close_database();
94
95         close_ui();
96         
97         exit(0);
98 }
99
100 int
101 main(int argc, char **argv)
102 {
103 #if defined(HAVE_SETLOCALE) && defined(HAVE_LOCALE_H)
104         setlocale(LC_ALL, "" );
105 #endif
106                 
107         parse_command_line(argc, argv);
108         
109         init_abook();
110
111         get_commands(); 
112         
113         quit_abook();
114
115         return 0;
116 }
117
118 static void
119 set_filenames()
120 {
121         struct stat s;
122
123         if( (stat(getenv("HOME"), &s)) == -1 || ! S_ISDIR(s.st_mode) ) {
124                 fprintf(stderr,"%s is not a valid HOME directory\n", getenv("HOME") );
125                 exit(1);
126         }
127
128         if (!datafile)
129                 datafile = strconcat(getenv("HOME"), "/" DATAFILE, NULL);
130
131         rcfile = strconcat(getenv("HOME"), "/" RCFILE, NULL);
132
133         atexit(free_filenames);
134 }
135
136 static void
137 free_filenames()
138 {
139         my_free(rcfile);
140         my_free(datafile);
141 }
142
143 static void
144 parse_command_line(int argc, char **argv)
145 {
146         int i;
147
148         for( i = 1; i < argc; i++ ) {
149                 if( !strcmp(argv[i], "--help") ) {
150                         show_usage();
151                         exit(1);
152                 } else if( !strcmp(argv[i], "--mutt-query") ) {
153                         mutt_query(argv[i + 1]);
154                 } else if( !strcmp(argv[i], "--datafile") ) {
155                         if (argc > i + 1 ) {
156                                 if (argv[i+1][0] != '/') {
157                                         char *cwd = my_getcwd();
158                                         datafile = strconcat(cwd, "/", argv[i+1], NULL);
159                                         free(cwd);
160                                 } else {
161                                         datafile = strdup(argv[i+1]);
162                                 }
163                                 i++;
164                         } else {
165                                 show_usage();
166                                 exit(1);
167                         }
168                 } else if( !strcmp(argv[i], "--convert") ) {
169                         if( argc < 5 || argc > 6 ) {
170                                 fprintf(stderr, "incorrect number of argumets to make conversion\n");
171                                 fprintf(stderr, "try %s --help\n", argv[0]);
172                                 exit(1);
173                         }
174                         if( argc > i + 4 )
175                                 convert(argv[i+1], argv[i+2],
176                                         argv[i+3], argv[i+4]);
177                         else
178                                 convert(argv[i+1], argv[i+2], argv[i+3], "-");
179                 } else if( !strcmp(argv[i], "--add-email") ) {
180                         add_email(0);
181                 } else if( !strcmp(argv[i], "--add-email-quiet") ) {
182                         add_email(1);
183                 } else {
184                         printf("option %s not recognized\n", argv[i]);
185                         printf("try %s --help\n", argv[0]);
186                         exit(1);
187                 }
188         }
189 }
190
191
192 static void
193 show_usage()
194 {
195         puts    (PACKAGE " v " VERSION "\n");
196         puts    ("      --help                          show usage");
197         puts    ("      --datafile      <filename>      use an alternative addressbook file");
198         puts    ("      --mutt-query    <string>        make a query for mutt");
199         puts    ("      --convert       <inputformat> <inputfile> "
200                 "<outputformat> <outputfile>");
201         puts    ("      --add-email                     "
202                         "read an e-mail message from stdin and\n"
203                 "                                       "
204                 "add the sender to the addressbook");
205         puts    ("      --add-email-quiet               "
206                 "same as --add-email but doesn't\n"
207                 "                                       confirm adding");
208         putchar('\n');
209         puts    ("available formats for --convert option:");
210         print_filters();
211 #ifdef DEBUG
212         puts    ("\nWarning: this version compiled with DEBUG flag ON");
213 #endif
214 }
215
216 extern list_item *database;
217
218 static void
219 muttq_print_item(FILE *file, int item)
220 {
221         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
222         int i;
223
224         split_emailstr(item, emails);
225         
226         for(i = 0; i < (options_get_int("mutt_return_all_emails") ?
227                         MAX_EMAILS : 1) ; i++)
228                 if( *emails[i] )
229                         fprintf(file, "%s\t%s\t%s\n", emails[i],
230                                 database[item][NAME],
231                                 database[item][NOTES] == NULL ? " " :
232                                         database[item][NOTES]
233                                 );
234 }
235
236 static void
237 mutt_query(char *str)
238 {
239         init_mutt_query();
240
241         if( str == NULL || !strcasecmp(str, "all") ) {
242                 struct db_enumerator e = init_db_enumerator(ENUM_ALL);
243                 printf("All items\n");
244                 db_enumerate_items(e)
245                         muttq_print_item(stdout, e.item);
246         } else {
247                 int search_fields[] = {NAME, EMAIL, NICK, -1};
248                 int i;
249                 if( (i = find_item(str, 0, search_fields)) < 0 ) {
250                         printf("Not found\n");
251                         quit_mutt_query(1);
252                 }
253                 putchar('\n');
254                 while(i >= 0) {
255                         muttq_print_item(stdout, i);
256                         i = find_item(str, i+1, search_fields);
257                 }
258         }
259
260         quit_mutt_query(0);
261 }
262
263 static void
264 init_mutt_query()
265 {
266         set_filenames();
267         init_options();
268         
269         if( load_database(datafile) ) {
270                 printf("Cannot open database\n");
271                 quit_mutt_query(1);
272                 exit(1);
273         }
274 }
275
276 static void
277 quit_mutt_query(int status)
278 {
279         close_database();
280         close_config();
281
282         exit(status);
283 }
284
285
286 static char *
287 make_mailstr(int item)
288 {
289         char email[MAX_EMAIL_LEN];
290         char *ret;
291         char *name = mkstr("\"%s\"", database[item][NAME]);
292
293         get_first_email(email, item);
294
295         ret = *database[item][EMAIL] ?
296                 mkstr("%s <%s>", name, email) :
297                 strdup(name);
298
299         free(name);
300         
301         return ret;
302 }
303
304 void
305 print_stderr(int item)
306 {
307         fprintf (stderr, "%c", '\n');
308
309         if( is_valid_item(item) )
310                 muttq_print_item(stderr, item);
311         else {
312                 struct db_enumerator e = init_db_enumerator(ENUM_SELECTED);
313                 db_enumerate_items(e) {
314                         muttq_print_item(stderr, e.item);
315                 }
316         }
317
318 }
319
320 void
321 launch_mutt(int item)
322 {
323         char *cmd = NULL, *mailstr = NULL;
324         char *mutt_command = options_get_str("mutt_command");
325
326         if(mutt_command == NULL || !*mutt_command)
327                 return;
328
329         if( is_valid_item(item) )
330                 mailstr = make_mailstr(item);
331         else {
332                 struct db_enumerator e = init_db_enumerator(ENUM_SELECTED);
333                 char *tmp = NULL;
334                 db_enumerate_items(e) {
335                         tmp = mailstr;
336                         mailstr = tmp ?
337                                 strconcat(tmp, ",", make_mailstr(e.item), NULL):
338                                 strconcat(make_mailstr(e.item), NULL);
339                         free(tmp);
340                 }
341         }
342
343         cmd = strconcat(mutt_command, " \'", mailstr,
344                                 "\'", NULL);
345         free(mailstr);
346 #ifdef DEBUG
347         fprintf(stderr, "cmd: %s\n", cmd);
348 #endif
349         system(cmd);    
350         free(cmd);
351         
352         /*
353          * we need to make sure that curses settings are correct
354          */
355         ui_init_curses();
356 }
357
358 void
359 launch_wwwbrowser(int item)
360 {
361         char *cmd = NULL;
362
363         if( !is_valid_item(item) )
364                 return;
365
366         if( database[item][URL] )
367                 cmd = mkstr("%s '%s'",
368                                 options_get_str("www_command"),
369                                 safe_str(database[item][URL]));
370         else
371                 return;
372
373         if ( cmd )
374                 system(cmd);
375
376         free(cmd);
377
378         /*
379          * we need to make sure that curses settings are correct
380          */
381         ui_init_curses();
382 }
383
384 void *
385 abook_malloc(size_t size)
386 {
387         void *ptr;
388
389         if ( (ptr = malloc(size)) == NULL ) {
390                 if( is_ui_initialized() )
391                         quit_abook();
392                 perror("malloc() failed");
393                 exit(1);
394         }
395
396         return ptr;
397 }
398
399 void *
400 abook_realloc(void *ptr, size_t size)
401 {
402         ptr = realloc(ptr, size);
403
404         if( size == 0 )
405                 return NULL;
406
407         if( ptr == NULL ) {
408                 if( is_ui_initialized() )
409                         quit_abook();
410                 perror("realloc() failed");
411                 exit(1);
412         }
413
414         return ptr;
415 }
416
417 FILE *
418 abook_fopen (const char *path, const char *mode)
419 {       
420         struct stat s;
421         
422         if( ! strchr(mode, 'r') )
423                 return fopen(path, mode);
424         
425         if ( (stat(path, &s)) == -1 )
426                 return NULL;
427         
428         return S_ISREG(s.st_mode) ? fopen(path, mode) : NULL;
429 }
430
431
432
433 static void
434 convert(char *srcformat, char *srcfile, char *dstformat, char *dstfile)
435 {
436         int ret=0;
437
438         if( !srcformat || !srcfile || !dstformat || !dstfile ) {
439                 fprintf(stderr, "too few argumets to make conversion\n");
440                 fprintf(stderr, "try --help\n");
441         }
442
443         strlower(srcformat);
444         strlower(dstformat);
445
446 #ifndef DEBUG
447         if( !strcmp(srcformat, dstformat) ) {
448                 printf( "input and output formats are the same\n"
449                         "exiting...\n");
450                 exit(1);
451         }
452 #endif
453
454         set_filenames();
455         init_options();
456
457         switch( import(srcformat, srcfile) ) {
458                 case -1:
459                         fprintf(stderr,
460                                 "input format %s not supported\n", srcformat);
461                         ret = 1;
462                 case 1:
463                         fprintf(stderr, "cannot read file %s\n", srcfile);
464                         ret = 1;
465         }
466
467         if(!ret)
468                 switch( export(dstformat, dstfile) ) {
469                         case -1:
470                                 fprintf(stderr,
471                                         "output format %s not supported\n",
472                                         dstformat);
473                                 ret = 1;
474                                 break;
475                         case 1:
476                                 fprintf(stderr,
477                                         "cannot write file %s\n", dstfile);
478                                 ret = 1;
479                                 break;
480                 }
481
482         close_database();
483         close_config();
484         exit(ret);
485 }
486
487 /*
488  * --add-email handling
489  */
490
491 static int add_email_count = 0;
492
493 static void
494 quit_add_email()
495 {
496         if(add_email_count > 0) {
497                 if(save_database() < 0) {
498                         fprintf(stderr, "cannot open %s\n", datafile);
499                         exit(1);
500                 }
501                 printf("%d item(s) added to %s\n", add_email_count, datafile);
502         } else {
503                 puts("Valid sender address not found");
504         }
505
506         exit(0);
507 }
508
509 static void
510 init_add_email()
511 {
512         set_filenames();
513         atexit(free_filenames);
514         init_options();
515         atexit(close_config);
516         
517         /*
518          * we don't actually care if loading fails or not
519          */
520         load_database(datafile);
521
522         atexit(close_database);
523
524         signal(SIGINT, quit_add_email);
525 }
526
527 static int
528 add_email_add_item(int quiet, char *name, char *email)
529 {
530         list_item item;
531
532         if(!quiet) {
533                 FILE *in = fopen("/dev/tty", "r");
534                 char c;
535                 if(!in) {
536                         fprintf(stderr, "cannot open /dev/tty\n"
537                                 "you may want to use --add-email-quiet\n");
538                         exit(1);
539                 }
540                 printf("Add ``%s <%s>'' to %s ? (y/n)\n",
541                                 name,
542                                 email,
543                                 datafile
544                 );
545                 do {
546                         c = fgetc(in);
547                         if(c == 'n' || c == 'N') {
548                                 fclose(in);
549                                 return 0;
550                         }
551                 } while(c != 'y' && c != 'Y');
552                 fclose(in);
553         }
554
555         memset(item, 0, sizeof(item));
556         item[NAME] = strdup(name);
557         item[EMAIL] = strdup(email);
558         add_item2database(item);
559
560         return 1;
561 }
562
563 static void
564 add_email(int quiet)
565 {
566         char *line;
567         char *name = NULL, *email = NULL;
568         
569         init_add_email();
570
571         do {
572                 line = getaline(stdin);
573                 if(line && !strncasecmp("From:", line, 5) ) {
574                         getname(line, &name, &email);
575                         my_free(line);
576                         add_email_count += add_email_add_item(quiet,
577                                         name, email);
578                         my_free(name);
579                         my_free(email);
580                 }
581                 my_free(line);
582         } while( !feof(stdin) );
583
584         quit_add_email();
585 }
586
587 /*
588  * end of --add-email handling
589  */