Mercurial > masqmail
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 = ""; |