|
|
1.1 ! root 1: /* sendmail-like interface to /bin/mail for system V, ! 2: Copyright (C) 1985 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU Emacs General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU Emacs, but only under the conditions described in the ! 15: GNU Emacs General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU Emacs so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: #define NO_SHORTNAMES ! 23: #include "../src/config.h" ! 24: ! 25: #if defined (BSD) && !defined (BSD4_1) ! 26: /* This program isnot used in BSD, so just avoid loader complaints. */ ! 27: main () ! 28: { ! 29: } ! 30: #else /* not BSD 4.2 (or newer) */ ! 31: /* This conditional contains all the rest of the file. */ ! 32: ! 33: /* These are defined in config in some versions. */ ! 34: ! 35: #ifdef static ! 36: #undef static ! 37: #endif ! 38: ! 39: #ifdef read ! 40: #undef read ! 41: #undef write ! 42: #undef open ! 43: #undef close ! 44: #endif ! 45: ! 46: #include <stdio.h> ! 47: #include <string.h> ! 48: #include <ctype.h> ! 49: #include <time.h> ! 50: #include <pwd.h> ! 51: ! 52: /* Type definitions */ ! 53: ! 54: #define boolean int ! 55: #define true 1 ! 56: #define false 0 ! 57: ! 58: /* Various lists */ ! 59: ! 60: struct line_record ! 61: { ! 62: char *string; ! 63: struct line_record *continuation; ! 64: }; ! 65: typedef struct line_record *line_list; ! 66: ! 67: struct header_record ! 68: { ! 69: line_list text; ! 70: struct header_record *next; ! 71: struct header_record *previous; ! 72: }; ! 73: typedef struct header_record *header; ! 74: ! 75: struct stream_record ! 76: { ! 77: FILE *handle; ! 78: int (*action)(); ! 79: struct stream_record *rest_streams; ! 80: }; ! 81: typedef struct stream_record *stream_list; ! 82: ! 83: /* A `struct linebuffer' is a structure which holds a line of text. ! 84: * `readline' reads a line from a stream into a linebuffer ! 85: * and works regardless of the length of the line. ! 86: */ ! 87: ! 88: struct linebuffer ! 89: { ! 90: long size; ! 91: char *buffer; ! 92: }; ! 93: ! 94: struct linebuffer lb; ! 95: ! 96: #define new_list() \ ! 97: ((line_list) xmalloc (sizeof (struct line_record))) ! 98: #define new_header() \ ! 99: ((header) xmalloc (sizeof (struct header_record))) ! 100: #define new_stream() \ ! 101: ((stream_list) xmalloc (sizeof (struct stream_record))) ! 102: #define alloc_string(nchars) \ ! 103: ((char *) xmalloc ((nchars) + 1)) ! 104: ! 105: /* Global declarations */ ! 106: ! 107: #define BUFLEN 1024 ! 108: #define KEYWORD_SIZE 256 ! 109: #define FROM_PREFIX "From" ! 110: #define MY_NAME "fakemail" ! 111: #define NIL ((line_list) NULL) ! 112: #define INITIAL_LINE_SIZE 200 ! 113: ! 114: #ifndef MAIL_PROGRAM_NAME ! 115: #define MAIL_PROGRAM_NAME "/bin/mail" ! 116: #endif ! 117: ! 118: static char *my_name; ! 119: static char *the_date; ! 120: static char *the_user; ! 121: static line_list file_preface; ! 122: static stream_list the_streams; ! 123: static boolean no_problems = true; ! 124: ! 125: extern FILE *popen (); ! 126: extern int fclose (), pclose (); ! 127: extern char *malloc (), *realloc (); ! 128: ! 129: #ifdef CURRENT_USER ! 130: extern struct passwd *getpwuid (); ! 131: extern unsigned short geteuid (); ! 132: static struct passwd *my_entry; ! 133: #define cuserid(s) \ ! 134: (my_entry = getpwuid (((int) geteuid ())), \ ! 135: my_entry->pw_name) ! 136: #endif ! 137: ! 138: /* Utilities */ ! 139: ! 140: /* Print error message. `s1' is printf control string, `s2' is arg for it. */ ! 141: ! 142: static void ! 143: error (s1, s2) ! 144: char *s1, *s2; ! 145: { ! 146: printf ("%s: ", my_name); ! 147: printf (s1, s2); ! 148: printf ("\n"); ! 149: no_problems = false; ! 150: } ! 151: ! 152: /* Print error message and exit. */ ! 153: ! 154: static void ! 155: fatal (s1, s2) ! 156: char *s1, *s2; ! 157: { ! 158: error (s1, s2); ! 159: exit (1); ! 160: } ! 161: ! 162: /* Like malloc but get fatal error if memory is exhausted. */ ! 163: ! 164: static char * ! 165: xmalloc (size) ! 166: int size; ! 167: { ! 168: char *result = malloc (((unsigned) size)); ! 169: if (result == ((char *) NULL)) ! 170: fatal ("virtual memory exhausted", 0); ! 171: return result; ! 172: } ! 173: ! 174: static char * ! 175: xrealloc (ptr, size) ! 176: char *ptr; ! 177: int size; ! 178: { ! 179: char *result = realloc (ptr, ((unsigned) size)); ! 180: if (result == ((char *) NULL)) ! 181: fatal ("virtual memory exhausted"); ! 182: return result; ! 183: } ! 184: ! 185: /* Initialize a linebuffer for use */ ! 186: ! 187: void ! 188: init_linebuffer (linebuffer) ! 189: struct linebuffer *linebuffer; ! 190: { ! 191: linebuffer->size = INITIAL_LINE_SIZE; ! 192: linebuffer->buffer = ((char *) xmalloc (INITIAL_LINE_SIZE)); ! 193: } ! 194: ! 195: /* Read a line of text from `stream' into `linebuffer'. ! 196: * Return the length of the line. ! 197: */ ! 198: ! 199: long ! 200: readline (linebuffer, stream) ! 201: struct linebuffer *linebuffer; ! 202: FILE *stream; ! 203: { ! 204: char *buffer = linebuffer->buffer; ! 205: char *p = linebuffer->buffer; ! 206: char *end = p + linebuffer->size; ! 207: ! 208: while (true) ! 209: { ! 210: int c = getc (stream); ! 211: if (p == end) ! 212: { ! 213: linebuffer->size *= 2; ! 214: buffer = ((char *) xrealloc (buffer, linebuffer->size)); ! 215: p += buffer - linebuffer->buffer; ! 216: end += buffer - linebuffer->buffer; ! 217: linebuffer->buffer = buffer; ! 218: } ! 219: if (c < 0 || c == '\n') ! 220: { ! 221: *p = 0; ! 222: break; ! 223: } ! 224: *p++ = c; ! 225: } ! 226: ! 227: return p - buffer; ! 228: } ! 229: ! 230: char * ! 231: get_keyword (field, rest) ! 232: register char *field; ! 233: char **rest; ! 234: { ! 235: static char keyword[KEYWORD_SIZE]; ! 236: register char *ptr; ! 237: register char c; ! 238: ! 239: ptr = &keyword[0]; ! 240: c = *field++; ! 241: if ((isspace (c)) || (c == ':')) ! 242: return ((char *) NULL); ! 243: *ptr++ = ((islower (c)) ? (toupper (c)) : c); ! 244: while (((c = *field++) != ':') && (!(isspace (c)))) ! 245: *ptr++ = ((islower (c)) ? (toupper (c)) : c); ! 246: *ptr++ = '\0'; ! 247: while (isspace (c)) c = *field++; ! 248: if (c != ':') return ((char *) NULL); ! 249: *rest = field; ! 250: return &keyword[0]; ! 251: } ! 252: ! 253: boolean ! 254: has_keyword (field) ! 255: char *field; ! 256: { ! 257: char *ignored; ! 258: return (get_keyword (field, &ignored) != ((char *) NULL)); ! 259: } ! 260: ! 261: char * ! 262: add_field (the_list, field, where) ! 263: line_list the_list; ! 264: register char *field, *where; ! 265: { ! 266: register char c; ! 267: while (true) ! 268: { ! 269: *where++ = ' '; ! 270: while ((c = *field++) != '\0') ! 271: *where++ = ((c == ',') ? ' ' : c); ! 272: if (the_list == NIL) break; ! 273: field = the_list->string; ! 274: the_list = the_list->continuation; ! 275: } ! 276: return where; ! 277: } ! 278: ! 279: line_list ! 280: make_file_preface () ! 281: { ! 282: char *the_string, *temp; ! 283: long idiotic_interface; ! 284: long prefix_length; ! 285: long user_length; ! 286: long date_length; ! 287: line_list result; ! 288: ! 289: prefix_length = strlen (FROM_PREFIX); ! 290: time (&idiotic_interface); ! 291: the_date = ctime (&idiotic_interface); ! 292: /* the_date has an unwanted newline at the end */ ! 293: date_length = strlen (the_date) - 1; ! 294: the_date[date_length] = '\0'; ! 295: temp = cuserid ((char *) NULL); ! 296: user_length = strlen (temp); ! 297: the_user = alloc_string (user_length + 1); ! 298: strcpy (the_user, temp); ! 299: the_string = alloc_string (3 + prefix_length + ! 300: user_length + ! 301: date_length); ! 302: temp = the_string; ! 303: strcpy (temp, FROM_PREFIX); ! 304: temp = &temp[prefix_length]; ! 305: *temp++ = ' '; ! 306: strcpy (temp, the_user); ! 307: temp = &temp[user_length]; ! 308: *temp++ = ' '; ! 309: strcpy (temp, the_date); ! 310: result = new_list (); ! 311: result->string = the_string; ! 312: result->continuation = ((line_list) NULL); ! 313: return result; ! 314: } ! 315: ! 316: void ! 317: write_line_list (the_list, the_stream) ! 318: register line_list the_list; ! 319: FILE *the_stream; ! 320: { ! 321: for ( ; ! 322: the_list != ((line_list) NULL) ; ! 323: the_list = the_list->continuation) ! 324: { ! 325: fputs (the_list->string, the_stream); ! 326: putc ('\n', the_stream); ! 327: } ! 328: return; ! 329: } ! 330: ! 331: int ! 332: close_the_streams () ! 333: { ! 334: register stream_list rem; ! 335: for (rem = the_streams; ! 336: rem != ((stream_list) NULL); ! 337: rem = rem->rest_streams) ! 338: no_problems = (no_problems && ! 339: ((*rem->action) (rem->handle) == 0)); ! 340: the_streams = ((stream_list) NULL); ! 341: return (no_problems ? 0 : 1); ! 342: } ! 343: ! 344: void ! 345: add_a_stream (the_stream, closing_action) ! 346: FILE *the_stream; ! 347: int (*closing_action)(); ! 348: { ! 349: stream_list old = the_streams; ! 350: the_streams = new_stream (); ! 351: the_streams->handle = the_stream; ! 352: the_streams->action = closing_action; ! 353: the_streams->rest_streams = old; ! 354: return; ! 355: } ! 356: ! 357: int ! 358: my_fclose (the_file) ! 359: FILE *the_file; ! 360: { ! 361: putc ('\n', the_file); ! 362: fflush (the_file); ! 363: return fclose (the_file); ! 364: } ! 365: ! 366: boolean ! 367: open_a_file (name) ! 368: char *name; ! 369: { ! 370: FILE *the_stream = fopen (name, "a"); ! 371: if (the_stream != ((FILE *) NULL)) ! 372: { ! 373: add_a_stream (the_stream, my_fclose); ! 374: if (the_user == ((char *) NULL)) ! 375: file_preface = make_file_preface (); ! 376: write_line_list (file_preface, the_stream); ! 377: return true; ! 378: } ! 379: return false; ! 380: } ! 381: ! 382: void ! 383: put_string (s) ! 384: char *s; ! 385: { ! 386: register stream_list rem; ! 387: for (rem = the_streams; ! 388: rem != ((stream_list) NULL); ! 389: rem = rem->rest_streams) ! 390: fputs (s, rem->handle); ! 391: return; ! 392: } ! 393: ! 394: void ! 395: put_line (s) ! 396: char *s; ! 397: { ! 398: register stream_list rem; ! 399: for (rem = the_streams; ! 400: rem != ((stream_list) NULL); ! 401: rem = rem->rest_streams) ! 402: { ! 403: fputs (s, rem->handle); ! 404: putc ('\n', rem->handle); ! 405: } ! 406: return; ! 407: } ! 408: ! 409: #define mail_error error ! 410: ! 411: void ! 412: setup_files (the_list, field) ! 413: register line_list the_list; ! 414: register char *field; ! 415: { ! 416: register char *start; ! 417: register char c; ! 418: while (true) ! 419: { ! 420: while (((c = *field) != '\0') && ! 421: ((c == ' ') || ! 422: (c == '\t') || ! 423: (c == ','))) ! 424: field += 1; ! 425: if (c != '\0') ! 426: { ! 427: start = field; ! 428: while (((c = *field) != '\0') && ! 429: (c != ' ') && ! 430: (c != '\t') && ! 431: (c != ',')) ! 432: field += 1; ! 433: *field = '\0'; ! 434: if (!open_a_file (start)) ! 435: mail_error ("Could not open file %s", start); ! 436: *field = c; ! 437: if (c != '\0') continue; ! 438: } ! 439: if (the_list == ((line_list) NULL)) return; ! 440: field = the_list->string; ! 441: the_list = the_list->continuation; ! 442: } ! 443: } ! 444: ! 445: int ! 446: args_size (the_header) ! 447: header the_header; ! 448: { ! 449: register header old = the_header; ! 450: register line_list rem; ! 451: register int size = 0; ! 452: do ! 453: { ! 454: char *field; ! 455: register char *keyword = get_keyword (the_header->text->string, &field); ! 456: if ((strcmp (keyword, "TO") == 0) || ! 457: (strcmp (keyword, "CC") == 0) || ! 458: (strcmp (keyword, "BCC") == 0)) ! 459: { ! 460: size += 1 + strlen (field); ! 461: for (rem = the_header->text->continuation; ! 462: rem != NIL; ! 463: rem = rem->continuation) ! 464: size += 1 + strlen (rem->string); ! 465: } ! 466: the_header = the_header->next; ! 467: } while (the_header != old); ! 468: return size; ! 469: } ! 470: ! 471: parse_header (the_header, where) ! 472: header the_header; ! 473: register char *where; ! 474: { ! 475: register header old = the_header; ! 476: do ! 477: { ! 478: char *field; ! 479: register char *keyword = get_keyword (the_header->text->string, &field); ! 480: if (strcmp (keyword, "TO") == 0) ! 481: where = add_field (the_header->text->continuation, field, where); ! 482: else if (strcmp (keyword, "CC") == 0) ! 483: where = add_field (the_header->text->continuation, field, where); ! 484: else if (strcmp (keyword, "BCC") == 0) ! 485: { ! 486: where = add_field (the_header->text->continuation, field, where); ! 487: the_header->previous->next = the_header->next; ! 488: the_header->next->previous = the_header->previous; ! 489: } ! 490: else if (strcmp (keyword, "FCC") == 0) ! 491: setup_files (the_header->text->continuation, field); ! 492: the_header = the_header->next; ! 493: } while (the_header != old); ! 494: *where = '\0'; ! 495: return; ! 496: } ! 497: ! 498: header ! 499: read_header () ! 500: { ! 501: register header the_header = ((header) NULL); ! 502: register line_list *next_line = ((line_list *) NULL); ! 503: ! 504: init_linebuffer (&lb); ! 505: ! 506: do ! 507: { ! 508: long length; ! 509: register char *line; ! 510: ! 511: readline (&lb, stdin); ! 512: line = lb.buffer; ! 513: length = strlen (line); ! 514: if (length == 0) break; ! 515: ! 516: if (has_keyword (line)) ! 517: { ! 518: register header old = the_header; ! 519: the_header = new_header (); ! 520: if (old == ((header) NULL)) ! 521: { ! 522: the_header->next = the_header; ! 523: the_header->previous = the_header; ! 524: } ! 525: else ! 526: { ! 527: the_header->previous = old; ! 528: the_header->next = old->next; ! 529: old->next = the_header; ! 530: } ! 531: next_line = &(the_header->text); ! 532: } ! 533: ! 534: if (next_line == ((line_list *) NULL)) ! 535: { ! 536: /* Not a valid header */ ! 537: exit (1); ! 538: } ! 539: *next_line = new_list (); ! 540: (*next_line)->string = alloc_string (length); ! 541: strcpy (((*next_line)->string), line); ! 542: next_line = &((*next_line)->continuation); ! 543: *next_line = NIL; ! 544: ! 545: } while (true); ! 546: ! 547: return the_header->next; ! 548: } ! 549: ! 550: void ! 551: write_header (the_header) ! 552: header the_header; ! 553: { ! 554: register header old = the_header; ! 555: do ! 556: { ! 557: register line_list the_list; ! 558: for (the_list = the_header->text; ! 559: the_list != NIL; ! 560: the_list = the_list->continuation) ! 561: put_line (the_list->string); ! 562: the_header = the_header->next; ! 563: } while (the_header != old); ! 564: put_line (""); ! 565: return; ! 566: } ! 567: ! 568: void ! 569: main (argc, argv) ! 570: int argc; ! 571: char **argv; ! 572: { ! 573: char *command_line; ! 574: header the_header; ! 575: long name_length = strlen (MAIL_PROGRAM_NAME); ! 576: char buf[BUFLEN + 1]; ! 577: register int size; ! 578: FILE *the_pipe; ! 579: ! 580: my_name = MY_NAME; ! 581: the_streams = ((stream_list) NULL); ! 582: the_date = ((char *) NULL); ! 583: the_user = ((char *) NULL); ! 584: ! 585: the_header = read_header (); ! 586: command_line = alloc_string (name_length + args_size (the_header)); ! 587: strcpy (command_line, MAIL_PROGRAM_NAME); ! 588: parse_header (the_header, &command_line[name_length]); ! 589: ! 590: the_pipe = popen (command_line, "w"); ! 591: if (the_pipe == ((FILE *) NULL)) ! 592: fatal ("cannot open pipe to real mailer"); ! 593: ! 594: add_a_stream (the_pipe, pclose); ! 595: ! 596: write_header (the_header); ! 597: ! 598: /* Dump the message itself */ ! 599: ! 600: while (!feof (stdin)) ! 601: { ! 602: size = fread (buf, 1, BUFLEN, stdin); ! 603: buf[size] = '\0'; ! 604: put_string (buf); ! 605: } ! 606: ! 607: exit (close_the_streams ()); ! 608: } ! 609: ! 610: #endif /* not BSD 4.2 (or newer) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.