home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3413 < prev    next >
Encoding:
Internet Message Format  |  1991-05-25  |  41.7 KB

  1. From: mj@dfv.rwth-aachen.de (Martin Junius)
  2. Newsgroups: alt.sources
  3. Subject: FIDOGATE 03/06
  4. Message-ID: <mj.675078404@suntex>
  5. Date: 24 May 91 09:46:44 GMT
  6.  
  7. ---- Cut Here and feed the following to sh ----
  8. #!/bin/sh
  9. # This is part 03 of a multipart archive
  10. # ============= rfmail.c ==============
  11. if test -f 'rfmail.c' -a X"$1" != X"-c"; then
  12.     echo 'x - skipping rfmail.c (File already exists)'
  13. else
  14. echo 'x - extracting rfmail.c (Text)'
  15. sed 's/^X//' << 'SHAR_EOF' > 'rfmail.c' &&
  16. /*:ts=4*/
  17. /*****************************************************************************
  18. X * FIDOGATE --- Gateway software UNIX <-> FIDO
  19. X *
  20. X * $Id: rfmail.c,v 2.24 91/05/22 20:13:26 mj Exp $
  21. X *
  22. X * Read mail or news from standard input and put it into spool-directory.
  23. X * rfmail is called by the included version of rmail (mail receiver)
  24. X * and by relaynews from the CNews software.
  25. X *
  26. X * $Log:   rfmail.c,v $
  27. X * Revision 2.24  91/05/22  20:13:26  mj
  28. X * Removed additional '\n' in log file entry.
  29. X * 
  30. X * Revision 2.23  91/05/21  09:41:23  mj
  31. X * rfmail now split messages larger than MAXMSGSIZE into several parts.
  32. X * 
  33. X * Revision 2.22  91/05/21  08:48:52  mj
  34. X * Moved log entry for NetMail to here.
  35. X * 
  36. X * Revision 2.21  91/05/19  17:23:16  mj
  37. X * Some changes. (what?)
  38. X * 
  39. X * Revision 2.20  91/05/07  23:58:59  mj
  40. X * Changed usage of function parse_address() due to new return type.
  41. X * 
  42. X * Revision 2.19  91/03/29  18:13:07  mj
  43. X * No more chmod(600) for news articles.
  44. X * 
  45. X * Revision 2.18  91/01/05  13:07:34  mj
  46. X * Improved generation of FIDO `^AREPLY', use `References:' or `In-Reply-To:'
  47. X * even if no `Message-ID:' present. Fixed function get_header().
  48. X * 
  49. X * Revision 2.17  90/12/09  18:36:48  mj
  50. X * Support for new `X' header in intermediate file taken from RFC `X-Flags:'.
  51. X * Crash mail is now possible via `X-Flags: C'.
  52. X * 
  53. X * Revision 2.16  90/12/09  17:35:13  mj
  54. X * Fixed a small bug in subject handling.
  55. X * 
  56. X * Revision 2.15  90/12/02  21:22:25  mj
  57. X * Changed program header to mention both authors of the original
  58. X * software posted to alt.sources.
  59. X * 
  60. X * Revision 2.14  90/12/01  17:49:49  mj
  61. X * Major new feature: rfmail is now able to handle news articles posted
  62. X * to several newsgroup. For each newsgroup in the Newsgroups header a
  63. X * seperate spool file for the corresponding FIDO EchoMail area is created.
  64. X * 
  65. X * Revision 2.13  90/11/23  21:52:14  mj
  66. X * Changed date output to be compliant with FTS-0001: `DD MON YY  HH:MM:SS',
  67. X * so QMail hopefully won't mess around with rfmail's dates any more.
  68. X * 
  69. X * Revision 2.12  90/11/23  20:42:36  mj
  70. X * Output of ^AREPLY no longer depends on real versus fake net address.
  71. X * 
  72. X * Revision 2.11  90/11/20  21:09:35  mj
  73. X * Added support for ^AINTL kludge.
  74. X * 
  75. X * Revision 2.10  90/11/05  20:50:55  mj
  76. X * Changed my signature in all program headers.
  77. X * 
  78. X * Revision 2.9  90/11/01  14:53:43  mj
  79. X * Take last message id from RFC822 Message-ID/References header.
  80. X * 
  81. X * Revision 2.8  90/11/01  14:35:05  mj
  82. X * Enabled generation of ^AREPLY kludge.
  83. X * 
  84. X * Revision 2.7  90/10/29  21:20:15  mj
  85. X * Enabled generation of ^AMSGID kludge.
  86. X * 
  87. X * Revision 2.6  90/09/16  17:36:25  mj
  88. X * Some changes. (what?)
  89. X * 
  90. X * Revision 2.5  90/09/15  14:22:54  mj
  91. X * Bug in newsgroup<->area conversion removed.
  92. X * 
  93. X * Revision 2.4  90/09/13  21:58:38  mj
  94. X * Two major changes:
  95. X * Improved handling of user names in addresses and real names.
  96. X * Normally we use real name from header lines, but in case of
  97. X * special addressing via '%', e.g. "... % MAUS AC", we must use
  98. X * name in address, because "% ..." is not in real name.
  99. X * rfmail now handles news messages too. `-n' option implemented for
  100. X * this purpose. Look up newsgroup<->area conversion in Areas file
  101. X * and generate tear, origin, seen-by and path line. No more need
  102. X * for the rfnews program.
  103. X * 
  104. X * Revision 2.3  90/09/08  18:49:03  mj
  105. X * Move strsaveline() to xalloc.c
  106. X * 
  107. X * Revision 2.2  90/09/03  17:57:44  mj
  108. X * Some changes. Generation of ^AMSGID and ^AREPLY not active
  109. X * at this point.
  110. X * 
  111. X * Revision 2.1  90/08/12  14:16:05  mj
  112. X * Added output of FIDO `^AMSGID:' and `^AREPLY:' kludges to the
  113. X * spool file for fpack. These lines are generated from RFC 822
  114. X * header lines `Message-ID:' and `References:'.
  115. X * 
  116. X * Revision 2.0  90/08/12  11:58:33  mj
  117. X * Rewrote much of the code of rfmail.c: Parsing of header is now
  118. X * much cleaner, changed the names of some functions, introduced
  119. X * other ones. Sending of mail to more than one user now really
  120. X * works.
  121. X * 
  122. X * Revision 1.6  90/08/09  19:18:05  mj
  123. X * `Comment-To:' header line no longer makes it's way into the FIDO
  124. X * message.
  125. X * 
  126. X * Revision 1.5  90/07/29  18:12:23  mj
  127. X * Place real net/node in message header for FIDO netmail. Also
  128. X * a `^AFMPT x' kludge is generated in this case. Recipient of
  129. X * our mail now gets real address from message, which should
  130. X * make replying much easier.
  131. X * 
  132. X * Revision 1.4  90/07/07  18:23:53  mj
  133. X * Support for point addressing and the IFNA `^ATOPT x' kludge
  134. X * added to rfmail.
  135. X * 
  136. X * Revision 1.3  90/07/01  13:46:04  mj
  137. X * Removed all calls to alloca(). All unsave malloc()'s without
  138. X * checking the returned pointer are now done via xmalloc().
  139. X * Fixed a malloc() error in rmail.
  140. X * 
  141. X * Revision 1.2  90/06/28  22:04:43  mj
  142. X * Much rework of the sources, no more hsu.h and other clean up.
  143. X * rmail improved, now handles special XENIX quirks.
  144. X * 
  145. X * Revision 1.1  90/06/21  21:09:34  mj
  146. X * Everything seems to work, so this delta was made.
  147. X * 
  148. X * Revision 1.0  90/06/19  18:33:19  mj
  149. X * Initial revision
  150. X * 
  151. X *
  152. X *****************************************************************************
  153. X * This version hacked and maintained by:
  154. X *    _____ _____
  155. X *   |     |___  |   Martin Junius     FIDO:    2:242/6.1   2:242/6.0
  156. X *   | | | |   | |   Republikplatz 3   DOMAIN:  mju@dfv.rwth-aachen.de
  157. X *   |_|_|_|_____|   D-5100 Aachen     Tel. (Voice) 0241-86931
  158. X *
  159. X * Original version of these programs and files:
  160. X *
  161. X *   Teemu Torma
  162. X *   Heikki Suonsivu   FIDO: 2:504/1   UUCP: ...!mcsun!santra!hsu
  163. X *
  164. X *****************************************************************************/
  165. X
  166. #include "fidogate.h"
  167. X
  168. #include <varargs.h>
  169. #include <pwd.h>
  170. X
  171. X
  172. X
  173. #define PROGRAMNAME     "rfmail $Revision: 2.24 $"
  174. X
  175. #define ORIGIN          "Link to news/mail at hippo.uucp"
  176. X
  177. /*
  178. X * Max. message size for FIDO. Due to some more brain damage in FIDONET
  179. X * programs we have to split larger messages into several smaller ones.
  180. X * QMail moved messages larger than 16K to the BADMSG directory. We use
  181. X * 15000 bytes as the max. message size, this leaves enough room for
  182. X * header and other things.
  183. X */
  184. #define MAXMSGSIZE      15000
  185. X
  186. X
  187. X
  188. extern struct passwd *getpwuid();
  189. extern int getopt();
  190. extern char *optarg;
  191. extern int optind;
  192. extern void exit();
  193. extern char *spoolfile(), *basename();
  194. extern char *regex();
  195. extern time_t time();
  196. extern FILE *popen();
  197. X
  198. X
  199. /* Verbosity */
  200. int verbose = INIT_VERBOSE;
  201. X
  202. /* Private mail (default) */
  203. bool private = TRUE;
  204. X
  205. /* News-article */
  206. int newsmode = FALSE;
  207. X
  208. /* Our net/node information */
  209. Node this;
  210. X
  211. /*
  212. X * Global array to save message header
  213. X */
  214. #define MAXHEADERS 50
  215. X
  216. char *headers[MAXHEADERS];
  217. X
  218. X
  219. X
  220. /*
  221. X * get_header() --- Get specific message header from headers[]
  222. X *
  223. X * Example:
  224. X *   To: mj@hippo.uucp (Martin Junius)
  225. X * Use:
  226. X *   get_header("To") -> "mj@hippo.uucp (Martin Junius)"
  227. X */
  228. X
  229. char *get_header(name)
  230. char *name;
  231. {
  232. register int i, len;
  233. X
  234. X   len = strlen(name);
  235. X   for(i=0; i<MAXHEADERS && headers[i]; i++)
  236. X       if(!strncmp(headers[i], name, len) && headers[i][len]==':')
  237. X           return(headers[i] + strlen(name) + 2);      /* +2 for ": " */
  238. X   return(NULL);
  239. }
  240. X
  241. X
  242. X
  243. /*
  244. X * Extract address/name from `From:', `Reply-To:' or `To:' field.
  245. X * Understood formats:
  246. X *     full name <address>
  247. X *     address (full name)
  248. X *     address
  249. X */
  250. X
  251. void get_address(field, address)
  252. char *field, *address;
  253. {
  254. register char *cp, *np;
  255. X
  256. X   if ((cp = strchr(field, '(')) && strchr(cp + 1, ')')) {
  257. X       /* format is 'address (full name)' */
  258. X       for (np = field; np < cp - 1; np++)
  259. X           *address++ = *np;
  260. X       *address = 0;
  261. X   }
  262. X   else if ((cp = strchr(field, '<')) && (np = strchr(cp + 1, '>'))) {
  263. X       /* format is 'full name <address>' */
  264. X       cp++;
  265. X       while (cp < np)
  266. X           *address++ = *cp++;
  267. X       *address = 0;
  268. X   }
  269. X   else
  270. X       /* line contains only address */
  271. X       strcpy(address, field);
  272. }
  273. X
  274. void get_name(field, name)
  275. char *field;
  276. char *name;
  277. {
  278. register char *cp, *np;
  279. X
  280. X   if ((cp = strchr(field, '(')) && (np = strchr(cp + 1, ')'))) {
  281. X       /* format is 'address (full name)' */
  282. X       for(cp++; *cp && cp<np; cp++)
  283. X           *name++ = *cp;
  284. X       *name= 0;
  285. X   }
  286. X   else if ((cp = strchr(field, '<')) && (np = strchr(cp + 1, '>'))) {
  287. X       /* format is 'full name <address>' */
  288. X       for(cp=field; *cp && *cp!='<' && *(cp+1)!='<'; cp++)
  289. X           *name++ = *cp;
  290. X       *name = 0;
  291. X   }
  292. X   else
  293. X       /* line contains only address */
  294. X       *name = 0;
  295. }
  296. X
  297. X
  298. X
  299. /*
  300. X * Get return address for returning undeliverable mail to sender.
  301. X * Extract it from Reply-To: or From: fields.
  302. X */
  303. X
  304. void
  305. get_return_address(address)
  306. char *address;
  307. {
  308. char buffer[BUFSIZ];
  309. char *field;
  310. X
  311. X   *address = 0;
  312. X
  313. X   /* check is there is Reply-To: field */
  314. X   if(field = get_header("Reply-To")) {
  315. X       get_address(field, address);
  316. X       return;
  317. X   }
  318. X
  319. X   /* no Reply-To:, check for From: */
  320. X   if(field = get_header("From")) {
  321. X       get_address(field, address);
  322. X       return;
  323. X   }
  324. X
  325. X   /* not found, send it to root */
  326. X   strcpy(address, "root");
  327. }
  328. X
  329. X
  330. X
  331. /*
  332. X * Open stream associated with programs standard input. Program is invoked
  333. X * with given argument list. Popen(3S) would invoke mailer thru sh(1),
  334. X * so this uses less memory and is faster.
  335. X */
  336. X
  337. FILE *open_mailer(program, args, pid)
  338. char *program, **args;
  339. int *pid;
  340. {
  341. FILE *fp;
  342. int fd[2];
  343. X
  344. X   /* create pipe */
  345. X   if (pipe(fd) == -1) {
  346. X       perror("rfmail: pipe");
  347. X       exit(EX_OSERR);
  348. X   }
  349. X
  350. X   switch (*pid = fork()) {
  351. X       case -1:                                /* Error */
  352. X           perror("rfmail: fork failed");
  353. X           exit(EX_OSERR);
  354. X       case 0:                                 /* Child */
  355. X           (void) close(0);
  356. X           if (dup(fd[0]) == 0) {
  357. X               (void) close(fd[0]);
  358. X               (void) close(fd[1]);
  359. X               (void) execvp(program, args);
  360. X               perror(program);
  361. X           }
  362. X           else
  363. X               perror("rfmail: dup");
  364. X           exit(EX_OSERR);
  365. X       default:                                /* Parent */
  366. X           (void) close(fd[0]);
  367. X           if ((fp = fdopen(fd[1], "w")) == NULL) {
  368. X               perror("rfmail: fdopen");
  369. X               exit(EX_OSERR);
  370. X           }
  371. X   }
  372. X   return fp;
  373. }
  374. X
  375. X
  376. X
  377. /*
  378. X * In case of error send mail back to sender.
  379. X * First argument is file pointer for mail file, the following
  380. X * are format string and args for printf().
  381. X */
  382. X
  383. /**VARARGS**/
  384. void sendback(va_alist)
  385. va_dcl
  386. {
  387. va_list args;
  388. FILE *mail;
  389. char *fmt;
  390. X
  391. #ifdef RETURN_FAILED_MAIL
  392. FILE *mailer;
  393. char to[128];
  394. char *argv[3];
  395. int pid;
  396. char buffer[BUFSIZ];
  397. int i;
  398. #endif /* RETURN_FAILED_MAIL */
  399. X
  400. X   va_start(args);
  401. X   mail = va_arg(args, FILE *);
  402. X   fmt = va_arg(args, char *);
  403. X
  404. #ifdef RETURN_FAILED_MAIL
  405. X   get_return_address(to);
  406. X   log("Mail failed, return to %s", to);
  407. X
  408. X   argv[0] = RMAIL;
  409. X   argv[1] = to;
  410. X   argv[2] = NULL;
  411. X   mailer = open_mailer(RMAIL, argv, &pid);
  412. X   if(!mailer) {
  413. X       log("$Unable to invoke mailer for returned mail");
  414. X       va_end(args);
  415. X       return;
  416. X   }
  417. X
  418. X   /* print correct header for mailer */
  419. X   fprintf(mailer, "From rfmail %s\n", date("%a %h %d %T 19%y", (long *) 0));
  420. X   fprintf(mailer, "Received: by %s (%s/%s)\n",
  421. X                   internode(this), PROGRAMNAME, this.name);
  422. X   fprintf(mailer, "\tid AA%05d; %s\n", getpid(),
  423. X                   date("%a, %d %h %y %T %o (%z)", (long *) 0));
  424. X   fprintf(mailer, "Date: %s\n", date("%a, %d %h %y %T %o", (long *) 0));
  425. X   fprintf(mailer, "From: Gateway to FIDONet <%s@%s>\n",
  426. X                   "rfmail", internode(this));
  427. X   fprintf(mailer, "Subject: Returned mail: Unable to deliver mail to FIDONet\n");
  428. X   fprintf(mailer, "Message-Id: <%s.AA%05d@%s>\n",
  429. X                   date("%y%m%q%H%M", (long *) 0), getpid(),
  430. X                   internode(this));
  431. X   fprintf(mailer, "To: %s\n", to);
  432. X   fprintf(mailer, "\n");
  433. X   fprintf(mailer, "  ----- Transcript of session follows -----\n");
  434. X   vfprintf(mailer, fmt, args);
  435. X   fprintf(mailer, "\n\n");
  436. X   fprintf(mailer, "  ----- Unsent message follows -----\n");
  437. X
  438. X   /* Copy removed header line */
  439. X   for(i=0; i<MAXHEADERS && headers[i]; i++)
  440. X       fprintf(mailer, "%s\n", headers[i]);
  441. X   fprintf(mailer, "\n");
  442. X
  443. X   /* now copy the message to mailer */
  444. X   rewind(mail);
  445. X   while (fgets(buffer, BUFSIZ, mail))
  446. X       fputs(buffer, mailer);
  447. X
  448. X   /* mail is now sent, close mailer */
  449. X   fclose(mailer);
  450. X
  451. #else /**!RETURN_FAILED_MAIL**/
  452. X   mail = va_arg(args, FILE*);
  453. X   fmt = va_arg(args, char *);
  454. X
  455. X   vfprintf(stderr, fmt, args);
  456. #endif /* not RETURN_FAILED_MAIL */
  457. X
  458. X   va_end(args);
  459. }
  460. X
  461. X
  462. X
  463. /* Check that net/node exists and mail can be send to there (ie. it
  464. X   is not down or in hold). Also be will replace name with sysop's name,
  465. X   if mail is for sysop (note that alias will override this sysop-name).
  466. X   Mail will be send back to sender, if this checking fails. */
  467. X
  468. int
  469. valid_netnode(name, node, mail)
  470. X     char *name;
  471. X     Node node;
  472. X     FILE *mail;
  473. {
  474. #ifdef NODELIST_SUPPORT
  475. X  Node *entry;
  476. X
  477. X  if (entry = node_entry(node))
  478. X    switch (entry->type)
  479. X      {
  480. X      case HOLD:
  481. X        /* node is in hold */
  482. X        sendback(mail, "Node %s is in hold", ascnode(node));
  483. X        return EX_NOHOST;
  484. X      case DOWN:
  485. X        /* node is down */
  486. X        sendback(mail, "Node %s is currently down", ascnode(node));
  487. X        return EX_NOHOST;
  488. X      default:
  489. X        /* everything was fine */
  490. X        if (!strcmp(name, "sysop") || !strcmp(name, "Sysop"))
  491. X          (void) strcpy(name, entry->sysop);
  492. X        return EX_OK;
  493. X      }
  494. X
  495. X  /* we didn't find node */
  496. X  sendback(mail, "Node %s does not exist", ascnode(node));
  497. X  return EX_NOHOST;
  498. #else
  499. X   return EX_OK;
  500. #endif
  501. }
  502. X
  503. X
  504. X
  505. /*
  506. X * Return sender of mail. Figure it out from From: field or from
  507. X * our uid if it's not administrative uid (e.g. uucp or nuucp).
  508. X * If not there, try $HOME/.fullname, then
  509. X * $HOME/.realname, then
  510. X * environment string NAME.
  511. X * If neither method works, return NULL.
  512. X * If $HOME is not defined, skip both .fullname and .realname
  513. X */
  514. X
  515. char *mail_sender()
  516. {
  517. struct passwd *pwd;
  518. static char name[36];
  519. char buffer[BUFSIZ];
  520. register char *cp, *np;
  521. register int cnt;
  522. Node dummynode;
  523. FILE *fp;
  524. char *from;
  525. X
  526. X   name[35] = 0;
  527. X   buffer[0] = 0;
  528. X   
  529. X   if(from = get_header("From"))
  530. X       strcpy(buffer, from);
  531. X       
  532. X   if(*buffer) {
  533. X       debug(2, "Checking From: field");
  534. X       /*
  535. X        * Parse the name out from From: field. there are basically
  536. X        * two kinds of formats: 'User Name <address>' or
  537. X        * 'address (User Name)'. We'll try to figure it out
  538. X        * which format sender uses.
  539. X        */
  540. X       if ((cp = strchr(buffer, '<')) && (np = strchr(cp, '>'))) {
  541. X           /* Format is 'From: Name <address>' */
  542. X           for(np = buffer,
  543. X               cnt = 0; np < cp - 1 && cnt < 35;
  544. X               np++, cnt++)
  545. X               name[cnt] = *np;
  546. X           name[cnt] = 0;
  547. X           debug(2, "Got name %s, fmt name <address>", name);
  548. X       }
  549. X       else if ((cp = strchr(buffer, '(')) && (np = strchr(cp, ')'))) {
  550. X           /* Format is 'From: address (Name)' */
  551. X           for (cnt = 0, cp++; cp < np && cnt < 35; cp++, cnt++)
  552. X               name[cnt] = *cp;
  553. X           name[cnt] = 0;
  554. X           debug(2, "Got name %s, fmt address (name)", name);
  555. X       }
  556. X       else {
  557. X           debug(5, "Could no find realname in <> or ()");
  558. X           /* Try parse it with parse_address */
  559. X           if (parse_address(buffer, name, &dummynode)) {
  560. X               (void) strncpy(name, buffer, 35);
  561. X               name[35] = 0;
  562. X               debug(2, "No format in From: line, name %s", name);
  563. X           }
  564. X           else {
  565. X               name[35] = 0;
  566. X               debug(2, "Name %s parsed from address", name);
  567. X           }
  568. X       }
  569. X       return name;
  570. X   }
  571. X
  572. X  /* hmm.. no From: field in mail. let's try to figure this problem
  573. X     out some other way. If our uid is some user's uid, we'll use
  574. X     that uid to show user's name, otherwise we'll return NULL. */
  575. X
  576. X  if (getuid() >= USERUID && (pwd = getpwuid( (int) getuid())))
  577. X    {
  578. X      /* There are two commonly used gecos-formats: So called USG
  579. X         format used by System III and System V machines and BSD
  580. X         format used by BSD machines. In USG format name is
  581. X         sandwitched between '-' and '(' characters and in BSD
  582. X         format name is first this in gecos-field up to first comma
  583. X         in it. In many machines there's only name in gecos. */
  584. X
  585. X      if ((cp = strchr(pwd->pw_gecos, '-')) && (np = strchr(cp, '(')))
  586. X        {
  587. X          /* USG format 'stuff-name(stuff)' */
  588. X          for (cnt = 0, cp++; cnt < 35 && cp < np; cp++, cnt++)
  589. X            name[cnt] = *cp;
  590. X          name[cnt] = 0;
  591. X          debug(3, "Got name from USG fmt, name %s", name);
  592. X        }
  593. X      else
  594. X        if (cp = strchr(pwd->pw_gecos, ','))
  595. X          {
  596. X            /* BSD format 'name,stuff...' */
  597. X            for (cp = buffer, cnt = 0; cnt < 35 && *cp != ','; cp++, cnt++)
  598. X              name[cnt] = *cp;
  599. X            name[cnt] = 0;
  600. X            debug(3, "Got name from BSD format, name %s", name);
  601. X          }
  602. X        else
  603. X          if (*pwd->pw_gecos)
  604. X            {
  605. X              /* non-empty gecos, assume that there's only name */
  606. X              (void) strncpy(name, pwd->pw_gecos, 35);
  607. X              name[35] = 0;
  608. X              debug(3, "No fmt in gecos, name %s", name);
  609. X            }
  610. X          else
  611. X            {
  612. X              /* Lazy administrator or user who want's to be anonymous
  613. X                 (or this is some administrative uid with no explanation
  614. X                 which)... We'll use only the username. */
  615. X
  616. X              (void) strncpy(name, pwd->pw_name, 35);
  617. X              /* never heard over 35 char usernames???? I haven't but... */
  618. X              name[35] = 0;
  619. X              debug(3, "No gecos, name = %s");
  620. X            }
  621. X      return name;
  622. X    }
  623. X
  624. X  *buffer = 0;
  625. X  if (cp = getenv("HOME"))
  626. X    {
  627. X      debug(5, "Try .fullname");
  628. X      if (fp = fopen(sprintfs("%s/%s", cp, ".fullname"), "r"))
  629. X    {
  630. X      if (!fgets(buffer, BUFSIZ, fp)) *buffer = 0;
  631. X      fclose(fp);
  632. X      strncpy(name, buffer, 35);
  633. X      if (!strempty(name))
  634. X        {
  635. X          strclean(name);
  636. X          debug(2, "Got name %s from .fullname", name);
  637. X          return name;
  638. X        }
  639. X      else
  640. X        debug(1, "Empty name '%s' in .fullname", name);
  641. X    }
  642. X      debug(5, "Try .realname");
  643. X      if (fp = fopen(sprintfs("%s/%s", cp, ".realname"), "r"))
  644. X    {
  645. X      if (!fgets(buffer, BUFSIZ, fp)) *buffer = 0;
  646. X      fclose(fp);
  647. X      strncpy(name, buffer, 35);
  648. X      if (!strempty(name))
  649. X        {
  650. X          strclean(name);
  651. X          debug(2, "Got name %s from .realname", name);
  652. X          return name;
  653. X        }
  654. X      else
  655. X        debug(1, "Empty name '%s' in .realname", name);
  656. X    }
  657. X    }
  658. X
  659. X  if (cp = getenv("NAME"))
  660. X    {
  661. X      debug(5, "Name defined, use it");
  662. X      strncpy(name, buffer, 35);
  663. X      if (!strempty(name))
  664. X    {
  665. X      strclean(name);
  666. X      debug(2, "Got name %s from environment NAME", name);
  667. X      return name;
  668. X    }
  669. X    }
  670. X
  671. X   debug(2, "No name, uid = %d", getuid());
  672. X
  673. X   return (char *) 0;
  674. }
  675. X
  676. X
  677. X
  678. /* Get net/node information from info. If zone, net, or point are missing,
  679. X   they will be returned as -1TRUE is returned, if
  680. X   everything went fine, otherwise FALSE. */
  681. X
  682. bool
  683. getnode(info, node)
  684. X     char *info;
  685. X     Node *node;
  686. {
  687. X  /* Extract zone information */
  688. X  if (strchr(info, ':'))
  689. X    {
  690. X      for (node->zone = 0; *info != ':'; info++)
  691. X    if (isdigit(*info))
  692. X      node->zone = node->zone * 10 + *info - '0';
  693. X    else
  694. X      {
  695. X        debug(1, "Invalid character in zone '%c' %02x", *info, *info);
  696. X        return FALSE;
  697. X      }
  698. X      info++;
  699. X    }
  700. X  else
  701. X    node->zone = -1;
  702. X
  703. X  /* Extract net information if net is present, otherwise
  704. X     set net to -1. */
  705. X
  706. X  if (strchr(info, '/'))
  707. X    {
  708. X      for (node->net = 0; *info != '/'; info++)
  709. X        if (isdigit(*info))
  710. X          node->net = node->net * 10 + *info - '0';
  711. X        else
  712. X          {
  713. X            debug(1, "Invalid character in net '%c' %02x", *info, *info);
  714. X            return FALSE;
  715. X          }
  716. X      info++;
  717. X    }
  718. X  else
  719. X    node->net = -1;
  720. X
  721. X  /* Exract node information, set to -1 if empty. */
  722. X
  723. X  if (*info)
  724. X    for (node->node = 0; *info && *info != '.'; info++)
  725. X      if (isdigit(*info))
  726. X        node->node = node->node * 10 + *info - '0';
  727. X      else
  728. X        {
  729. X          debug(1, "Invalid characer in node '%c' %02x", *info, *info);
  730. X          return FALSE;
  731. X        }
  732. X  else
  733. X    node->node = -1;
  734. X
  735. X  /* Exract point information, set to -1 if empty. */
  736. X
  737. X  if (*info)
  738. X    for (node->point = 0; *info; info++)
  739. X      if (isdigit(*info))
  740. X        node->point = node->point * 10 + *info - '0';
  741. X      else
  742. X        {
  743. X          debug(1, "Invalid characer in node '%c' %02x", *info, *info);
  744. X          return FALSE;
  745. X        }
  746. X  else
  747. X    node->point = -1;
  748. X
  749. X  debug(2, "Got alias %s", ascnode(*node));
  750. X  return TRUE;
  751. }
  752. X
  753. /* Compare receiver and user in aliasfile. Each line in aliasfile contains
  754. X   alias, optional net/node information separated by commas zero or
  755. X   more times, white space(s) and rest of the line literally to whom
  756. X   mail should be send. Net and node information is format 'net/node'.
  757. X   if net is omitted then every net is counted, if node is omitted,
  758. X   then all nodes in that net. If net is omitted, slash may be left off.
  759. X
  760. X   E.g following are valid aliases:
  761. X
  762. X   tot,504/ Teemu Torma
  763. X   foo Foo Bar
  764. X   sysop,504/1,504/9 System Operator */
  765. X
  766. bool aliascmp(alias, to, node)
  767. char *alias, *to;
  768. Node *node;
  769. {
  770. char buffer[BUFSIZ];
  771. char *cp;
  772. Node anode;
  773. X
  774. X   while (*alias && *alias != ',' && !isspace(*alias) && *to)
  775. X       if (*alias++ != *to++)
  776. X           return FALSE;
  777. X
  778. X   if(*to)
  779. X       return FALSE;
  780. X
  781. X   if (isspace(*alias)) /* match */
  782. X       return TRUE;
  783. X
  784. X   if (*alias == ',') {
  785. X       /* copy alias to buffer and terminate the it after first space */
  786. X       strcpy(buffer, alias + 1);
  787. X       for (cp = buffer; *cp; cp++)
  788. X           if (isspace(*cp)) {
  789. X               *cp = 0;
  790. X               break;
  791. X           }
  792. X
  793. X       /* get net/node information from buffer one at the time */
  794. X       for (cp = strtok(buffer, ","); cp; cp = strtok((char *) 0, ",")) {
  795. X           debug(2, "Got node '%s'", cp);
  796. X           if (getnode(cp, &anode)) {
  797. X               if ((anode.zone  == -1 || anode.zone  == node->zone ) &&
  798. X                   (anode.net   == -1 || anode.net   == node->net  ) &&
  799. X                   (anode.node  == -1 || anode.node  == node->node ) &&
  800. X                   (anode.point == -1 || anode.point == node->point)   )
  801. X                   return TRUE;
  802. X               }
  803. X           else
  804. X               return FALSE;
  805. X       }
  806. X   }
  807. X   else
  808. X       debug(1, "Invalid alias, %c is not ',' or white space", *alias);
  809. X
  810. X   return FALSE;
  811. }
  812. X
  813. X
  814. X
  815. /* Return receiver's name. If name is aliased, return it, otherwise
  816. X   return receiver's name. */
  817. X
  818. char *receiver(to, node)
  819. char *to;
  820. Node *node;
  821. {
  822. static char name[36];
  823. char buffer[BUFSIZ];
  824. register int cnt;
  825. register char *cp;
  826. FILE *fp;
  827. int i, c, convert_flag;
  828. X
  829. X   debug(3, "Name for alias checking: %s", to);
  830. X
  831. X   if (fp = fopen(ALIAS, "r")) {
  832. X       while (fgets(buffer, BUFSIZ, fp)) {
  833. X           buffer[strlen(buffer) - 1] = 0;
  834. X           if (*buffer != '#')
  835. X               debug(3, "Checking for alias %s", buffer);
  836. X           if (*buffer != '#' && aliascmp(buffer, to, node)) {
  837. X               /* match, save the alias. */
  838. X               for (cp = buffer; *cp && !isspace(*cp); cp++)
  839. X                   /* skip alias itself */;
  840. X               while (isspace(*cp))
  841. X                   cp++;
  842. X               if (*cp) {
  843. X                   for (cnt = 0; *cp && cnt < 35; cnt++, cp++)
  844. X                       name[cnt] = *cp;
  845. X                   name[cnt] = 0;
  846. X                   debug(2, "Got alias %s", name);
  847. X                   fclose(fp);
  848. X                   return name;
  849. X               }
  850. X               else
  851. X                   debug(1, "Missing alias");
  852. X           }
  853. X       }
  854. X       fclose(fp);
  855. X   }
  856. X   else
  857. X       log("$Unable to open aliasfile %s", ALIAS);
  858. X
  859. X   /*
  860. X    * Alias not found. Return the the original receiver with all
  861. X    * '_' characters replaced by space and all words capitalized.
  862. X    */
  863. X   convert_flag = isupper(*to) ? -1 : 1;
  864. X   for(i=0; *to && i<35; i++, to++) {
  865. X       c = *to;
  866. X       switch(c) {
  867. X           case '_':
  868. X               name[i] = ' ';
  869. X               if(!convert_flag)
  870. X                   convert_flag = 1;
  871. X               break;
  872. X           case '%':
  873. X               if(convert_flag != -1)
  874. X                   convert_flag = 2;
  875. X               /**Fall thru**/
  876. X           default:
  877. X               if(convert_flag > 0) {
  878. X                   name[i] = islower(c) ? toupper(c) : c;
  879. X                   if(convert_flag == 1)
  880. X                       convert_flag = 0;
  881. X               }
  882. X               else
  883. X                   name[i] = c;
  884. X               break;
  885. X       }
  886. X   }
  887. X   name[i] = 0;
  888. X
  889. X   debug(2, "No alias, name %s", name);
  890. X   return name;
  891. }
  892. X
  893. X
  894. X
  895. /*
  896. X * Return from field for FIDO message.
  897. X * Alias checking is done via receiver().
  898. X */
  899. X
  900. char *mail_receiver(address, node)
  901. char *address;
  902. Node *node;
  903. {
  904. char *cp;
  905. int found = 0;
  906. char name[36];
  907. char realname[36];
  908. char addr[128];
  909. char *to;
  910. Node dummy;
  911. X
  912. X   realname[0] = 0;
  913. X
  914. X   if(address) {
  915. X       /*
  916. X        * Address is argument
  917. X        */
  918. X       debug(2, "Address to parse: %s", address);
  919. X       if(parse_address(address, name, node)) {
  920. X           log("Parse of address %s failed", address);
  921. X           return NULL;
  922. X       }
  923. X   }
  924. X   else {
  925. X       /*
  926. X        * Address is echo feed
  927. X        */
  928. X       node->zone  = MY_ZONE;
  929. X       node->net   = ECHOFEED_NET;
  930. X       node->node  = ECHOFEED_NODE;
  931. X       node->point = 0;
  932. X       strcpy(name, "All");
  933. X   }
  934. X       
  935. X   /*
  936. X    * Try to look up a better real name in header fields
  937. X    *
  938. X    * Standard RFC822 header line
  939. X    */
  940. X   if(to = get_header("To")) {
  941. X       debug(2, "Checking To: field");
  942. X       get_address(to, addr);
  943. X       if(!address || !strcmp(address, addr)) {
  944. X           get_name(to, realname);
  945. X           found = 1;
  946. X       }
  947. X   }
  948. X
  949. X   /*
  950. X    * User-defined header line for gateway software
  951. X    * (can be patched into news reader)
  952. X    */
  953. X   if(!found && (to = get_header("Comment-To"))) {
  954. X       debug(2, "Checking Comment-To: field");
  955. X       get_address(to, addr);
  956. X       if(!address || !strcmp(address, addr)) {
  957. X           get_name(to, realname);
  958. X           found = 1;
  959. X       }
  960. X    }
  961. X   
  962. X   /*
  963. X    * Header generated by nn's `r' command
  964. X    */
  965. X   if(!found && (to = get_header("Orig-To"))) {
  966. X       debug(2, "Checking Orig-To: field");
  967. X       get_address(to, addr);
  968. X       if(!address || !strcmp(address, addr)) {
  969. X           get_name(to, realname);
  970. X           found = 1;
  971. X       }
  972. X    }
  973. X   
  974. X   /*
  975. X    * News message: get name from address taken out of header line
  976. X    */
  977. X   if(found && !address)
  978. X       parse_address(addr, name, &dummy);
  979. X       
  980. X   /*
  981. X    * Use real name from header line, if no special addressing with '%'
  982. X    */
  983. X   if(found && !strchr(name, '%') && *realname)
  984. X       strcpy(name, realname);
  985. X   
  986. X   return receiver(name, node);
  987. }
  988. X
  989. X
  990. X
  991. /*
  992. X * Get date field for FIDO message. Look for `Date:' header or use
  993. X * current time.
  994. X */
  995. X
  996. char *fido_date()
  997. {
  998. time_t timevar;
  999. struct tm *localtime();
  1000. struct tm *mtime;
  1001. static char timebuf[20];
  1002. /* literal months */
  1003. static char *months[] = {
  1004. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1005. X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  1006. X    (char *) 0,
  1007. };
  1008. /* Literal weekdays */
  1009. static char *wkdays[] = {
  1010. X    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", (char *) 0,
  1011. };
  1012. char *header_date;
  1013. X
  1014. X   if(header_date = get_header("Date")) {
  1015. X        /* try to extract date and other information from it */
  1016. X        debug(2, "Found date: '%s'", header_date);
  1017. X       timevar = getdate(header_date, NULL);
  1018. X   }
  1019. X   else
  1020. X       timevar = time(0);
  1021. X
  1022. X   debug(2, "timevar %ld", timevar);
  1023. X   mtime = localtime(&timevar);
  1024. X   /* Save date in FTS-0001 format ! */
  1025. X   sprintf(timebuf, "%02d %3s %02d  %02d:%02d:%02d",
  1026. X                    mtime->tm_mday, months[mtime->tm_mon], mtime->tm_year,
  1027. X                    mtime->tm_hour, mtime->tm_min, mtime->tm_sec           );
  1028. X   debug(1, "Returning %s", timebuf);
  1029. X   return timebuf;
  1030. }
  1031. X
  1032. X
  1033. X
  1034. char *estrtok(s, sep)
  1035. char *s, *sep;
  1036. {
  1037. X   char *p;
  1038. X
  1039. X   if (p = strtok(s, sep))
  1040. X       return p;
  1041. X   return "";
  1042. }
  1043. X
  1044. X
  1045. X
  1046. /*
  1047. X * Output mail/news messages into spool file(s) for fpack
  1048. X */
  1049. X
  1050. #define NGROUPS         10
  1051. #define NFIDO           6
  1052. X
  1053. #define FIDO_NODE       0
  1054. #define FIDO_TO         1
  1055. #define FIDO_FROM       2
  1056. #define FIDO_SUBJECT    3
  1057. #define FIDO_DATE       4
  1058. #define FIDO_FLAGS      5
  1059. X
  1060. int send_mail(fp, to, split)
  1061. FILE *fp;                               /* Temporary file message body */
  1062. char *to;                               /* Adress to send to (news = NULL) */
  1063. int split;                              /* Split message into several parts */
  1064. {
  1065. char buffer[BUFSIZ];
  1066. char groups[BUFSIZ];
  1067. char *group[NGROUPS];
  1068. Node node;
  1069. char *p;
  1070. char *fido_header[NFIDO];
  1071. char *area;
  1072. char *newsgroup;
  1073. FILE *fpareas;
  1074. int status;
  1075. int i;
  1076. X
  1077. X   if(to)
  1078. X       debug(1, "Sending mail to %s", to);
  1079. X   else
  1080. X       debug(1, "Sending news");
  1081. X
  1082. X   /*
  1083. X    * Get to/from/node/subject/date
  1084. X    */
  1085. X   fido_header[FIDO_TO]      = mail_receiver(to, &node);
  1086. X   if(!fido_header[FIDO_TO]) {
  1087. X       sendback(fp, "Illegal address %s", to);
  1088. X       return(EX_NOHOST);
  1089. X   }
  1090. X
  1091. X   fido_header[FIDO_FROM]    = mail_sender();
  1092. X   if(!fido_header[FIDO_FROM])
  1093. X       fido_header[FIDO_FROM] = "Gateway to FIDONET";
  1094. X
  1095. X   fido_header[FIDO_NODE]    = ascnode(node);
  1096. X
  1097. X   fido_header[FIDO_SUBJECT] = get_header("Subject");
  1098. X   if(!fido_header[FIDO_SUBJECT])
  1099. X       fido_header[FIDO_SUBJECT] = "Mail from Gateway to FIDONET";
  1100. X   
  1101. X   fido_header[FIDO_DATE]    = fido_date();
  1102. X   
  1103. X   fido_header[FIDO_FLAGS]   = get_header("X-Flags");
  1104. X   if(!fido_header[FIDO_FLAGS])
  1105. X       fido_header[FIDO_FLAGS] = "";
  1106. X
  1107. X   debug(2, "FIDO Node:    %s", fido_header[FIDO_NODE]);
  1108. X   debug(2, "FIDO To:      %s", fido_header[FIDO_TO]);
  1109. X   debug(2, "FIDO From:    %s", fido_header[FIDO_FROM]);
  1110. X   debug(2, "FIDO Subject: %s", fido_header[FIDO_SUBJECT]);
  1111. X   debug(2, "FIDO Date:    %s", fido_header[FIDO_DATE]);
  1112. X   debug(2, "FIDO Flags:   %s", fido_header[FIDO_DATE]);
  1113. X
  1114. X   if(newsmode) {
  1115. X       /*
  1116. X        * News message: get newsgroups and convert to FIDO areas
  1117. X        */
  1118. X       p = get_header("Newsgroups");
  1119. X       if(!p) {
  1120. X           sendback(fp, "No Newsgroups header in news message");
  1121. X           return(EX_DATAERR);
  1122. X       }
  1123. X       strcpy(groups, p);
  1124. X       debug(3, "Newsgroups '%s'", groups);
  1125. X
  1126. X       for(i=0, p=strtok(groups, ","); p && i<NGROUPS; p=strtok(NULL, ","), i++)
  1127. X           group[i] = p;
  1128. X       for(; i<NGROUPS; i++)
  1129. X           group[i] = NULL;
  1130. X
  1131. X       fpareas = pfopen(LIBDIR, "Areas", "r");
  1132. X       if(!fpareas) {
  1133. X           log("$Can't open areas file");
  1134. X           sendback(fp, "Internal error: can't open file");
  1135. X           return(EX_IOERR);
  1136. X       }
  1137. X
  1138. X       for(i=0; i<NGROUPS && group[i]; i++) {
  1139. X           p = group[i];
  1140. X           debug(3, "Look up newsgroup %s", p);
  1141. X           rewind(fpareas);
  1142. X           while(getcl(buffer, BUFSIZ, fpareas)) {
  1143. X               area      = estrtok(buffer, " \t");
  1144. X               newsgroup = estrtok(NULL,   " \t");
  1145. X               debug(4, "Checking newsgroup %s", newsgroup);
  1146. X               if(!strcmp(newsgroup, p)) {     /* Found */
  1147. X                   debug(4, "Found area %s", area);
  1148. X                   break;
  1149. X               }
  1150. X               area = NULL;
  1151. X           }
  1152. #if 0
  1153. X           if(!area) {
  1154. X               log("No EchoMail area found for newsgroup '%s'", p);
  1155. /*              area = "JUNK"; /**/
  1156. X           }
  1157. #endif
  1158. X           if(area) {
  1159. X               debug(3, "Sending message to area '%s'", area);
  1160. X               status = send_message(fp, node, fido_header, area, split);
  1161. X               if(status)
  1162. X                   return(status);
  1163. X           }
  1164. X       }
  1165. X   }
  1166. X   else {
  1167. X       /*
  1168. X        * NetMail message
  1169. X        */
  1170. X       p = get_header("From");
  1171. X       log("%s -> %s @ %s", p ? p : fido_header[FIDO_FROM],
  1172. X           fido_header[FIDO_TO], fido_header[FIDO_NODE]        );
  1173. X       return(send_message(fp, node, fido_header, NULL, split));
  1174. X   }
  1175. X   
  1176. X   return EX_OK;
  1177. }
  1178. X
  1179. X
  1180. int send_message(fp, node, fido_header, area, split)
  1181. FILE *fp;
  1182. Node node;
  1183. char *fido_header[];
  1184. char *area;
  1185. int split;
  1186. {
  1187. char buffer[BUFSIZ];
  1188. FILE *sf;
  1189. char *sfile;
  1190. char *header;
  1191. int part = 1;
  1192. long size;
  1193. X
  1194. X   rewind(fp);
  1195. X
  1196. X   /*
  1197. X    * Open spool file for output
  1198. X    */
  1199. again:
  1200. X   sf = fopen(sfile = spoolfile("M."), "w");
  1201. X   if(!sf) {
  1202. X       log("$Unable to open spoolfile %s", sfile);
  1203. X       return(EX_CANTCREAT);
  1204. X   }
  1205. X   
  1206. X   /* set correct permissions for spoolfile and lock it */
  1207. X   if(private)
  1208. X       chmod(sfile, 0600);
  1209. X   lock(fileno(sf));
  1210. X
  1211. X   /*
  1212. X    * Header for fpack
  1213. X    *     N destination node
  1214. X    *     T destination name
  1215. X    *     F from name
  1216. X    *     S subject
  1217. X    *     D date
  1218. X    *     X flags            (P=private, C=crash)
  1219. X    */
  1220. X   fprintf(sf, "N %s\n", fido_header[FIDO_NODE]);
  1221. X   fprintf(sf, "T %s\n", fido_header[FIDO_TO]);
  1222. X   fprintf(sf, "F %s\n", fido_header[FIDO_FROM]);
  1223. X   if(split)
  1224. X       fprintf(sf, "S %c: %s\n", part + '@', fido_header[FIDO_SUBJECT]);
  1225. X   else
  1226. X       fprintf(sf, "S %s\n", fido_header[FIDO_SUBJECT]);
  1227. X   fprintf(sf, "D %s\n", fido_header[FIDO_DATE]);
  1228. X   fprintf(sf, "X %s%s\n", private ? "P" : "", fido_header[FIDO_FLAGS]);
  1229. X   fprintf(sf, "\n");
  1230. X
  1231. X
  1232. X   if(newsmode) {
  1233. X       /*
  1234. X        * Add AREA:... line for echo mail
  1235. X        */
  1236. X       fprintf(sf, "AREA:%s\n", area);
  1237. X   }
  1238. X   else {
  1239. X       /*
  1240. X        * Add IFNA kludges for zone/point addressing
  1241. X        */
  1242. X       if(private && (node.zone != MY_ZONE))
  1243. X           fprintf(sf, "\001INTL %s %s\n", ascnoden(node), ascnoden(this));
  1244. X       if(private && REAL_POINT)
  1245. X           fprintf(sf, "\001FMPT %d\n", REAL_POINT);
  1246. X       if(node.point)
  1247. X           fprintf(sf, "\001TOPT %d\n", node.point);
  1248. X   }
  1249. X   
  1250. X   /*
  1251. X    * Add kludge for MSGID / REPLY
  1252. X    */
  1253. X   if(header = get_header("Message-ID")) {
  1254. X       if(print_msgid(sf, "MSGID", header))
  1255. X           print_local_msgid(sf);
  1256. X       if(header = get_header("References"))
  1257. X           print_msgid(sf, "REPLY", header);
  1258. X       else if(header = get_header("In-Reply-To"))
  1259. X           print_msgid(sf, "REPLY", header);
  1260. X   }
  1261. X   else {
  1262. X       print_local_msgid(sf);
  1263. X       if(header = get_header("In-Reply-To"))
  1264. X           print_msgid(sf, "REPLY", header);
  1265. X   }
  1266. X
  1267. X   /*
  1268. X    * Add some header lines
  1269. X    */
  1270. X   if(header = get_header("From"))
  1271. X       fprintf(sf, "From: %s\n", header);
  1272. X   if(header = get_header("Reply-To"))
  1273. X       fprintf(sf, "Reply-To: %s\n", header);
  1274. X   if(header = get_header("To"))
  1275. X       fprintf(sf, "To: %s\n", header);
  1276. X   if(header = get_header("Cc"))
  1277. X       fprintf(sf, "Cc: %s\n", header);
  1278. X   if(header = get_header("Newsgroups"))
  1279. X       if(strchr(header, ','))             /* Posted to multiple groups */
  1280. X           fprintf(sf, "Newsgroups: %s\n", header);
  1281. X   fprintf(sf, "\n");
  1282. X
  1283. X   /*
  1284. X    * Add line indicating splitted message
  1285. X    */
  1286. X   if(split)
  1287. X       fprintf(sf, " * Large message splitted by rfmail: part %02d/%02d\n\n",
  1288. X                   part, split                                             );
  1289. X
  1290. X   /*
  1291. X    * Copy mail file
  1292. X    */
  1293. X   size = 0;
  1294. X   debug(3, "Copying mail");
  1295. X   while(fgets(buffer, BUFSIZ, fp)) {
  1296. X       fputs(buffer, sf);
  1297. X       size += strlen(buffer) + 1;
  1298. X       if(size > MAXMSGSIZE) {
  1299. X           if(newsmode)
  1300. X               print_origin(sf);
  1301. X           fclose(sf);
  1302. X           part++;
  1303. X           goto again;
  1304. X       }
  1305. X   }
  1306. X
  1307. X   /*
  1308. X    * If message is for echo mail (-n flag) then add
  1309. X    * tear, origin, seen-by and path line.
  1310. X    */
  1311. X   if(newsmode)
  1312. X       print_origin(sf);
  1313. X
  1314. X   /*
  1315. X    * Done
  1316. X    */
  1317. X   fclose(sf);
  1318. X   return EX_OK;
  1319. }
  1320. X
  1321. X
  1322. X
  1323. /*
  1324. X * Generate origin, seen-by and path line
  1325. X */
  1326. X
  1327. int print_origin(fp)
  1328. FILE *fp;
  1329. {
  1330. X   fprintf(fp, "\n--- %s\n", PROGRAMNAME);
  1331. X   fprintf(fp, " * Origin: %s (%d:%d/%d.%d)\n", ORIGIN,
  1332. X                 REAL_ZONE, REAL_NET, REAL_NODE, REAL_POINT);
  1333. X   fprintf(fp, "SEEN-BY: %d/%d ", MY_NET, MY_NODE);
  1334. X   if(ECHOFEED_NET != MY_NET)
  1335. X       fprintf(fp, "%d/", ECHOFEED_NET);
  1336. X   fprintf(fp,"%d\n", ECHOFEED_NODE);
  1337. X   fprintf(fp, "\001PATH: %d/%d\n", MY_NET, MY_NODE);
  1338. }
  1339. X
  1340. X
  1341. X
  1342. /*
  1343. X * Generate new FIDO kludge: `^AMSGID:' and `^AREPLY:'
  1344. X */
  1345. X
  1346. int print_msgid(fp, name, message_id)
  1347. FILE *fp;
  1348. char *name;
  1349. char *message_id;
  1350. {
  1351. char *id, *host, *p;
  1352. char *savep;
  1353. Node node;
  1354. long atol();
  1355. X
  1356. X   savep = message_id = strsave(message_id);
  1357. X   /*
  1358. X    * Format of message_id is "<identification@host.domain> ..."
  1359. X    * We want the the last one in the chain, which is the message id
  1360. X    * of the article replied to.
  1361. X    */
  1362. X   message_id = strrchr(message_id, '<');
  1363. X   if(!message_id)
  1364. X       goto error;
  1365. X   id   = message_id+1;
  1366. X   host = strchr(message_id, '@');
  1367. X   if(!host)
  1368. X       goto error;
  1369. X   *host++ = 0;
  1370. X   p = strchr(host, '>');
  1371. X   if(!p)
  1372. X       goto error;
  1373. X   *p = 0;
  1374. X   
  1375. X   /*
  1376. X    * First let's test id. If it is entirely numeric, we can use
  1377. X    * it for the 32-bit number in ^AMSGID, else give up.
  1378. X    */
  1379. X   for(p=id; *p; p++)
  1380. X       if(!isdigit(*p))
  1381. X           goto error;
  1382. X   
  1383. X   /*
  1384. X    * Try to interprete host as a FIDO node. If this succeedes
  1385. X    * print out host as <zone>:<net>/<node>[.<point>], else
  1386. X    * print host as we got it from message_id.
  1387. X    */
  1388. X   if(!parseinternode(host, &node))
  1389. X       host = ascnode(node);
  1390. X   fprintf(fp, "\001%s: %s %08lx\n", name, host, atol(id));
  1391. X
  1392. X   free(savep);
  1393. X   return(0);
  1394. X
  1395. error:
  1396. X   free(savep);
  1397. X   return(-1);
  1398. }
  1399. X
  1400. X
  1401. X
  1402. /*
  1403. X * Generate local `^AMSGID:' if none is found in message header
  1404. X */
  1405. X
  1406. print_local_msgid(fp)
  1407. FILE *fp;
  1408. {
  1409. long msgid;
  1410. X
  1411. X   msgid = sequencer(MSGIDSEQ);
  1412. X   fprintf(fp, "\001MSGID: %s %08lx\n", ascnode(this), msgid);
  1413. }
  1414. X
  1415. X
  1416. X
  1417. main(argc, argv)
  1418. int argc;
  1419. char *argv[];
  1420. {
  1421. int cnt, c;
  1422. FILE *mail;
  1423. char buffer[BUFSIZ], tmpfile[L_tmpnam];
  1424. int status = EX_OK;
  1425. char *error;
  1426. Node *node, mynode;
  1427. int header_count;
  1428. long size;
  1429. int split;
  1430. X
  1431. X   newsmode = FALSE;
  1432. X
  1433. X   while ((c = getopt(argc, argv, "npvV:")) != EOF)
  1434. X       switch (c) {
  1435. X           case 'n':
  1436. X               /* Set news-mode */
  1437. X               newsmode = TRUE;
  1438. X               private  = FALSE;
  1439. X               break;
  1440. X           case 'v':
  1441. X               /* set more verbosity */
  1442. X               verbose++;
  1443. X               break;
  1444. X           case 'V':
  1445. X               verbose = atoi(optarg);
  1446. X               break;
  1447. X           case 'p':
  1448. X               /* this is not private message */
  1449. X               private  = FALSE;
  1450. X               break;
  1451. X           default:
  1452. X               fprintf(stderr, "%s\n\n", PROGRAMNAME);
  1453. X               fprintf(stderr, "usage: rfmail [-npv] [-V verbose_level] user ...\n\n");
  1454. X               exit(EX_USAGE);
  1455. X               break;
  1456. X       }
  1457. X
  1458. X   /*
  1459. X    * Create temp file for saving standard input and open it
  1460. X    */
  1461. X   tmpnam(tmpfile);
  1462. X   if((mail = fopen(tmpfile, "w+")) == NULL) {
  1463. X       log("$Can not open %s for writing", tmpfile);
  1464. X       exit(EX_CANTCREAT);
  1465. X   }
  1466. X   /* protect mail file */
  1467. X   chmod(tmpfile, 0600);
  1468. X
  1469. X   /*
  1470. X    * Read headers from stdin
  1471. X    */
  1472. X   header_count = 0;
  1473. X   while(fgets(buffer, BUFSIZ, stdin)) {
  1474. X       if(*buffer == '\n')                 /* End of header lines */
  1475. X           break;
  1476. X       if(header_count < MAXHEADERS)
  1477. X           headers[header_count++] = strsaveline(buffer);
  1478. X   }
  1479. X
  1480. X   /*
  1481. X    * Copy remainder of stdin to temporary file and count size
  1482. X    */
  1483. X   size = 0;
  1484. X   while(fgets(buffer, BUFSIZ, stdin)) {
  1485. X       fputs(buffer, mail);
  1486. X       size += strlen(buffer) + 1;             /* `+1' for additional CR */
  1487. X   }
  1488. X   split = size>MAXMSGSIZE ? size/MAXMSGSIZE + 1 : 0;
  1489. X   debug(3, "Message body size %ld", size);
  1490. X   if(split)
  1491. X       debug(3, "Must split message, %d parts", split);
  1492. X
  1493. #ifdef NODELIST_SUPPORT
  1494. X   /* update nodelist-index if needed */
  1495. X   if (error = update_index()) {
  1496. X       /* there was error while updating nodelist-index */
  1497. X       if (*error == '$')
  1498. X           sendback(mail, "%s: %s", error + 1, strerror(errno));
  1499. X       else
  1500. X           sendback(mail, "%s", error);
  1501. X       exit(EX_SOFTWARE);
  1502. X   }
  1503. #endif
  1504. X
  1505. X   mynode.zone  = REAL_ZONE;
  1506. X   mynode.net   = REAL_NET;
  1507. X   mynode.node  = REAL_NODE;
  1508. X   mynode.point = REAL_POINT;
  1509. X   strcpy(mynode.name, MY_NAME);
  1510. X
  1511. #ifdef NODELIST_SUPPORT
  1512. X   if ((node = node_entry(mynode)) == NULL) {
  1513. X       (void) fprintf(stderr, "Unable to this node from nodelist\n");
  1514. X       log("No %s in nodelist", ascnode(mynode));
  1515. X       exit(EX_SOFTWARE);
  1516. X   }
  1517. #else
  1518. X   node = &mynode;
  1519. #endif
  1520. X   this = *node;
  1521. X
  1522. X
  1523. X   rewind(mail);
  1524. X
  1525. X   if(newsmode)
  1526. X       /*
  1527. X        * Send mail to echo feed for news messages
  1528. X        */
  1529. X       status = send_mail(mail, NULL, split);
  1530. X   else
  1531. X       /*
  1532. X        * Send mail to addresses from command line args
  1533. X        */
  1534. X       for(cnt = optind; cnt < argc; cnt++)
  1535. X           if((status = send_mail(mail, argv[cnt], split)) != EX_OK)
  1536. X               break;
  1537. X
  1538. X   /* remove temporary file */
  1539. X   fclose(mail);
  1540. X   unlink(tmpfile);
  1541. X
  1542. X   exit(status);
  1543. }
  1544. SHAR_EOF
  1545. chmod 0644 rfmail.c ||
  1546. echo 'restore of rfmail.c failed'
  1547. Wc_c="`wc -c < 'rfmail.c'`"
  1548. test 36748 -eq "$Wc_c" ||
  1549.     echo 'rfmail.c: original size 36748, current size' "$Wc_c"
  1550. fi
  1551. true || echo 'restore of funcs.c failed'
  1552. echo End of part 3, continue with part 4
  1553. exit 0
  1554.  
  1555. --
  1556.  _____ _____
  1557. |     |___  |   Martin Junius     FIDO:    2:242/6.1   2:242/6.0
  1558. | | | |   | |   Republikplatz 3   DOMAIN:  mj@dfv.rwth-aachen.de
  1559. |_|_|_|_____|   D-5100 Aachen     Tel. (Voice) 0241-86931
  1560.