comparison src/masqmail.c @ 249:f9da5a7caeda

refactored the cmdline argument processing I replaced the nested switch statements with one single large else-if construct. Instead of char comparision now str(n)cmp(3) is used. Although this is slower it is much more readable and covers corner-cases which were uncovered before (e.g. -bdxxx). As always: Readability and simplicity matter, not performance.
author markus schnalke <meillo@marmaro.de>
date Thu, 04 Nov 2010 11:02:42 -0300
parents 018cfd163f5c
children a41c013c8458
comparison
equal deleted inserted replaced
248:018cfd163f5c 249:f9da5a7caeda
89 } 89 }
90 return FALSE; 90 return FALSE;
91 } 91 }
92 #endif 92 #endif
93 93
94 /*
95 argv: the original argv
96 argp: number of arg (may get modified!)
97 cp: pointing to the char after the option
98 e.g. `-d 6' `-d6'
99 ^ ^
100 */
94 gchar* 101 gchar*
95 get_optarg(char *argv[], gint argc, gint * argp, gint * pos) 102 get_optarg(char* argv[], gint* argp, char* cp)
96 { 103 {
97 if (argv[*argp][*pos]) 104 if (*cp) {
98 return &(argv[*argp][*pos]); 105 /* this kind: -xval */
99 else { 106 return cp;
100 if (*argp + 1 < argc) { 107 }
101 if (argv[(*argp) + 1][0] != '-') { 108 cp = argv[*argp+1];
102 (*argp)++; 109 if (cp && (*cp != '-')) {
103 *pos = 0; 110 /* this kind: -x val */
104 return &(argv[*argp][*pos]); 111 (*argp)++;
105 } 112 return cp;
106 }
107 } 113 }
108 return NULL; 114 return NULL;
109 } 115 }
110 116
111 gchar* 117 gchar*
286 int 292 int
287 main(int argc, char *argv[]) 293 main(int argc, char *argv[])
288 { 294 {
289 /* cmd line flags */ 295 /* cmd line flags */
290 gchar *conf_file = CONF_FILE; 296 gchar *conf_file = CONF_FILE;
291 gint arg = 1; 297 char* opt;
298 gint arg;
292 299
293 gboolean do_listen = FALSE; 300 gboolean do_listen = FALSE;
294 gboolean do_runq = FALSE; 301 gboolean do_runq = FALSE;
295 gboolean do_runq_online = FALSE; 302 gboolean do_runq_online = FALSE;
296 303
334 } else if (strcmp(progname, "smtpd") == 0 || strcmp(progname, "in.smtpd") == 0) { 341 } else if (strcmp(progname, "smtpd") == 0 || strcmp(progname, "in.smtpd") == 0) {
335 mta_mode = MODE_SMTP; 342 mta_mode = MODE_SMTP;
336 } 343 }
337 344
338 /* parse cmd line */ 345 /* parse cmd line */
339 while (arg < argc) { 346 for (arg=1; arg<argc && argv[arg][0]=='-'; arg++) {
340 gint pos = 0; 347 opt = argv[arg] + 1;
341 if ((argv[arg][pos] == '-') && (argv[arg][pos + 1] != '-')) { 348
342 pos++; 349 if (strcmp(opt, "-") == 0) {
343 switch (argv[arg][pos++]) { 350 /* everything after `--' are address arguments */
344 case 'b': 351 arg++;
345 switch (argv[arg][pos++]) { 352 break;
346 case 'd': 353
347 do_listen = TRUE; 354 } else if (strcmp(opt, "bd") == 0) {
348 mta_mode = MODE_DAEMON; 355 do_listen = TRUE;
349 break; 356 mta_mode = MODE_DAEMON;
350 case 'i': 357
351 /* ignored */ 358 } else if (strcmp(opt, "bi") == 0) {
352 mta_mode = MODE_BI; 359 /* ignored */
353 break; 360 mta_mode = MODE_BI;
354 case 's': 361
355 mta_mode = MODE_SMTP; 362 } else if (strcmp(opt, "bs") == 0) {
356 break; 363 mta_mode = MODE_SMTP;
357 case 'p': 364
358 mta_mode = MODE_LIST; 365 } else if (strcmp(opt, "bp") == 0) {
359 break; 366 mta_mode = MODE_LIST;
360 case 'V': 367
361 mta_mode = MODE_VERSION; 368 } else if (strcmp(opt, "bV") == 0) {
362 break; 369 mta_mode = MODE_VERSION;
363 default: 370
364 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 371 } else if (strncmp(opt, "B", 1) == 0) {
365 exit(EXIT_FAILURE); 372 /* we ignore this and throw the argument away */
366 } 373 get_optarg(argv, &arg, opt+1);
367 break; 374
368 case 'B': 375 } else if (strncmp(opt, "C", 1) == 0) {
369 /* we ignore this and throw the argument away */ 376 if (!(conf_file = get_optarg(argv, &arg, opt+1))) {
370 get_optarg(argv, argc, &arg, &pos); 377 fprintf(stderr, "-C requires a filename as argument.\n");
371 break;
372 case 'C':
373 if (!(conf_file = get_optarg(argv, argc, &arg, &pos))) {
374 fprintf(stderr, "-C requires a filename as argument.\n");
375 exit(EXIT_FAILURE);
376 }
377 break;
378 case 'F':
379 {
380 full_sender_name = get_optarg(argv, argc, &arg, &pos);
381 if (!full_sender_name) {
382 fprintf(stderr, "-F requires a name as an argument\n");
383 exit(EXIT_FAILURE);
384 }
385 }
386 break;
387 case 'd':
388 if (getuid() == 0) {
389 char *lvl = get_optarg(argv, argc, &arg, &pos);
390 if (lvl)
391 debug_level = atoi(lvl);
392 else {
393 fprintf(stderr, "-d requires a number as an argument.\n");
394 exit(EXIT_FAILURE);
395 }
396 } else {
397 fprintf(stderr, "only root may set the debug level.\n");
398 exit(EXIT_FAILURE);
399 }
400 break;
401 case 'f':
402 /* set return path */
403 {
404 gchar *address;
405 address = get_optarg(argv, argc, &arg, &pos);
406 if (address) {
407 f_address = g_strdup(address);
408 } else {
409 fprintf(stderr, "-f requires an address as an argument\n");
410 exit(EXIT_FAILURE);
411 }
412 }
413 break;
414 case 'i':
415 if (argv[arg][pos] == 0) {
416 opt_i = TRUE;
417 exit_failure = FALSE; /* may override -oem */
418 } else {
419 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
420 exit(EXIT_FAILURE);
421 }
422 break;
423 case 'M':
424 {
425 mta_mode = MODE_MCMD;
426 M_cmd = g_strdup(&(argv[arg][pos]));
427 }
428 break;
429 case 'm':
430 /* ignore -m (me too) switch (see man page) */
431 break;
432 case 'o':
433 char* oarg = argv[arg][pos+1];
434 if (strcmp(oarg, "oem") == 0) {
435 if (!opt_i) {
436 /* FIXME: this check needs to be done after
437 option processing as -oi may come later */
438 exit_failure = TRUE;
439 }
440 } else if (strcmp(oarg, "odb") == 0) {
441 /* ignore ``deliver in background'' switch */
442 } else if (strcmp(oarg, "odq") == 0) {
443 do_queue = TRUE;
444 } else if (strcmp(oarg, "oi") == 0) {
445 exit_failure = FALSE; /* may override -oem */
446 } else if (strcmp(oarg, "om") == 0) {
447 /* ignore ``me too'' switch */
448 } else {
449 fprintf(stderr, "ignoring unrecognized option %s\n",
450 argv[arg]);
451 }
452 break;
453
454 case 'q':
455 {
456 gchar *optarg;
457
458 do_runq = TRUE;
459 mta_mode = MODE_RUNQUEUE;
460 if (argv[arg][pos] == 'o') {
461 pos++;
462 do_runq = FALSE;
463 do_runq_online = TRUE;
464 /* can be NULL, then we use online detection method */
465 route_name = get_optarg(argv, argc, &arg, &pos);
466 } else
467 if ((optarg = get_optarg(argv, argc, &arg, &pos))) {
468 mta_mode = MODE_DAEMON;
469 queue_interval = time_interval(optarg, &pos);
470 }
471 }
472 break;
473 case 't':
474 if (argv[arg][pos] == '\0') {
475 opt_t = TRUE;
476 } else {
477 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
478 exit(EXIT_FAILURE);
479 }
480 break;
481 case 'v':
482 do_verbose = TRUE;
483 break;
484 default:
485 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
486 exit(EXIT_FAILURE); 378 exit(EXIT_FAILURE);
487 } 379 }
380
381 } else if (strncmp(opt, "d", 1) == 0) {
382 if (getuid() != 0) {
383 fprintf(stderr, "only root may set the debug level.\n");
384 exit(EXIT_FAILURE);
385 }
386 char *lvl = get_optarg(argv, &arg, opt+1);
387 if (!lvl) {
388 fprintf(stderr, "-d requires a number argument.\n");
389 exit(EXIT_FAILURE);
390 }
391 debug_level = atoi(lvl);
392
393 } else if (strncmp(opt, "f", 1) == 0) {
394 /* set return path */
395 gchar *address = get_optarg(argv, &arg, opt+1);
396 if (!address) {
397 fprintf(stderr, "-f requires an address argument\n");
398 exit(EXIT_FAILURE);
399 }
400 f_address = g_strdup(address);
401
402 } else if (strncmp(opt, "F", 1) == 0) {
403 full_sender_name = get_optarg(argv, &arg, opt+1);
404 if (!full_sender_name) {
405 fprintf(stderr, "-F requires a name argument\n");
406 exit(EXIT_FAILURE);
407 }
408
409 } else if (strcmp(opt, "i") == 0) {
410 opt_i = TRUE;
411 exit_failure = FALSE; /* may override -oem */
412
413 } else if (strcmp(opt, "m") == 0) {
414 /* ignore -m (me too) switch (see man page) */
415
416 } else if (strcmp(opt, "Mrm") == 0) {
417 mta_mode = MODE_MCMD;
418 M_cmd = "rm";
419
420 } else if (strcmp(opt, "odq") == 0) {
421 do_queue = TRUE;
422
423 } else if (strcmp(opt, "oem") == 0) {
424 if (!opt_i) {
425 /* TODO: Why is this related to -i in any way? */
426 exit_failure = TRUE;
427 }
428
429 } else if (strcmp(opt, "oi") == 0) {
430 exit_failure = FALSE; /* may override -oem */
431
432 } else if (strncmp(opt, "o", 1) == 0) {
433 /* ignore all other -oXXX options */
434
435 } else if (strncmp(opt, "qo", 2) == 0) {
436 mta_mode = MODE_RUNQUEUE;
437 do_runq = FALSE;
438 do_runq_online = TRUE;
439 /* can be NULL, then we use online detection method */
440 route_name = get_optarg(argv, &arg, opt+2);
441
442 } else if (strncmp(opt, "q", 1) == 0) {
443 /* must be after the `qo' check */
444 gchar *optarg;
445 int dummy;
446
447 do_runq = TRUE;
448 mta_mode = MODE_RUNQUEUE;
449 if ((optarg = get_optarg(argv, &arg, opt+1))) {
450 mta_mode = MODE_DAEMON;
451 queue_interval = time_interval(optarg, &dummy);
452 }
453
454 } else if (strcmp(opt, "t") == 0) {
455 opt_t = TRUE;
456
457 } else if (strcmp(opt, "v") == 0) {
458 do_verbose = TRUE;
459
488 } else { 460 } else {
489 if (argv[arg][pos + 1] == '-') { 461 fprintf(stderr, "unrecognized option `-%s'\n", opt);
490 if (argv[arg][pos + 2] != '\0') { 462 exit(EXIT_FAILURE);
491 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 463 }
492 exit(EXIT_FAILURE);
493 }
494 arg++;
495 }
496 break;
497 }
498 arg++;
499 } 464 }
500 465
501 if (mta_mode == MODE_VERSION) { 466 if (mta_mode == MODE_VERSION) {
502 gchar *with_resolver = ""; 467 gchar *with_resolver = "";
503 gchar *with_auth = ""; 468 gchar *with_auth = "";