home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / fnet / part02 < prev    next >
Text File  |  1989-03-05  |  61KB  |  2,249 lines

  1. Subject:  v18i003:  Fido/Usenet gateway, Part02/05
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Heikki Suonsivu <hsu@santra.hut.fi>
  7. Posting-number: Volume 18, Issue 3
  8. Archive-name: fnet/part02
  9.  
  10. #!/bin/sh
  11. # this is part 2 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file rfmail.c continued
  14. #
  15. CurArch=2
  16. if test ! -r s2_seq_.tmp
  17. then echo "Please unpack part 1 first!"
  18.      exit 1; fi
  19. ( read Scheck
  20.   if test "$Scheck" != $CurArch
  21.   then echo "Please unpack part $Scheck next!"
  22.        exit 1;
  23.   else exit 0; fi
  24. ) < s2_seq_.tmp || exit 1
  25. echo "x - Continuing file rfmail.c"
  26. sed 's/^X//' << 'SHAR_EOF' >> rfmail.c
  27. X}
  28. X
  29. X/* Get return address from mail. Extract it from Reply-To: or From: fields. */
  30. X
  31. Xvoid
  32. Xget_return_address(mail, address)
  33. X     FILE *mail;
  34. X     char *address;
  35. X{
  36. X  char buffer[BUFSIZ];
  37. X
  38. X  *address = 0;
  39. X
  40. X  /* check is there is Reply-To: field */
  41. X  (void) rewind(mail);
  42. X  while (fgets(buffer, BUFSIZ, mail) && *buffer != '\n')
  43. X    if (!strncmp(buffer, "Reply-To: ", 10))
  44. X      {
  45. X        get_address(buffer + 10, address);
  46. X        return;
  47. X      }
  48. X
  49. X  /* no Reply-To:, check for From: */
  50. X  (void) rewind(mail);
  51. X  while (fgets(buffer, BUFSIZ, mail) && *buffer != '\n')
  52. X    if (!strncmp(buffer, "From: ", 6))
  53. X      {
  54. X        get_address(buffer + 6, address);
  55. X        return;
  56. X      }
  57. X
  58. X  /* not found, send it to uucp */
  59. X  (void) strcpy(address, "uucp");
  60. X}
  61. X
  62. X/* Send mail back to sender. If Reply-To: of From:-field is present,
  63. X   we'll use address specified in that, otherwise we will not return
  64. X   mail (it also should be able to parse From_ fields). First argument
  65. X   is file containing this mail, others are for vprintf(3S) to be used
  66. X   as transcript. */
  67. X
  68. X/* VARARGS */
  69. Xvoid
  70. Xsendback(va_alist)
  71. X     va_dcl
  72. X{
  73. X  va_list args;
  74. X  FILE *mail;
  75. X
  76. X#ifdef RETURN_FAILED_MAIL
  77. X  FILE *mailer;
  78. X  char *fmt, buffer[BUFSIZ];
  79. X  char to[128];
  80. X#endif /* RETURN_FAILED_MAIL */
  81. X
  82. X  va_start(args);
  83. X  mail = va_arg(args, FILE *);
  84. X  fmt = va_arg(args, char *);
  85. X
  86. X#ifdef RETURN_FAILED_MAIL
  87. X  get_return_address(mail, to);
  88. X  log("Mail failed, return to %s", to);
  89. X
  90. X  /* generate shell command and open it */
  91. X  (void) sprintf(buffer, "exec %s %s", RMAIL, to);
  92. X  if (mailer = popen(buffer, "w"))
  93. X    {
  94. X      /* print correct header for mailer */
  95. X      (void) fprintf(mailer, "From %d!MAILER-DAEMON %s remote from %d\n",
  96. X                     this.node, date("%a %h %d %T 19%y", (long *) 0),
  97. X                     this.net);
  98. X      (void) fprintf(mailer, "Received: by %s (%s/%s)\n",
  99. X                     internode(this), PROGRAMNAME, this.name);
  100. X      (void) fprintf(mailer, "\tid AA%05d; %s\n", getpid(),
  101. X                     date("%a, %d %h %y %T %o (%z)", (long *) 0));
  102. X      (void) fprintf(mailer, "Date: %s\n", date("%a, %d %h %y %T %o",
  103. X                                                (long *) 0));
  104. X      (void) fprintf(mailer, "From: FidoNet Mail <%s@%s>\n",
  105. X                     "MAILER-DAEMON", internode(this));
  106. X      (void) fprintf(mailer, "Subject: Returned mail: %s\n",
  107. X                     "Unable to deliver mail to FidoNet");
  108. X      (void) fprintf(mailer, "Message-Id: <%s.AA%05d@%s>\n",
  109. X                     date("%y%m%q%H%M", (long *) 0), getpid(),
  110. X             internode(this));
  111. X      (void) fprintf(mailer, "To: %s\n", to);
  112. X      (void) fprintf(mailer, "\n");
  113. X      (void) fprintf(mailer, "  ----- Transcript of session follows -----\n");
  114. X      (void) vfprintf(mailer, fmt, args);
  115. X      (void) fprintf(mailer, "\n\n");
  116. X      (void) fprintf(mailer, "  ----- Unsent message follows -----\n");
  117. X
  118. X      /* now copy the message to mailer */
  119. X      (void) rewind(mail);
  120. X      while (fgets(buffer, BUFSIZ, mail))
  121. X        (void) fputs(buffer, mailer);
  122. X
  123. X      /* mail is now sent, close mailer */
  124. X      (void) pclose(mailer);
  125. X    }
  126. X  else
  127. X    log("$Unable to invoke mailer for returned mail");
  128. X#else /* not RETURN_FAILED_MAIL */
  129. X  /* get dummy mail-file pointer */
  130. X  mail = va_arg(args, FILE*);
  131. X  fmt = va_arg(args, char *);
  132. X
  133. X  /* just print error to stderr, sendmail will return mail to sender
  134. X     due to non-zero exit code. */
  135. X  (void) vfprintf(stderr, fmt, args);
  136. X#endif /* not RETURN_FAILED_MAIL */
  137. X
  138. X  va_end(args);
  139. X}
  140. X
  141. X/* Check that net/node exists and mail can be send to there (ie. it
  142. X   is not down or in hold). Also be will replace name with sysop's name,
  143. X   if mail is for sysop (note that alias will override this sysop-name).
  144. X   Mail will be send back to sender, if this checking fails. */
  145. X
  146. Xint
  147. Xvalid_netnode(name, node, mail)
  148. X     char *name;
  149. X     Node node;
  150. X     FILE *mail;
  151. X{
  152. X  Node *entry;
  153. X
  154. X  if (entry = node_entry(node))
  155. X    switch (entry->type)
  156. X      {
  157. X      case HOLD:
  158. X        /* node is in hold */
  159. X        sendback(mail, "Node %s is in hold", ascnode(node));
  160. X        return EX_NOHOST;
  161. X      case DOWN:
  162. X        /* node is down */
  163. X        sendback(mail, "Node %s is currently down", ascnode(node));
  164. X        return EX_NOHOST;
  165. X      default:
  166. X        /* everything was fine */
  167. X        if (!strcmp(name, "sysop") || !strcmp(name, "Sysop"))
  168. X          (void) strcpy(name, entry->sysop);
  169. X        return EX_OK;
  170. X      }
  171. X
  172. X  /* we didn't find node */
  173. X  sendback(mail, "Node %s does not exist", ascnode(node));
  174. X  return EX_NOHOST;
  175. X}
  176. X
  177. X/* Return sender of mail. Figure it out from From: field or from
  178. X   our uid if it's not administrative uid (e.g. uucp or nuucp).
  179. X   If not there, try $HOME/.fullname, then
  180. X   $HOME/.realname, then
  181. X   environment string NAME.
  182. X   If neither method works, return NULL.
  183. X   If $HOME is not defined, skip both .fullname and .realname */
  184. X
  185. Xchar *
  186. Xsender(mail, field)
  187. X     FILE *mail;
  188. X     char *field;
  189. X{
  190. X  struct passwd *pwd;
  191. X  static char name[36];
  192. X  char buffer[BUFSIZ];
  193. X  register char *cp, *np;
  194. X  register int cnt;
  195. X  Node dummynode;
  196. X  FILE *fp;
  197. X
  198. X  name[35] = 0;
  199. X  (void) rewind(mail);
  200. X  while (fgets(buffer, BUFSIZ, mail))
  201. X    {
  202. X      buffer[strlen(buffer) - 1] = 0; /* strip newline */
  203. X      if (!strncmp(buffer, field, strlen(field)))
  204. X        {
  205. X          /* Parse the name out from From: field. there are basically
  206. X             two kinds of formats: 'User Name <address>' or
  207. X             'address (User Name)'. We'll try to figure it out
  208. X             which format sender uses. */
  209. X
  210. X          if ((cp = strchr(buffer, '<')) && (np = strchr(cp, '>')))
  211. X            {
  212. X              /* Format is 'From: Name <address>' */
  213. X              for (np = buffer + strlen(field),
  214. X           cnt = 0; np < cp - 1 && cnt < 35;
  215. X                   np++, cnt++)
  216. X                name[cnt] = *np;
  217. X              name[cnt] = 0;
  218. X              debug(2, "Got name %s, fmt name <address>", name);
  219. X            }
  220. X          else
  221. X            if ((cp = strchr(buffer, '(')) && (np = strchr(cp, ')')))
  222. X              {
  223. X                /* Format is 'From: address (Name)' */
  224. X                for (cnt = 0, cp++; cp < np && cnt < 35; cp++, cnt++)
  225. X                  name[cnt] = *cp;
  226. X                name[cnt] = 0;
  227. X                debug(2, "Got name %s, fmt address (name)", name);
  228. X              }
  229. X            else
  230. X              {
  231. X        debug(5, "Could no find realname in <> or ()");
  232. X        /* Try parse it with parse_address */
  233. X        if (parse_address(buffer + strlen(field), name, &dummynode))
  234. X          {
  235. X            (void) strncpy(name, buffer + strlen(field), 35);
  236. X            name[35] = 0;
  237. X            debug(2, "No format in %s, name %s", field, name);
  238. X          }
  239. X        else
  240. X          {
  241. X            name[35] = 0;
  242. X            debug(2, "Name %s parsed from address", name);
  243. X          }
  244. X              }
  245. X          return name;
  246. X        }
  247. X    }
  248. X
  249. X  /* If not searching for sender, don't try to use uid */
  250. X
  251. X  if (strcmp(field, "From: ")) return NULL;
  252. X
  253. X  /* hmm.. no From: field in mail. let's try to figure this problem
  254. X     out some other way. If our uid is some user's uid, we'll use
  255. X     that uid to show user's name, otherwise we'll return NULL. */
  256. X
  257. X  if (getuid() >= USERUID && (pwd = getpwuid( (int) getuid())))
  258. X    {
  259. X      /* There are two commonly used gecos-formats: So called USG
  260. X         format used by System III and System V machines and BSD
  261. X         format used by BSD machines. In USG format name is
  262. X         sandwitched between '-' and '(' characters and in BSD
  263. X         format name is first this in gecos-field up to first comma
  264. X         in it. In many machines there's only name in gecos. */
  265. X
  266. X      if ((cp = strchr(pwd->pw_gecos, '-')) && (np = strchr(cp, '(')))
  267. X        {
  268. X          /* USG format 'stuff-name(stuff)' */
  269. X          for (cnt = 0, cp++; cnt < 35 && cp < np; cp++, cnt++)
  270. X            name[cnt] = *cp;
  271. X          name[cnt] = 0;
  272. X          debug(3, "Got name from USG fmt, name %s", name);
  273. X        }
  274. X      else
  275. X        if (cp = strchr(pwd->pw_gecos, ','))
  276. X          {
  277. X            /* BSD format 'name,stuff...' */
  278. X            for (cp = buffer, cnt = 0; cnt < 35 && *cp != ','; cp++, cnt++)
  279. X              name[cnt] = *cp;
  280. X            name[cnt] = 0;
  281. X            debug(3, "Got name from BSD format, name %s", name);
  282. X          }
  283. X        else
  284. X          if (*pwd->pw_gecos)
  285. X            {
  286. X              /* non-empty gecos, assume that there's only name */
  287. X              (void) strncpy(name, pwd->pw_gecos, 35);
  288. X              name[35] = 0;
  289. X              debug(3, "No fmt in gecos, name %s", name);
  290. X            }
  291. X          else
  292. X            {
  293. X              /* Lazy administrator or user who want's to be anonymous
  294. X                 (or this is some administrative uid with no explanation
  295. X                 which)... We'll use only the username. */
  296. X
  297. X              (void) strncpy(name, pwd->pw_name, 35);
  298. X              /* never heard over 35 char usernames???? I haven't but... */
  299. X              name[35] = 0;
  300. X              debug(3, "No gecos, name = %s");
  301. X            }
  302. X      return name;
  303. X    }
  304. X
  305. X  *buffer = 0;
  306. X  if (cp = getenv("HOME"))
  307. X    {
  308. X      debug(5, "Try .fullname");
  309. X      if (fp = fopen(sprintfs("%s/%s", cp, ".fullname"), "r"))
  310. X    {
  311. X      if (!fgets(buffer, BUFSIZ, fp)) *buffer = 0;
  312. X      fclose(fp);
  313. X      strncpy(name, buffer, 35);
  314. X      if (!strempty(name))
  315. X        {
  316. X          strclean(name);
  317. X          debug(2, "Got name %s from .fullname", name);
  318. X          return name;
  319. X        }
  320. X      else
  321. X        debug(1, "Empty name '%s' in .fullname", name);
  322. X    }
  323. X      debug(5, "Try .realname");
  324. X      if (fp = fopen(sprintfs("%s/%s", cp, ".realname"), "r"))
  325. X    {
  326. X      if (!fgets(buffer, BUFSIZ, fp)) *buffer = 0;
  327. X      fclose(fp);
  328. X      strncpy(name, buffer, 35);
  329. X      if (!strempty(name))
  330. X        {
  331. X          strclean(name);
  332. X          debug(2, "Got name %s from .realname", name);
  333. X          return name;
  334. X        }
  335. X      else
  336. X        debug(1, "Empty name '%s' in .realname", name);
  337. X    }
  338. X    }
  339. X
  340. X  if (cp = getenv("NAME"))
  341. X    {
  342. X      debug(5, "Name defined, use it");
  343. X      strncpy(name, buffer, 35);
  344. X      if (!strempty(name))
  345. X    {
  346. X      strclean(name);
  347. X      debug(2, "Got name %s from environment NAME", name);
  348. X      return name;
  349. X    }
  350. X    }
  351. X
  352. X  /* Found nothing reasonable. we could put there path, but it's quite
  353. X     complicated to parse it and it's quite often more than 35 characters
  354. X     and partial paths are not very informative. Reader can figure
  355. X     it out by himself (or herself) and tell sender to use mailer... */
  356. X
  357. X  debug(2, "No name, uid = %d", getuid());
  358. X
  359. X  return (char *) 0;
  360. X}
  361. X
  362. X/* Get net/node information from info. If zone, net, or point are missing,
  363. X   they will be returned as -1True is returned, if
  364. X   everything went fine, otherwise False. */
  365. X
  366. Xbool
  367. Xgetnode(info, node)
  368. X     char *info;
  369. X     Node *node;
  370. X{
  371. X  /* Extract zone information */
  372. X  if (strchr(info, ':'))
  373. X    {
  374. X      for (node->zone = 0; *info != ':'; info++)
  375. X    if (isdigit(*info))
  376. X      node->zone = node->zone * 10 + *info - '0';
  377. X    else
  378. X      {
  379. X        debug(1, "Invalid character in zone '%c' %02x", *info, *info);
  380. X        return False;
  381. X      }
  382. X      info++;
  383. X    }
  384. X  else
  385. X    node->zone = -1;
  386. X
  387. X  /* Extract net information if net is present, otherwise
  388. X     set net to -1. */
  389. X
  390. X  if (strchr(info, '/'))
  391. X    {
  392. X      for (node->net = 0; *info != '/'; info++)
  393. X        if (isdigit(*info))
  394. X          node->net = node->net * 10 + *info - '0';
  395. X        else
  396. X          {
  397. X            debug(1, "Invalid character in net '%c' %02x", *info, *info);
  398. X            return False;
  399. X          }
  400. X      info++;
  401. X    }
  402. X  else
  403. X    node->net = -1;
  404. X
  405. X  /* Exract node information, set to -1 if empty. */
  406. X
  407. X  if (*info)
  408. X    for (node->node = 0; *info && *info != '.'; info++)
  409. X      if (isdigit(*info))
  410. X        node->node = node->node * 10 + *info - '0';
  411. X      else
  412. X        {
  413. X          debug(1, "Invalid characer in node '%c' %02x", *info, *info);
  414. X          return False;
  415. X        }
  416. X  else
  417. X    node->node = -1;
  418. X
  419. X  /* Exract point information, set to -1 if empty. */
  420. X
  421. X  if (*info)
  422. X    for (node->point = 0; *info; info++)
  423. X      if (isdigit(*info))
  424. X        node->point = node->point * 10 + *info - '0';
  425. X      else
  426. X        {
  427. X          debug(1, "Invalid characer in node '%c' %02x", *info, *info);
  428. X          return False;
  429. X        }
  430. X  else
  431. X    node->point = -1;
  432. X
  433. X  debug(2, "Got alias %s", ascnode(*node));
  434. X  return True;
  435. X}
  436. X
  437. X/* Compare receiver and user in aliasfile. Each line in aliasfile contains
  438. X   alias, optional net/node information separated by commas zero or
  439. X   more times, white space(s) and rest of the line literally to whom
  440. X   mail should be send. Net and node information is format 'net/node'.
  441. X   if net is omitted then every net is counted, if node is omitted,
  442. X   then all nodes in that net. If net is omitted, slash may be left off.
  443. X
  444. X   E.g following are valid aliases:
  445. X
  446. X   tot,504/ Teemu Torma
  447. X   foo Foo Bar
  448. X   sysop,504/1,504/9 System Operator */
  449. X
  450. Xbool
  451. Xaliascmp(alias, to, node)
  452. X     char *alias, *to;
  453. X     Node node;
  454. X{
  455. X  char buffer[BUFSIZ];
  456. X  char *cp;
  457. X  Node anode;
  458. X
  459. X  while (*alias && *alias != ',' && !isspace(*alias) && *to)
  460. X    if (*alias++ != *to++)
  461. X      return False;
  462. X
  463. X  if (isspace(*alias)) /* match */
  464. X    return True;
  465. X
  466. X  if (*alias == ',')
  467. X    {
  468. X      /* copy alias to buffer and terminate the it after first space */
  469. X      (void) strcpy(buffer, alias + 1);
  470. X      for (cp = buffer; *cp; cp++)
  471. X        if (isspace(*cp))
  472. X          {
  473. X            *cp = 0;
  474. X            break;
  475. X          }
  476. X
  477. X      /* get net/node information from buffer one at the time */
  478. X      for (cp = strtok(buffer, ","); cp; cp = strtok((char *) 0, ","))
  479. X        {
  480. X          debug(2, "Got node '%s'", cp);
  481. X          if (getnode(cp, &anode))
  482. X            {
  483. X              if ((anode.zone == -1 || anode.zone == node.zone) &&
  484. X          (anode.net == -1 || anode.net == node.net) &&
  485. X          (anode.node == -1 || anode.node == node.node) &&
  486. X          (anode.point == -1 || anode.point == node.point))
  487. X                return True;
  488. X            }
  489. X          else
  490. X            return False;
  491. X        }
  492. X    }
  493. X  else
  494. X    debug(1, "Invalid alias, %c is not ',' or white space", *alias);
  495. X
  496. X  return False;
  497. X}
  498. X
  499. X/* Return receiver's name. If name is aliased, return it, otherwise
  500. X   return receiver's name. */
  501. X
  502. Xchar *
  503. Xreceiver(to, node)
  504. X     char *to;
  505. X     Node node;
  506. X{
  507. X  static char name[36];
  508. X  char buffer[BUFSIZ];
  509. X  register int cnt;
  510. X  register char *cp;
  511. X  FILE *fp;
  512. X
  513. X  if (fp = fopen(ALIAS, "r"))
  514. X    {
  515. X      while (fgets(buffer, BUFSIZ, fp))
  516. X        {
  517. X          buffer[strlen(buffer) - 1] = 0;
  518. X          if (*buffer != '#')
  519. X            debug(3, "Checking for alias %s", buffer);
  520. X          if (*buffer != '#' && aliascmp(buffer, to, node))
  521. X            {
  522. X              /* match, save the alias. */
  523. X              for (cp = buffer; *cp && !isspace(*cp); cp++)
  524. X                /* skip alias itself */;
  525. X              while (isspace(*cp))
  526. X                cp++;
  527. X              if (*cp)
  528. X                {
  529. X                  for (cnt = 0; *cp && cnt < 35; cnt++, cp++)
  530. X                    name[cnt] = *cp;
  531. X                  name[cnt] = 0;
  532. X                  debug(2, "Got alias %s", name);
  533. X                  return name;
  534. X                }
  535. X              else
  536. X                debug(1, "Missing alias");
  537. X            }
  538. X        }
  539. X      (void) fclose(fp);
  540. X    }
  541. X  else
  542. X    log("$Unable to open aliasfile %s", ALIAS);
  543. X
  544. X  /* Alias not found. Return the the original receiver with all
  545. X     _-characters replaced by space and all words calitalized. */
  546. X
  547. X  for (cp = NULL, cnt = 0; *to && cnt < 35; cnt++, cp = to++)
  548. X    {
  549. X      if (*to == '_')
  550. X        name[cnt] = ' ';
  551. X      else
  552. X        if (!cp || *cp == '_' || *to == ' ')
  553. X          name[cnt] = toupper(*to);
  554. X        else
  555. X          name[cnt] = tolower(*to);
  556. X    }
  557. X  name[cnt] = 0;
  558. X  debug(2, "No alias, name %s", name);
  559. X  return name;
  560. X}
  561. X
  562. X/* Return receiver's name, took Comment-To: field. If not found,
  563. X   call receiver() and return what it returns */
  564. X
  565. Xchar *newsreceiver(fp, to, node)
  566. X     FILE *fp;
  567. X     char *to;
  568. X     Node node;
  569. X{
  570. X  char *cp;
  571. X
  572. X  debug(2, "Checking To: field");
  573. X  if (cp = sender(fp, "To: "))
  574. X    {
  575. X      debug(1, "Got recipent %s from To: field", cp);
  576. X      strcpy(to, cp);
  577. X    }
  578. X  else
  579. X    {
  580. X      debug(2, "Checking Comment-To: field");
  581. X      if (cp = sender(fp, "Comment-To: "))
  582. X    {
  583. X      debug(1, "Got recipent %s from Comment-To field", cp);
  584. X      strcpy(to, cp);
  585. X    }
  586. X    }
  587. X
  588. X  return receiver(to, node);
  589. X}
  590. X
  591. X/* Get date from mail. Look for Date: field, if present and time is in
  592. X   correct format (same than ARPA-net mail uses), it will be used, otherwise
  593. X   current time will be taken. */
  594. X
  595. Xchar *
  596. Xlgetdate(fp)
  597. X     FILE *fp;
  598. X{
  599. X  time_t timevar;
  600. X  struct tm *localtime();
  601. X  struct tm *mtime;
  602. X  static char timebuf[20];
  603. X  char buffer[BUFSIZ];
  604. X  /* literal months */
  605. X  static char *months[] = {
  606. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  607. X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  608. X    (char *) 0,
  609. X  };
  610. X  /* Literal weekdays */
  611. X  static char *wkdays[] = {
  612. X    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", (char *) 0,
  613. X  };
  614. X
  615. X  (void) rewind(fp);
  616. X  while (fgets(buffer, BUFSIZ, fp))
  617. X    /* did we find Date: */
  618. X    if (!strncmp(buffer, "Date: ", 6))
  619. X      {
  620. X    buffer[strlen(buffer) - 1] = '\0';
  621. X        /* try to extract date and other information from it */
  622. X        debug(2, "Found date: '%s'", buffer + 6);
  623. X#ifdef OLD_VERSION
  624. X        if (sscanf(buffer + 6, "%3s, %2d %3s %2d %2d:%2d:%*2d %*s",
  625. X           wday, &mday, month, &year, &hour, &min) == 6)
  626. X          {
  627. X            debug(2, "Correct date format");
  628. X            /* save date in SEAdog format */
  629. X            (void) sprintf(timebuf, "%3s %2d %3s %2d %02d:%02d",
  630. X                           wday, mday, month, year, hour, min);
  631. X            return timebuf;
  632. X          }
  633. X#else
  634. X    timevar = getdate(buffer + 6, (struct timeb *) NULL);
  635. X    debug(2, "timevar %ld", timevar);
  636. X    mtime = localtime(&timevar);
  637. X    /* Save date in SEAdog format */
  638. X    (void) sprintf(timebuf, "%3s %2d %3s %2d %02d:%02d",
  639. X               wkdays[mtime->tm_wday], mtime->tm_mday,
  640. X               months[mtime->tm_mon], mtime->tm_year,
  641. X               mtime->tm_hour, mtime->tm_min);
  642. X    debug(1, "Returning %s", timebuf);
  643. X    return timebuf;
  644. X#endif
  645. X      }
  646. X
  647. X  (void) rewind(fp);
  648. X  debug(2, "No Date: field in mail");
  649. X
  650. X  /* we did not found Date: field, let's use current time */
  651. X  return date("%a %d %h %y %T", (long *) NULL);
  652. X}
  653. X
  654. X/* Send mail from filepoiner fp to user to. To is in format of
  655. X   net!node!receiver, where net and node are destnation and
  656. X   receiver is receivers name in which blankos are replaces by
  657. X   _-characters or alias. */
  658. X
  659. Xint
  660. Xsendmail(fp, to)
  661. X     FILE *fp;
  662. X     char *to;
  663. X{
  664. X  char buffer[BUFSIZ], *cp;
  665. X  FILE *sf;
  666. X  char *sfile;
  667. X  char hostname[10];
  668. X  Node node;
  669. X  char name[36];
  670. X  int status, nodate, nosubject, nofrom;
  671. X
  672. X  (void) gethostname(hostname, 10);
  673. X
  674. X  /* get receiver and net/node */
  675. X  if (cp = parse_address(to, name, &node))
  676. X    {
  677. X      sendback(fp, "Parse failed: %s", cp);
  678. X      return EX_NOHOST;
  679. X    }
  680. X
  681. X  debug(1, "Sending mail to %s at %s", name, ascnode(node));
  682. X
  683. X  if ((status = valid_netnode(name, node, fp)) != EX_OK)
  684. X    return status;
  685. X
  686. X  debug(1, "Netnode ok, opening spool file");
  687. X
  688. X  if (sf = fopen(sfile = spoolfile("M."), "w"))
  689. X    {
  690. X      /* set correct permissions for spoolfile and lock it */
  691. X      (void) chmod(sfile, 0600);
  692. X      (void) lock(fileno(sf));
  693. X
  694. X      debug(1, "chmod and lock ok");
  695. X
  696. X      /* save net and node information */
  697. X      (void) fprintf(sf, "N %s\n", ascnode(node));
  698. X
  699. X      /* save receiver. If using newsreceiver seem to cause
  700. X     trouble, use normal receiver if not in news mode */
  701. X
  702. X      (void) fprintf(sf, "T %s\n", newsreceiver(fp, name, node));
  703. X
  704. X      /* save sender ... */
  705. X      debug(10, "Trying to find sender (From)");
  706. X      (void) fprintf(sf, "F %s\n", (cp = sender(fp, "From: ")) ?
  707. X             cp : "Usenet");
  708. X
  709. X      /* try to find subject ... */
  710. X      (void) rewind(fp);
  711. X      while (fgets(buffer, BUFSIZ, fp))
  712. X        if (!strncmp("Subject: ", buffer, 9))
  713. X          {
  714. X            (void) fprintf(sf, "S %s", buffer + 9);
  715. X            buffer[strlen(buffer) - 1] = 0;
  716. X            debug(2, "Subject: %s", buffer + 9);
  717. X            break;
  718. X          }
  719. X
  720. X      if (feof(fp))
  721. X        /* we didn't find subject.. */
  722. X        (void) fprintf(sf, "S Mail from Usenet\n");
  723. X
  724. X      /* save date */
  725. X      (void) fprintf(sf, "D %s\n", lgetdate(fp));
  726. X
  727. X      /* if not public, mark that message is private */
  728. X      if (!public)
  729. X        (void) fprintf(sf, "P \n");
  730. X
  731. X      /* done with header information, now we'll copy the hole mail
  732. X         after the header */
  733. X
  734. X      (void) putc('\n', sf);
  735. X
  736. X      debug(2, "Copying mail");
  737. X
  738. X      /* Now copy mail, also add Received field to mail */
  739. X      (void) rewind(fp);
  740. X      while (fgets(buffer, BUFSIZ, fp) && (!strncmp(buffer, "From ", 5) ||
  741. X                                           !strncmp(buffer, ">From ", 6) ||
  742. X                       !strncmp(buffer, "AREA:", 5)))
  743. X    (void) fputs(buffer, sf);
  744. X
  745. X      (void) fprintf(sf, "Received: from %s%s by %s (%s%s/%s)\n",
  746. X             hostname, DOMAIN, internode(this), "rfmail",
  747. X             version, this.name);
  748. X      (void) fprintf(sf, "\tid AA%05d; %s\n", getpid(),
  749. X                     date("%a, %d %h %y %T %o (%z)", (long *) NULL));
  750. X
  751. X      /* Copy header. Try to avoid duplicating headers already in
  752. X     fidonet header. Only first occurence of header is processed,
  753. X     others will be ignored. Header is considered to end at first
  754. X     empty line. */
  755. X
  756. X      nodate = TRUE;
  757. X      nosubject = TRUE;
  758. X      nofrom = TRUE;
  759. X      do {
  760. X
  761. X    /* Date is in mail header, so skip header Date: */
  762. X    if (nodate)
  763. X      if (!strncmp(buffer, "Date:", 5))
  764. X        {
  765. X          nodate = FALSE;
  766. X          continue;
  767. X        }
  768. X
  769. X    /* Print subject only if it doesnt fit in fidonet header correctly */
  770. X    if (nosubject)
  771. X      if (!strncmp(buffer, "Subject:", 8))
  772. X        {
  773. X          if (strlen(buffer + 8) > 72)
  774. X        fputs(buffer, sf);
  775. X          nosubject = FALSE;
  776. X          continue;
  777. X        }
  778. X
  779. X    /* Print From field only if it doesn't fit in fidonet header */
  780. X    if (nofrom)
  781. X      if (!strncmp(buffer, "From:", 5))
  782. X        {
  783. X          if (strlen(buffer + 5) > 36)
  784. X        fputs(buffer, sf);
  785. X          nofrom = FALSE;
  786. X          continue;
  787. X        }
  788. X
  789. X    fputs(buffer, sf);
  790. X      } while (fgets(buffer, BUFSIZ, fp));
  791. X
  792. X      /* done. */
  793. X      (void) fclose(sf);
  794. X      return EX_OK;
  795. X    }
  796. X  else
  797. X    {
  798. X      log("$Unable to open spoolfile");
  799. X      return EX_CANTCREAT;
  800. X    }
  801. X  /* NOTREACHED */
  802. X}
  803. X
  804. X/*ARGSUSED*/
  805. Xint
  806. Xmain(argc, argv, envp)
  807. X     int argc;
  808. X     char **argv, **envp;
  809. X{
  810. X  int cnt, c;
  811. X  FILE *mail;
  812. X  char buffer[BUFSIZ], tmpf[L_tmpnam];
  813. X  int status = EX_OK;
  814. X  char *error;
  815. X  Node *node, mynode;
  816. X
  817. X  newsmode = FALSE;
  818. X  while ((c = getopt(argc, argv, "npvV:")) != EOF)
  819. X    switch (c)
  820. X      {
  821. X       case 'n':
  822. X    /* Set news-mode */
  823. X    newsmode = TRUE;
  824. X    break;
  825. X      case 'v':
  826. X        /* set more verbosity */
  827. X        verbose++;
  828. X        break;
  829. X      case 'V':
  830. X        /* allow version on command line only if test version. */
  831. X        if (*version != '%' || version[1] != 'I' || version[2] != '%')
  832. X          version = optarg;
  833. X        /* NOTE: Comparison cannot be with strcmp, because SCCS would also
  834. X           change that comparison string. */
  835. X        break;
  836. X      case 'p':
  837. X        /* this is not private message */
  838. X        public = True;
  839. X        break;
  840. X      default:
  841. X        (void) fprintf(stderr, "See manual page.\n", *argv);
  842. X        exit(EX_USAGE);
  843. X      }
  844. X
  845. X  /* create name of temporary mail-message */
  846. X  (void) strcpy(tmpf, P_tmpdir);
  847. X  (void) strcat(tmpf, mktemp("rfm.XXXXXX"));
  848. X
  849. X  /* open mail-temp */
  850. X  if (mail = fopen(tmpf, "w+"))
  851. X    {
  852. X      /* protect mail file */
  853. X      (void) chmod(tmpf, 0600);
  854. X
  855. X      /* copy mail to temp-file */
  856. X      while (fgets(buffer, BUFSIZ, stdin))
  857. X        (void) fputs(buffer, mail);
  858. X
  859. X      /* update nodelist-index if needed */
  860. X      if (error = update_index())
  861. X        {
  862. X          /* there was error while updating nodelist-index */
  863. X          if (*error == '$')
  864. X            sendback(mail, "%s: %s", error + 1, sys_errlist[errno]);
  865. X          else
  866. X            sendback(mail, "%s", error);
  867. X          exit(EX_SOFTWARE);
  868. X        }
  869. X
  870. X      mynode.zone = MY_ZONE;
  871. X      mynode.net = MY_NET;
  872. X      mynode.node = MY_NODE;
  873. X      mynode.point = MY_POINT;
  874. X      if ((node = node_entry(mynode)) == NULL)
  875. X        {
  876. X          (void) fprintf(stderr, "Unable to this node from nodelist\n");
  877. X          log("No %s in nodelist", ascnode(mynode));
  878. X          exit(EX_SOFTWARE);
  879. X        }
  880. X      this = *node;
  881. X
  882. X
  883. X      /* send mail to all user's */
  884. X      for (rewind(mail), cnt = optind; cnt < argc; rewind(mail), cnt++)
  885. X          /* send mail */
  886. X          if ((status = sendmail(mail, argv[cnt])) != EX_OK)
  887. X            break;
  888. X
  889. X      /* remove temporary file */
  890. X      (void) fclose(mail);
  891. X      (void) unlink(tmpf);
  892. X    }
  893. X  else
  894. X    {
  895. X      /* opening tmp-file failed, we can't even send mail back */
  896. X      log("$Can not open %s for writing", tmpf);
  897. X      exit(EX_CANTCREAT);
  898. X    }
  899. X
  900. X  exit(status);
  901. X  /*NOTREACHED*/
  902. X}
  903. SHAR_EOF
  904. echo "File rfmail.c is complete"
  905. chmod 0644 rfmail.c || echo "restore of rfmail.c fails"
  906. echo "x - extracting funcs.c (Text)"
  907. sed 's/^X//' << 'SHAR_EOF' > funcs.c &&
  908. X#ifndef lint
  909. Xstatic char *sccsid = "@(#)%M%  %I%  Teemu Torma %H%";
  910. X#endif
  911. X
  912. X/* Miscancelleus functions, logging, sequence numberic etc.
  913. X
  914. X   @(#)Copyright (c) 1987 by Teemu Torma
  915. X
  916. X   Permission is given to distribute this program and alter this code as
  917. X   needed to adapt it to forign systems provided that this header is
  918. X   included and that the original author's name is preserved. */
  919. X
  920. X/* LINTLIBRARY */
  921. X
  922. X#include <stdio.h>
  923. X#include <string.h>
  924. X#include <ctype.h>
  925. X#include <varargs.h>
  926. X#include <unistd.h>
  927. X#include <sys/types.h>
  928. X#include <time.h>
  929. X#include <sys/utsname.h>
  930. X#include <errno.h>
  931. X#include "hsu.h"
  932. X#include "config.h"
  933. X#include "fnet.h"
  934. X#include "sysexits.h"
  935. X#include "nodelist.h"
  936. X#include "shuffle.h"
  937. X
  938. X#define labs(n) (((n) < 0l) ? (-(n)) : (n))
  939. X
  940. Xextern void exit(), perror();
  941. Xextern long atol();
  942. Xextern time_t time();
  943. Xextern int errno;
  944. Xextern char *sys_errlist[];
  945. X
  946. XFILE *logfp = NULL;
  947. X
  948. X/* Lock file descriptor up to the end. If yur system doesn't have lockf()
  949. X   (also known as locking()), or other region or file locking function
  950. X   or system call, this should be done with lock-files. */
  951. X
  952. Xint
  953. Xlock(fd)
  954. X     int fd;
  955. X{
  956. X#ifdef LOCK_LOCKF
  957. X  return lockf(fd, F_LOCK, 0l);
  958. X#else
  959. X  return locking(fd, F_LOCK, 0l);
  960. X#endif
  961. X}
  962. X
  963. X/* Unlock file descriptor up to the end. Routine which calls this should
  964. X   first seek to original position. */
  965. X
  966. Xint
  967. Xunlock(fd)
  968. X     int fd;
  969. X{
  970. X#ifdef LOCK_LOCKF
  971. X  return lockf(fd, F_ULOCK, 0l);
  972. X#else
  973. X  return locking(fd, F_ULOCK, 0l);
  974. X#endif
  975. X}
  976. X
  977. X/* Return ascii-date in specified format. If format string is null, return
  978. X   date as date(1) returns it. Format is same than date(1) has, in addition
  979. X   %z, which means timezone name. Clock is the time to convert, if NULL,
  980. X   we'll use current time. */
  981. X
  982. Xchar *
  983. Xdate(fmt, clock)
  984. X     char *fmt;
  985. X     time_t *clock;
  986. X{
  987. X  /* names for weekdays */
  988. X  static char *weekdays[] = {
  989. X    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
  990. X  };
  991. X
  992. X  /* names for months */
  993. X  static char *months[] = {
  994. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  995. X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  996. X  };
  997. X
  998. X  static char buffer[80];
  999. X  char *bp = buffer;
  1000. X  time_t _clock;
  1001. X  struct tm *tm;
  1002. X
  1003. X  if (!clock)
  1004. X    _clock = time((long *) 0);
  1005. X  tm = localtime(clock ? clock : &_clock);
  1006. X
  1007. X  /* if no format string, this is default */
  1008. X  if (!fmt)
  1009. X    fmt = "%a %h %d %T %z 19%y";
  1010. X
  1011. X  for (*bp = 0; *fmt; fmt++)
  1012. X    switch (*fmt)
  1013. X      {
  1014. X      case '%':
  1015. X        switch (*++fmt)
  1016. X          {
  1017. X            /* newline */
  1018. X          case 'n':
  1019. X            *bp++ = '\n';
  1020. X            break;
  1021. X            /* tabulator */
  1022. X          case 't':
  1023. X            *bp++ = '\t';
  1024. X            break;
  1025. X            /* month number 1-12 */
  1026. X          case 'm':
  1027. X            (void) sprintf(bp, "%02d", tm->tm_mon + 1);
  1028. X            while (*bp)
  1029. X              bp++;
  1030. X            break;
  1031. X            /* day of month 1-31 */
  1032. X          case 'd':
  1033. X            (void) sprintf(bp, "%2d", tm->tm_mday);
  1034. X            while (*bp)
  1035. X              bp++;
  1036. X            break;
  1037. X          case 'q':
  1038. X            (void) sprintf(bp, "%02d", tm->tm_mday);
  1039. X            while (*bp)
  1040. X              bp++;
  1041. X            break;
  1042. X            /* year 00-99 */
  1043. X          case 'y':
  1044. X            (void) sprintf(bp, "%02d", tm->tm_year);
  1045. X            while (*bp)
  1046. X              bp++;
  1047. X            break;
  1048. X            /* date in format YY/MM/DD */
  1049. X          case 'D':
  1050. X            (void) sprintf(bp, "%02d/%02d/%02d", tm->tm_year,
  1051. X                           tm->tm_mon + 1, tm->tm_mday);
  1052. X            while (*bp)
  1053. X              bp++;
  1054. X            break;
  1055. X            /* hour 0-23 */
  1056. X          case 'H':
  1057. X            (void) sprintf(bp, "%02d", tm->tm_hour);
  1058. X            while (*bp)
  1059. X              bp++;
  1060. X            break;
  1061. X            /* minutes 0-59 */
  1062. X          case 'M':
  1063. X            (void) sprintf(bp, "%02d", tm->tm_min);
  1064. X            while (*bp)
  1065. X              bp++;
  1066. X            break;
  1067. X            /* seconds 0-59 */
  1068. X          case 'S':
  1069. X            (void) sprintf(bp, "%02d", tm->tm_sec);
  1070. X            while (*bp)
  1071. X              bp++;
  1072. X            break;
  1073. X            /* time in format HH:MM:SS */
  1074. X          case 'T':
  1075. X            (void) sprintf(bp, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
  1076. X                           tm->tm_sec);
  1077. X            while (*bp)
  1078. X              bp++;
  1079. X            break;
  1080. X            /* day of year 1-356 */
  1081. X          case 'j':
  1082. X            (void) sprintf(bp, "%03d", tm->tm_yday + 1);
  1083. X            while (*bp)
  1084. X              bp++;
  1085. X            break;
  1086. X            /* weekday 0-6 */
  1087. X          case 'w':
  1088. X            (void) sprintf(bp, "%d", tm->tm_wday);
  1089. X            while (*bp)
  1090. X              bp++;
  1091. X            break;
  1092. X            /* name of weekday 'Mon', 'Tue', ... , 'Sun' */
  1093. X          case 'a':
  1094. X            (void) strcpy(bp, weekdays[tm->tm_wday]);
  1095. X            while (*bp)
  1096. X              bp++;
  1097. X            break;
  1098. X            /* name of month 'Jan', 'Feb', ... , 'Dec' */
  1099. X          case 'h':
  1100. X            (void) strcpy(bp, months[tm->tm_mon]);
  1101. X            while (*bp)
  1102. X              bp++;
  1103. X            break;
  1104. X            /* name of timezone, e.g. EST */
  1105. X          case 'z':
  1106. X            (void) strcpy(bp, *tzname);
  1107. X            while (*bp)
  1108. X              bp++;
  1109. X            break;
  1110. X            /* numeric time zone, e.g. +0200 */
  1111. X          case 'o':
  1112. X            (void) sprintf(bp, "%c%02ld%02ld", (timezone <= 0l) ? '+' : '-',
  1113. X                           (labs(timezone) / (60l * 60l)),
  1114. X                           (labs(timezone) % (60l * 60l)));
  1115. X            while (*bp)
  1116. X              bp++;
  1117. X            break;
  1118. X          case 'l':
  1119. X            /* military time zone, Z = UT, A = -1, M = -12, (J not used),
  1120. X               N = +1, Y = +12.. */
  1121. X            *bp = (timezone == 0l) ? 'Z' : ((int) (labs(timezone) /
  1122. X                                                   (60l * 60l)) +
  1123. X                                            ((timezone < 0l) ? 'M' : '@'));
  1124. X            if (timezone > 0l && *bp >= 'J')
  1125. X              (*bp)++;
  1126. X            *++bp = 0;
  1127. X            break;
  1128. X          default:
  1129. X            *bp++ = *fmt;
  1130. X            break;
  1131. X          }
  1132. X        break;
  1133. X      default:
  1134. X        *bp++ = *fmt;
  1135. X        break;
  1136. X      }
  1137. X
  1138. X  *bp = 0;
  1139. X  return buffer;
  1140. X}
  1141. X
  1142. X/* Log to logfile. If logfile is not open, open it.
  1143. X
  1144. X   If first character in format string is '$', print also errno. If external
  1145. X   variable verbose is set, logging will be done also to stderr. */
  1146. X
  1147. X/* VARARGS */
  1148. Xvoid
  1149. Xlog(va_alist)
  1150. X     va_dcl
  1151. X{
  1152. X  va_list args;
  1153. X  char *fmt;
  1154. X  int eno = errno;
  1155. X
  1156. X  va_start(args);
  1157. X
  1158. X  fmt = va_arg(args, char *);
  1159. X
  1160. X  if (!logfp)
  1161. X    if ((logfp = fopen(LOGFILE, "a")) == NULL)
  1162. X      {
  1163. X    perror("Cannot open log file");
  1164. X    return;
  1165. X      }
  1166. X
  1167. X  (void) fprintf(logfp, "%s: ", date("%a, %d %h %y %T %o", (long *) 0));
  1168. X  (void) vfprintf(logfp, *fmt == '$' ? fmt + 1 : fmt, args);
  1169. X  if (*fmt == '$')
  1170. X    (void) fprintf(logfp, " errno = %d (%s)\n", eno, sys_errlist[eno]);
  1171. X  else
  1172. X    (void) fprintf(logfp, "\n");
  1173. X  (void) fflush(logfp);
  1174. X
  1175. X  /* if verbose is set, print also to stderr */
  1176. X  if (verbose)
  1177. X    {
  1178. X      (void) vfprintf(stderr, fmt + (*fmt == '$'), args);
  1179. X      if (*fmt == '$')
  1180. X        (void) fprintf(stderr, " errno = %d (%s)\n", eno,
  1181. X                       sys_errlist[eno]);
  1182. X      else
  1183. X        (void) fprintf(stderr, "\n");
  1184. X      (void) fflush(stderr);
  1185. X    }
  1186. X
  1187. X  va_end(args);
  1188. X}
  1189. X
  1190. X/* Debug output. First argument should be number, rest are used arguments
  1191. X   for vfprintf(3S). If external variable verbose has equal or greater
  1192. X   value than first number, vfprintf(3S) will be used to print other
  1193. X   arguments to stderr. */
  1194. X
  1195. X/* VARARGS */
  1196. Xvoid
  1197. Xdebug(va_alist)
  1198. X     va_dcl
  1199. X{
  1200. X  va_list args;
  1201. X  char *fmt;
  1202. X  int debug_level;
  1203. X
  1204. X  va_start(args);
  1205. X
  1206. X  debug_level = va_arg(args, int);
  1207. X  fmt = va_arg(args, char *);
  1208. X
  1209. X  if (debug_level <= verbose)
  1210. X    {
  1211. X      if (*fmt != '>' && *fmt != '<')
  1212. X    (void) fprintf(stderr, "\n%ld: ", time( (long *) NULL));
  1213. X      (void) vfprintf(stderr, fmt, args);
  1214. X    }
  1215. X
  1216. X  va_end(args);
  1217. X}
  1218. X
  1219. X/* Get next job number. New sequemnt number will be taken from file
  1220. X   LIBDIR/seq, which is in ascii-format and new number will be saved
  1221. X   back there. */
  1222. X
  1223. Xlong
  1224. Xjob_number()
  1225. X{
  1226. X  char seqfile[128], buffer[14];
  1227. X  FILE *fp;
  1228. X  long seqn = 0;
  1229. X
  1230. X  (void) sprintf(seqfile, "%s/seq", LIBDIR);
  1231. X  if (fp = fopen(seqfile, "r+"))
  1232. X    {
  1233. X      (void) lock(fileno(fp));
  1234. X      if (fgets(buffer, 14, fp))
  1235. X        seqn = atol(buffer);
  1236. X      seqn++;
  1237. X      (void) rewind(fp);
  1238. X      (void) fprintf(fp, "%ld\n", seqn);
  1239. X      (void) unlock(fileno(fp));
  1240. X      (void) fclose(fp);
  1241. X    }
  1242. X  else
  1243. X    {
  1244. X      log("$Can not open seq-file %s", seqfile);
  1245. X      exit(EX_OSFILE);
  1246. X    }
  1247. X  return seqn;
  1248. X}
  1249. X
  1250. X/* General sequencer */
  1251. X
  1252. Xlong
  1253. Xsequencer(filename)
  1254. X     char *filename;
  1255. X{
  1256. X  char seqfile[128], buffer[14];
  1257. X  FILE *fp;
  1258. X  long seqn = 0;
  1259. X
  1260. X  (void) sprintf(seqfile, "%s", filename);
  1261. X  if ((fp = fopen(seqfile, "r+")) == NULL)
  1262. X    {
  1263. X      if (errno == ENOENT)
  1264. X    {
  1265. X      if ((fp = fopen(seqfile, "w+")) == NULL)
  1266. X        {
  1267. X          log("$Can not create seq-file %s", seqfile);
  1268. X          exit(EX_OSFILE);
  1269. X        }
  1270. X      fputs("1", fp);
  1271. X      fclose(fp);
  1272. X      if ((fp = fopen(seqfile, "r+")) == NULL)
  1273. X        {
  1274. X          log("$Can not open new seq-file %s", seqfile);
  1275. X          exit(EX_OSFILE);
  1276. X        }
  1277. X    }
  1278. X      else
  1279. X    {
  1280. X      log("$Can not open seq-file %s", seqfile);
  1281. X      exit(EX_OSFILE);
  1282. X    }
  1283. X    }
  1284. X
  1285. X  (void) lock(fileno(fp));
  1286. X  if (fgets(buffer, 14, fp))
  1287. X    seqn = atol(buffer);
  1288. X  else
  1289. X    seqn = 0; /* This can theoretically fail */
  1290. X
  1291. X  seqn++;
  1292. X  (void) rewind(fp);
  1293. X  (void) fprintf(fp, "%ld\n", seqn);
  1294. X  (void) unlock(fileno(fp));
  1295. X  (void) fclose(fp);
  1296. X  return seqn;
  1297. X}
  1298. X
  1299. X/* Returns current last sequence number */
  1300. Xlong
  1301. Xgetsequencer(filename)
  1302. X     char *filename;
  1303. X{
  1304. X  char seqfile[128], buffer[14];
  1305. X  FILE *fp;
  1306. X  long seqn = 0;
  1307. X
  1308. X  (void) sprintf(seqfile, "%s", filename);
  1309. X  if ((fp = fopen(seqfile, "r+")) == NULL)
  1310. X    {
  1311. X      if (errno == ENOENT)
  1312. X    {
  1313. X      if ((fp = fopen(seqfile, "w+")) == NULL)
  1314. X        {
  1315. X          log("$Can not create seq-file %s", seqfile);
  1316. X          exit(EX_OSFILE);
  1317. X        }
  1318. X      fputs("1", fp);
  1319. X      fclose(fp);
  1320. X      if ((fp = fopen(seqfile, "r+")) == NULL)
  1321. X        {
  1322. X          log("$Can not open new seq-file %s", seqfile);
  1323. X          exit(EX_OSFILE);
  1324. X        }
  1325. X    }
  1326. X      else
  1327. X    {
  1328. X      log("$Can not open seq-file %s", seqfile);
  1329. X      exit(EX_OSFILE);
  1330. X    }
  1331. X    }
  1332. X
  1333. X  (void) lock(fileno(fp));
  1334. X  if (fgets(buffer, 14, fp))
  1335. X    seqn = atol(buffer);
  1336. X  else
  1337. X    seqn = 0; /* This can theoretically fail */
  1338. X
  1339. X  (void) unlock(fileno(fp));
  1340. X  (void) fclose(fp);
  1341. X  return seqn;
  1342. X}
  1343. X
  1344. X/* Get full pathname for spoolfile with new job number. File is in
  1345. X   spool directory and contains prefix followed by four digit
  1346. X   job number. */
  1347. X
  1348. Xchar *
  1349. Xspoolfile(prefix)
  1350. X     char *prefix;
  1351. X{
  1352. X  static char file[BUFLEN];
  1353. X
  1354. X  (void) sprintf(file, "%s/%s%08ld", SPOOL, prefix, job_number());
  1355. X  return file;
  1356. X}
  1357. X
  1358. X/* Return basename of s */
  1359. X
  1360. Xchar *
  1361. Xbasename(s)
  1362. X     register char *s;
  1363. X{
  1364. X  register char *p = s;
  1365. X
  1366. X  while (*s)
  1367. X    if (*s++ == '/')
  1368. X      p = s;
  1369. X  return p;
  1370. X}
  1371. X
  1372. X/* Open file with directory name and filename. */
  1373. X
  1374. XFILE *
  1375. Xpfopen(dir, name, mode)
  1376. X     char *dir, *name, *mode;
  1377. X{
  1378. X  char filename[128];
  1379. X
  1380. X  (void) strcpy(filename, dir);
  1381. X  (void) strcat(filename, "/");
  1382. X  (void) strcat(filename, name);
  1383. X
  1384. X  return fopen(filename, mode);
  1385. X}
  1386. X
  1387. Xchar *baseit(n)
  1388. X     long n;
  1389. X{
  1390. X  static char tab[] =
  1391. X    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  1392. X  int count = 0;
  1393. X
  1394. X  SHUFFLEBUFFERS;
  1395. X
  1396. X  while (n)
  1397. X    {
  1398. X      tcharp[count] = tab[n % strlen(tab)];
  1399. X      n = n / strlen(tab);
  1400. X      count++;
  1401. X    }
  1402. X
  1403. X  tcharp[count] = 0;
  1404. X  return tcharp;
  1405. X}
  1406. X
  1407. X/* Create packet name for node given */
  1408. X
  1409. Xsprintpacketname(s, node)
  1410. X     char *s;
  1411. X     Node node;
  1412. X{
  1413. X  sprintf(s, "%s%s.%s.%s", node.point ?
  1414. X      sprintfs("%s.", baseit( (long) node.point)) : "",
  1415. X      baseit( (long) node.node), baseit( (long) node.net),
  1416. X      baseit( (long) node.zone));
  1417. X}
  1418. X
  1419. X/* Create packet name for inbound xx.xx.xx.xx.num. If point
  1420. X   number is 0, don't include it. All numbers are in ~63-base to squeeze
  1421. X   them to as small space as possible. It could be more sensible solution
  1422. X   to make them directory trees but I would need more time for that. This
  1423. X   trick makes finding packets difficult.
  1424. X   */
  1425. X
  1426. Xsprintipacketname(s, node)
  1427. X     char *s;
  1428. X     Node node;
  1429. X{
  1430. X  sprintf(s, "%s%s.%s.%s.%s", node.point ?
  1431. X      sprintfs("%s.", baseit( (long) node.point)) : "",
  1432. X      baseit( (long) node.node), baseit( (long) node.net),
  1433. X      baseit( (long) node.zone), baseit(sequencer(IPACKETSEQUENCE)));
  1434. X}
  1435. X
  1436. X/* Get line from config file. If *-character is in first column, report
  1437. X   EOF, and otherwise return line with comments stripped. This causes
  1438. X   effect, that each section in configuration file looks like it's own
  1439. X   file. Arguments and return value are the same than with fgets(3S). */
  1440. X
  1441. Xchar *
  1442. Xgetcl(buffer, len, fp)
  1443. X     char *buffer;
  1444. X     int len;
  1445. X     FILE *fp;
  1446. X{
  1447. X  char *cp;
  1448. X
  1449. X  while (fgets(buffer, len, fp))
  1450. X    {
  1451. X      buffer[strlen(buffer) - 1] = 0;
  1452. X      if (*buffer == '*')
  1453. X        return (char *) NULL;
  1454. X      /* everything after #-sign is comment */
  1455. X      if (cp = strchr(buffer, '#'))
  1456. X        *cp = 0;
  1457. X      /* if there's something left, return it */
  1458. X      if (*buffer)
  1459. X        return buffer;
  1460. X    }
  1461. X  return (char *) NULL;
  1462. X}
  1463. X
  1464. X/* Scan config file to specified section. This mechanism is not very
  1465. X   effective, but otherwise it would get too complicated. */
  1466. X
  1467. Xvoid
  1468. Xsection(number, config)
  1469. X     int number;
  1470. X     FILE *config;
  1471. X{
  1472. X  char buffer[BUFLEN];
  1473. X
  1474. X  (void) rewind(config);
  1475. X  while (--number)
  1476. X    while (getcl(buffer, BUFLEN, config))
  1477. X      /* skip section */;
  1478. X}
  1479. X
  1480. X/* Get header field from file. */
  1481. X
  1482. X#define MAX_HEADER_LEN 256
  1483. X
  1484. Xchar *mheader(fp, headername)
  1485. X     FILE *fp;
  1486. X     char *headername;
  1487. X{
  1488. X  static char header[MAX_HEADER_LEN];
  1489. X  long position;
  1490. X
  1491. X  position = ftell(fp);
  1492. X
  1493. X  rewind(fp);
  1494. X
  1495. X  /* Blank line terminates also, there shouldn't be any headers
  1496. X     after it any more */
  1497. X
  1498. X  while (fgets(header, MAX_HEADER_LEN, fp) && *header != '\n')
  1499. X    if (!strncmp(header, headername, strlen(headername)))
  1500. X      {
  1501. X    /* Remove \n at end */
  1502. X    header[strlen(header) - 1] = 0;
  1503. X    fseek(fp, position, 0);
  1504. X    return header + strlen(headername);
  1505. X      }
  1506. X
  1507. X  /* Not found, return empty string */
  1508. X
  1509. X  fseek(fp, position, 0);
  1510. X  return "";
  1511. X}
  1512. X
  1513. X
  1514. X
  1515. SHAR_EOF
  1516. chmod 0644 funcs.c || echo "restore of funcs.c fails"
  1517. echo "x - extracting rfnews.c (Text)"
  1518. sed 's/^X//' << 'SHAR_EOF' > rfnews.c &&
  1519. X#ifndef lint
  1520. Xstatic char *sccsid = "@(#)%M%  %I%  Teemu Torma %H%";
  1521. X#endif
  1522. X
  1523. X/* Spool Usenet news articles to fidonet. Currently there is no news-system
  1524. X   in fido, it's done by software after and before mail-slots. Echomail
  1525. X   is most popular one, and this program does about the same thing:
  1526. X   it sends news-articles as fido-mail containing suitable information
  1527. X   for echomail. Echomail relies on normal fido-mail, we send news thru
  1528. X   rfmail, because this mechanism requires nothing different from normal
  1529. X   mail.
  1530. X
  1531. X   @(#)Copyright (c) 1987 by Teemu Torma
  1532. X
  1533. X   Permission is given to distribute this program and alter this code as
  1534. X   needed to adapt it to forign systems provided that this header is
  1535. X   included and that the original author's name is preserved. */
  1536. X
  1537. X#include <stdio.h>
  1538. X#include <ctype.h>
  1539. X#include <string.h>
  1540. X#include <sys/types.h>
  1541. X#include "hsu.h"
  1542. X#include "config.h"
  1543. X#include "fnet.h"
  1544. X#include "fnews.h"
  1545. X#include "nodelist.h"
  1546. X
  1547. Xextern void exit();
  1548. Xextern void perror();
  1549. X
  1550. Xint verbose = INIT_VERBOSE;
  1551. X
  1552. X/* Get header field. Rewind header file and scan forward until we find
  1553. X   desired field. Not effective, but... Return NULL if field not found. */
  1554. X
  1555. Xchar *
  1556. Xget_field(field, hdr)
  1557. X     char *field;
  1558. X     FILE *hdr;
  1559. X{
  1560. X  static char buffer[BUFLEN];
  1561. X  int conditional = FALSE;
  1562. X  char *p;
  1563. X
  1564. X  if (*field == '?')
  1565. X    {
  1566. X      conditional = TRUE;
  1567. X      for (p = field; *p = *(p + 1); p++);
  1568. X    }
  1569. X
  1570. X  (void) rewind(hdr);
  1571. X  while (fgets(buffer, BUFLEN, hdr))
  1572. X    if (!strncmp(field, buffer, strlen(field)))
  1573. X      {
  1574. X    if (conditional)
  1575. X      {
  1576. X        /* Note: <= is ok, because there is one blank after header which
  1577. X           wouldn't be included in Fidonet message header */
  1578. X        if (!strncmp(field, "Subject:", 8))
  1579. X          if (strlen(buffer + 8) <= 72) return NULL;
  1580. X        if (!strncmp(field, "From:", 5))
  1581. X          if (strlen(buffer + 5) <= 36) return NULL;
  1582. X        if (!strncmp(field, "Reply-To:", 9))
  1583. X          if (strlen(buffer + 9) <= 36) return NULL;
  1584. X        if (!strncmp(field, "To:", 3))
  1585. X          if (strlen(buffer + 3) <= 36) return NULL;
  1586. X      }
  1587. X
  1588. X        buffer[strlen(buffer) - 1] = 0;
  1589. X        return buffer + strlen(field);
  1590. X      }
  1591. X
  1592. X  return (char *) NULL;
  1593. X}
  1594. X
  1595. X/* Open stream which is associated with fido-mailers starndard input.
  1596. X   We could use also popen(3S), but it invokes also sh(1) which slows
  1597. X   down opening and gets more memory. This routine exists if something
  1598. X   goes wrong, because this is quite essential part of program and
  1599. X   we can not continue without mailer. */
  1600. X
  1601. XFILE *
  1602. Xopen_mailer(to)
  1603. X     char *to;
  1604. X{
  1605. X  FILE *fp;
  1606. X  int fd[2];
  1607. X  char mailer[128];
  1608. X
  1609. X  (void) sprintf(mailer, "%s/rfmail", LIBDIR);
  1610. X
  1611. X  /* create pipe */
  1612. X  if (pipe(fd) == -1)
  1613. X    {
  1614. X      perror("rfnews: pipe");
  1615. X      exit(1);
  1616. X    }
  1617. X
  1618. X  switch (fork())
  1619. X    {
  1620. X    case -1:
  1621. X      perror("rfnews: fork failed");
  1622. X      exit(1);
  1623. X    case 0:
  1624. X      (void) close(0);
  1625. X      /* duplicate pipe and close now unused fd's */
  1626. X      if (dup(fd[0]) == 0)
  1627. X        {
  1628. X          (void) close(fd[0]);
  1629. X          (void) close(fd[1]);
  1630. X          (void) execlp(mailer, "rfmail", "-p", to, (char *) NULL);
  1631. X          perror(mailer);
  1632. X        }
  1633. X      else
  1634. X        perror("rfnews: dup");
  1635. X      exit(0);
  1636. X    default:
  1637. X      (void) close(fd[0]);
  1638. X      /* open the other end of pipe as buffered */
  1639. X      if ((fp = fdopen(fd[1], "w")) == NULL)
  1640. X        {
  1641. X          perror("rfnews: fdopen");
  1642. X          exit(1);
  1643. X        }
  1644. X    }
  1645. X  return fp;
  1646. X}
  1647. X
  1648. X/* Save news header for future processing and return file pointer to it. */
  1649. X
  1650. XFILE *
  1651. Xsave_hdr()
  1652. X{
  1653. X  char buffer[BUFLEN];
  1654. X  FILE *hdr = tmpfile();
  1655. X
  1656. X  while (fgets(buffer, BUFLEN, stdin) && *buffer != '\n')
  1657. X    (void) fputs(buffer, hdr);
  1658. X  return hdr;
  1659. X}
  1660. X
  1661. X/* Open rfmail. Send mail to net/node in config file, receiver will be
  1662. X   All, because Usenet News articles don't have To: field. Net/node
  1663. X   exraction is not very reliable of there's something wrong in
  1664. X   configuration file. */
  1665. X
  1666. XFILE *
  1667. Xinvoke_rfmail(config)
  1668. X     FILE *config;
  1669. X{
  1670. X  char buffer[BUFLEN], *cp;
  1671. X  int net, node;
  1672. X
  1673. X  section(SECT_NETNODE, config);
  1674. X  if (getcl(buffer, BUFLEN, config))
  1675. X    {
  1676. X      /* get net number */
  1677. X      for (cp = buffer, net = 0; *cp && isdigit(*cp) && *cp != '/'; cp++)
  1678. X        net = net * 10 + *cp - '0';
  1679. X      debug(1, "Got net %d from config file", net);
  1680. X      if (*cp)
  1681. X        {
  1682. X          /* get node number */
  1683. X          for (cp++, node = 0; *cp && isdigit(*cp); cp++)
  1684. X            node = node * 10 + *cp - '0';
  1685. X          debug(1, "Got node %d from config file", node);
  1686. X        }
  1687. X      else
  1688. X        {
  1689. X          log("Missing node in config file");
  1690. X          exit(1);
  1691. X        }
  1692. X      (void) sprintf(buffer, "All@%d.%d.FidoNet", node, net);
  1693. X      return open_mailer(buffer);
  1694. X    }
  1695. X  else
  1696. X    {
  1697. X      log("Missing net/node in config file");
  1698. X      exit(1);
  1699. X    }
  1700. X  /* NOTREACHED */
  1701. X}
  1702. X
  1703. X/* Try to get area for some of the newsgroups in newsgroup list. Method
  1704. X   is not very sophisticated, but it should work. */
  1705. X
  1706. Xchar *
  1707. Xget_area(config, groups)
  1708. X     FILE *config;
  1709. X     char *groups;
  1710. X{
  1711. X  static char conv[BUFLEN];
  1712. X  char buffer[BUFLEN];
  1713. X  char *cp, *gr, *area;
  1714. X
  1715. X  debug(2, "Checking grouplist '%s'", groups);
  1716. X
  1717. X  section(SECT_NG_AREA, config);
  1718. X  while (getcl(conv, BUFLEN, config))
  1719. X    {
  1720. X      for (cp = conv; !isspace(*cp); cp++)
  1721. X        /* find the end of newsgroup name */;
  1722. X      if (isspace(*cp))
  1723. X        {
  1724. X          *cp++ = 0;
  1725. X          (void) strcpy(buffer, groups);
  1726. X          debug(3, "Config line '%s'", conv);
  1727. X          /* get group by group from newsgroup-list */
  1728. X          for (gr = strtok(buffer, " ,"); gr; gr = strtok((char *) NULL, " ,"))
  1729. X            {
  1730. X              debug(3, "Comparing '%s' and '%s'", gr, conv);
  1731. X              if (!strcmp(gr, conv))
  1732. X                {
  1733. X                  while (isspace(*cp))
  1734. X                    cp++;
  1735. X                  area = cp;
  1736. X                  while (*cp && !isspace(*cp))
  1737. X                    cp++;
  1738. X                  *cp = 0;
  1739. X                  debug(3, "Match, return area '%s'", area);
  1740. X                  return area;
  1741. X                }
  1742. X            }
  1743. X          debug(3, "No match");
  1744. X        }
  1745. X      else
  1746. X        log("Invalid line in config: '%s'", conv);
  1747. X    }
  1748. X  log("No area found for any group in '%s'", groups);
  1749. X  return (char *) NULL;
  1750. X}
  1751. X
  1752. X/* Do actual processing of article. This will copy article, get newsgoroups
  1753. X   and save them and then send all rest of article. */
  1754. X
  1755. X/* ARGSUSED */
  1756. Xint
  1757. Xmain(argc, argv, envp)
  1758. X     int argc;
  1759. X     char **argv, **envp;
  1760. X{
  1761. X  FILE *config, *rfmail, *hdr;
  1762. X  char buffer[BUFLEN], seenbys[BUFLEN];
  1763. X  int c;
  1764. X  char *cp, *errorstr;
  1765. X
  1766. X  /* get options */
  1767. X  while ((c = getopt(argc, argv, "v")) != EOF)
  1768. X    switch (c)
  1769. X      {
  1770. X      case 'v':
  1771. X        verbose++;
  1772. X        break;
  1773. X      default:
  1774. X        (void) fprintf(stderr, "Usage: %s [-v]\n", *argv);
  1775. X        exit(1);
  1776. X      }
  1777. X
  1778. X  /* try to update nodelist-index */
  1779. X  if (errorstr = update_index())
  1780. X    {
  1781. X      if (*errorstr == '$')
  1782. X        log("$Cannot update nodelist-index: %s", errorstr + 1);
  1783. X      else
  1784. X        log("Cannot update nodelist-index: %s", errorstr);
  1785. X      exit(EX_OSERR);
  1786. X    }
  1787. X
  1788. X  /* try to open config file */
  1789. X  if ((config = pfopen(LIBDIR, "fnews.cf", "r")) == NULL)
  1790. X    {
  1791. X      log("$Unable to open config file");
  1792. X      exit(1);
  1793. X    }
  1794. X
  1795. X  /* open rfmail to send news */
  1796. X  rfmail = invoke_rfmail(config);
  1797. X
  1798. X  /* save news header */
  1799. X  hdr = save_hdr();
  1800. X
  1801. X  /* try to get area to which this article is going */
  1802. X  if (cp = get_field("Newsgroups: ", hdr))
  1803. X    if (cp = get_area(config, cp))
  1804. X      {
  1805. X    (void) fprintf(rfmail, "AREA:%s\n", cp);
  1806. X    debug(2, "send area %s", cp);
  1807. X      }
  1808. X    else
  1809. X      {
  1810. X        log("Unable to get area");
  1811. X#ifdef JUNK_AREA
  1812. X        (void) fprintf(rfmail, "AREA:\n", JUNK_AREA);
  1813. X        log("Sending article to area %s", JUNK_AREA);
  1814. X#else
  1815. X        exit(1);
  1816. X#endif
  1817. X      }
  1818. X  else
  1819. X    {
  1820. X      log("Missing Newsgroups: line in article");
  1821. X      exit(1);
  1822. X    }
  1823. X
  1824. X  /* now send news header */
  1825. X  section(SECT_HEADERS, config);
  1826. X  while (getcl(buffer, BUFLEN, config))
  1827. X    if (cp = get_field(buffer, hdr))
  1828. X      (void) fprintf(rfmail,"%s%s\n", buffer, cp);
  1829. X  (void) putc('\n', rfmail);
  1830. X
  1831. X  /* send rest of the article */
  1832. X  while (fgets(buffer, BUFLEN, stdin))
  1833. X    (void) fputs(buffer, rfmail);
  1834. X
  1835. X  /* send last information */
  1836. X  fprintf(rfmail, "--- %s\n", PROGRAMNAME);
  1837. X  section(SECT_ENDMSG, config);
  1838. X  if (!getcl(buffer, BUFLEN, config))
  1839. X    strcpy(buffer, "No Origin");
  1840. X  else if (!getcl(seenbys, BUFLEN, config))
  1841. X    *seenbys = 0;
  1842. X
  1843. X  (void) fprintf(rfmail, " * Origin: %s (%d:%d/%d.%d)\n", buffer,
  1844. X         MY_ZONE, MY_NET, MY_NODE, MY_POINT);
  1845. X  fprintf(rfmail, "SEEN-BY: %s \n", seenbys);
  1846. X  fprintf(rfmail, "\001PATH: %d/%d \n", MY_NET, MY_NODE);
  1847. X
  1848. X  /* I think that that was all... */
  1849. X  (void) fclose(rfmail);
  1850. X  (void) wait((int *) NULL);
  1851. X
  1852. X  exit(0);
  1853. X  /* NOTREACHED */
  1854. X}
  1855. SHAR_EOF
  1856. chmod 0644 rfnews.c || echo "restore of rfnews.c fails"
  1857. echo "x - extracting rmail.c (Text)"
  1858. sed 's/^X//' << 'SHAR_EOF' > rmail.c &&
  1859. X#ifndef lint
  1860. Xstatic char *sccsid = "@(#)%M%  %I%  Teemu Torma %H%";
  1861. X#endif
  1862. X
  1863. X/* Replacement for rmail. This looks out, if destination system
  1864. X   name is numeric, and if it is, feeds mail to fidonet mail
  1865. X   server. If systemname is not numeric, this executes real rmail.
  1866. X   If this site is not fidonet gateway, define GATEWAY in rmail.h
  1867. X   to path to that host.
  1868. X
  1869. X   This is just a temporary replacement, MUCH MORE better is to use
  1870. X   sendmail for gatewaying or smail 2.3 version that also can invoke
  1871. X   other mailer.
  1872. X
  1873. X   @(#)Copyright (c) 1987 by Teemu Torma
  1874. X
  1875. X   Permission is given to distribute this program and alter this code as
  1876. X   needed to adapt it to forign systems provided that this header is
  1877. X   included and that the original author's name is preserved. */
  1878. X
  1879. X#include <stdio.h>
  1880. X#include <string.h>
  1881. X#include <ctype.h>
  1882. X#include <sys/types.h>
  1883. X#include "hsu.h"
  1884. X#include "rmail.h"
  1885. X#include "config.h"
  1886. X#include "sysexits.h"
  1887. X#include "nodelist.h"
  1888. X#include "fnet.h"
  1889. X
  1890. Xextern char *malloc();
  1891. Xextern void exit();
  1892. Xextern void perror();
  1893. Xextern char *regex();
  1894. X
  1895. X/* verbosity */
  1896. Xint verbose = INIT_VERBOSE;
  1897. X
  1898. X#ifndef GATEWAY
  1899. X
  1900. X
  1901. X/* Open stream associated with programs standard input. Program is invoked
  1902. X   with given argument list. Popen(3S) would invoke mailer thru sh(1),
  1903. X   so this uses less memory and is faster. */
  1904. X
  1905. XFILE *
  1906. Xopen_mailer(program, args, pid)
  1907. X     char *program, **args;
  1908. X     int *pid;
  1909. X{
  1910. X  FILE *fp;
  1911. X  int fd[2];
  1912. X
  1913. X  /* create pipe */
  1914. X  if (pipe(fd) == -1)
  1915. X    {
  1916. X      perror("rmail: pipe");
  1917. X      exit(EX_OSERR);
  1918. X    }
  1919. X
  1920. X  switch (*pid = fork())
  1921. X    {
  1922. X    case -1:
  1923. X      perror("rmail: fork failed");
  1924. X      exit(EX_OSERR);
  1925. X    case 0:
  1926. X      (void) close(0);
  1927. X      if (dup(fd[0]) == 0)
  1928. X        {
  1929. X          (void) close(fd[0]);
  1930. X          (void) close(fd[1]);
  1931. X          (void) execvp(program, args);
  1932. X          perror(program);
  1933. X        }
  1934. X      else
  1935. X        perror("rmail: dup");
  1936. X      exit(EX_OSERR);
  1937. X    default:
  1938. X      (void) close(fd[0]);
  1939. X      if ((fp = fdopen(fd[1], "w")) == NULL)
  1940. X        {
  1941. X          perror("rmail: fdopen");
  1942. X          exit(EX_OSERR);
  1943. X        }
  1944. X    }
  1945. X  return fp;
  1946. X}
  1947. X
  1948. X#endif
  1949. X
  1950. X
  1951. X/* ARGSUSED */
  1952. Xint
  1953. Xmain(argc, argv, envp)
  1954. X     int argc;
  1955. X     char **argv, **envp;
  1956. X{
  1957. X  int cnt;
  1958. X
  1959. X#ifdef GATEWAY
  1960. X
  1961. X  char *path;
  1962. X
  1963. X#else
  1964. X
  1965. X  char **rargs = marray(argc + 1), **fargs = marray(argc + 1);
  1966. X  int rrec = 0, frec = 0, rargc = 1, fargc = 1;
  1967. X  int status = EX_OK;
  1968. X  char dummyname[100];
  1969. X  Node dummynode;
  1970. X
  1971. X#endif
  1972. X
  1973. X#ifdef GATEWAY
  1974. X
  1975. X  /* If GATEWAY is defined, send all mail going to fidonet to there.
  1976. X     If domain .FidoNet is known by other mahcines, routing is not
  1977. X     really problem and this rmail is not needed elsewhere than in
  1978. X     real gateway if there's no sendmail or other intelligent system
  1979. X     in use. */
  1980. X
  1981. X  for (cnt = 1; cnt < argc; cnt++)
  1982. X    if (parse_address(argv[cnt], dummyname, &dummynet, &dummynode) == NULL)
  1983. X      {
  1984. X#ifdef DEBUG
  1985. X        (void) printf("Routing %s to %s.\n", argv[cnt], GATEWAY);
  1986. X#endif
  1987. X        path = malloc((unsigned) (strlen(GATEWAY) +
  1988. X                                  strlen(argv[cnt]) + 2));
  1989. X        (void) strcpy(path, GATEWAY);
  1990. X        (void) strcat(path, "!");
  1991. X        argv[cnt] = strcat(path, argv[cnt]);
  1992. X      }
  1993. X
  1994. X  (void) execvp(RMAIL, argv);
  1995. X  perror(RMAIL);
  1996. X
  1997. X#else
  1998. X
  1999. X  *rargs = RMAIL;
  2000. X  *fargs = FIDOMAILER;
  2001. X
  2002. X  /* Scan thru receiver list and put all receivers in fidonet in fido-
  2003. X     mailer's receiver-list and all others in real rmails one. No
  2004. X     options can be passed to fidomailer thru this, because it would
  2005. X     be too difficult to determine which one goes to which one and
  2006. X     there might be same options also. Somehow it's good that fidomailer
  2007. X     is well hidden under this... */
  2008. X
  2009. X  for (cnt = 1; cnt < argc; cnt++)
  2010. X    if (*argv[cnt] == '-')
  2011. X      rargs[rargc++] = strsave(argv[cnt]);
  2012. X    else
  2013. X      {
  2014. X        if (parse_address(argv[cnt], dummyname, &dummynode) == NULL)
  2015. X          {
  2016. X#ifdef DEBUG
  2017. X            (void) printf("Argument %d (receiver %d) in fidomailer: %s\n",
  2018. X                          fargc, frec + 1, argv[cnt]);
  2019. X#endif
  2020. X            fargs[fargc++] = strsave(argv[cnt]);
  2021. X            frec++;
  2022. X          }
  2023. X        else
  2024. X          {
  2025. X#ifdef DEBUG
  2026. X            (void) printf("Argument %d (receiver %d) in rmail: %s\n",
  2027. X                          rargc, rrec + 1, argv[cnt]);
  2028. X#endif
  2029. X            rargs[rargc++] = strsave(argv[cnt]);
  2030. X            rrec++;
  2031. X          }
  2032. X      }
  2033. X
  2034. X  /* NULL terminate arument lists */
  2035. X  rargs[rargc] = NULL;
  2036. X  fargs[fargc] = NULL;
  2037. X
  2038. X  /* If there is mail only to rmail or fidomail, execute that mailer
  2039. X     with our original argument list. */
  2040. X
  2041. X  if (!frec)
  2042. X    {
  2043. X#ifdef DEBUG
  2044. X      (void) printf("No mail to fidonet, executing %s\n", RMAIL);
  2045. X#endif
  2046. X      (void) execvp(RMAIL, argv);
  2047. X      perror(RMAIL);
  2048. X      exit(1);
  2049. X    }
  2050. X  else
  2051. X    if (!rrec)
  2052. X      {
  2053. X#ifdef DEBUG
  2054. X        (void) printf("No mail to UUCP, executing %s\n", FIDOMAILER);
  2055. X#endif
  2056. X        (void) execvp(FIDOMAILER, argv);
  2057. X        perror(FIDOMAILER);
  2058. X        exit(1);
  2059. X      }
  2060. X    else
  2061. X      {
  2062. X
  2063. X        /* There's mail to both fidonet and usenet. We'll have to open
  2064. X           both mailers and feed this letter to them at the same time.
  2065. X           This is quite risky: If one of the mailer's exits for any
  2066. X           reason, we will get SIGPIPE and we'll fall down.... if that
  2067. X           happens, the other mailer got incomplete letter. */
  2068. X
  2069. X        int rmail_pid, fmail_pid;
  2070. X        register FILE *rmail = open_mailer(RMAIL, rargs, &rmail_pid);
  2071. X        register FILE *fmail = open_mailer(FIDOMAILER, fargs, &fmail_pid);
  2072. X        char buffer[BUFSIZ];
  2073. X        int stat_loc, pid;
  2074. X
  2075. X#ifdef DEBUG
  2076. X        (void) printf("Mail both to fidonet and UUCP\n");
  2077. X#endif
  2078. X        while (fgets(buffer, BUFSIZ, stdin))
  2079. X          {
  2080. X            (void) fputs(buffer, rmail);
  2081. X            (void) fputs(buffer, fmail);
  2082. X          }
  2083. X        (void) fclose(rmail);
  2084. X        (void) fclose(fmail);
  2085. X
  2086. X        /* We should wait for both mailers to exit and check their exit
  2087. X           statuses. Then we should decide which one we'll should return,
  2088. X           in this case let's return status from rmail, if other than
  2089. X           EX_OK, otherwise from fidomail. */
  2090. X
  2091. X        while ((pid = wait(&stat_loc)) != -1)
  2092. X          if (pid == rmail_pid)
  2093. X            {
  2094. X              if ((stat_loc & 0377) == 0)
  2095. X                status = stat_loc >> 8;
  2096. X            }
  2097. X          else
  2098. X            if (pid == fmail_pid)
  2099. X              {
  2100. X                if ((stat_loc & 0377) == 0 && status == EX_OK)
  2101. X                  status = stat_loc >> 8;
  2102. X              }
  2103. X      }
  2104. X#endif
  2105. X
  2106. X  exit(status);
  2107. X  /* NOTREACHED */
  2108. X}
  2109. SHAR_EOF
  2110. chmod 0644 rmail.c || echo "restore of rmail.c fails"
  2111. echo "x - extracting fpack.c (Text)"
  2112. sed 's/^X//' << 'SHAR_EOF' > fpack.c &&
  2113. X#ifndef lint
  2114. Xstatic char *sccsid = "@(#)%M%  %I%  Teemu Torma %H%";
  2115. X#endif
  2116. X
  2117. X/* Create and update fidomail packets. Read mail messages from
  2118. X   spool directory and append them to packet. If packet doesn't
  2119. X   exist already, it will be created. Packet name in P.point.node.net.zone.
  2120. X
  2121. X   @(#)Copyright (c) 1987 by Teemu Torma
  2122. X
  2123. X   Permission is given to distribute this program and alter this code as
  2124. X   needed to adapt it to forign systems provided that this header is
  2125. X   included and that the original author's name is preserved. */
  2126. X
  2127. X#include <stdio.h>
  2128. X#include <ctype.h>
  2129. X#include <errno.h>
  2130. X#include <string.h>
  2131. X#include <fcntl.h>
  2132. X#include <sys/types.h>
  2133. X#include <time.h>
  2134. X#include <sys/stat.h>
  2135. X#include <dirent.h>
  2136. X#include "hsu.h"
  2137. X#include "config.h"
  2138. X#include "fnet.h"
  2139. X#include "fpack.h"
  2140. X#include "nodelist.h"
  2141. X
  2142. Xextern time_t time();
  2143. Xextern int getopt();
  2144. Xextern int optind;
  2145. Xextern char *optarg;
  2146. Xextern uint sleep();
  2147. Xextern void exit();
  2148. Xextern void swab();
  2149. X
  2150. XNode node;
  2151. Xint verbose = INIT_VERBOSE;
  2152. X
  2153. X/* Return True if string is numeric. */
  2154. X
  2155. Xbool
  2156. Xnumeric(s)
  2157. X     register char *s;
  2158. X{
  2159. X  while (*s)
  2160. X    if (!isdigit(*s++))
  2161. X      return False;
  2162. X  return True;
  2163. X}
  2164. X
  2165. X/* Return argument as 16 bit interger to msdos */
  2166. X
  2167. XINT16
  2168. Xint16(value)
  2169. X     int value;
  2170. X{
  2171. X  INT16 msint, mval = (INT16) value;
  2172. X
  2173. X#ifdef SWAB_BYTES
  2174. X  swab((char *) &mval, (char *) &msint, 2);
  2175. X#else
  2176. X  msint = mval;
  2177. X#endif
  2178. X  return msint;
  2179. X}
  2180. X
  2181. X/* Put string to file in null-terminated format. */
  2182. X
  2183. Xvoid
  2184. Xput_string(fp, s)
  2185. X     FILE *fp;
  2186. X     char *s;
  2187. X{
  2188. X  while (*s)
  2189. X    {
  2190. X      (void) putc(*s, fp);
  2191. X      s++;
  2192. X    }
  2193. X  (void) putc(0, fp);
  2194. X}
  2195. X
  2196. X/* Return date in ascii string that is in fido-format, ie.
  2197. X   dd mmm yy hh:mm:ss, like 24 Jan 87 06:24:27 */
  2198. X
  2199. Xchar
  2200. X*fido_date(clock)
  2201. X     time_t clock;
  2202. X{
  2203. X  struct tm *tm;
  2204. X  static char date[20];
  2205. X
  2206. X  /* Literal months */
  2207. X  static char *months[] = {
  2208. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  2209. X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  2210. X  };
  2211. X
  2212. X  tm = localtime(&clock);
  2213. X  (void) sprintf(date, "%02d %3s %02d %02d:%02d:%02d", tm->tm_mday,
  2214. X                 months[tm->tm_mon], tm->tm_year, tm->tm_hour,
  2215. X                 tm->tm_min, tm->tm_sec);
  2216. X  return date;
  2217. X}
  2218. X
  2219. X/* Write int to file in msdos interger format */
  2220. X
  2221. Xint
  2222. Xwrite_int(fp, value)
  2223. X     FILE *fp;
  2224. X     int value;
  2225. X{
  2226. X  INT16 msint = int16(value);
  2227. X
  2228. X  return fwrite((char *) &msint, sizeof(INT16), 1, fp);
  2229. X}
  2230. X
  2231. X/* Write fido msg header for mailfile. Mailfile contains first headers
  2232. X   terminated by empty line, after that comes message text.
  2233. X   Header consists of one letter id followed by arguments if any.
  2234. X
  2235. X   Id-letters:
  2236. X   N - fidonet address information of message, e.g. N 2:504/8.0.
  2237. X   T - to whom message is to, e.g. T Teemu Torma.
  2238. X   F - from whom message is from, e.g. F Foo Bar.
  2239. X   S - subject of message, e.g S How are you?.
  2240. X   P - indicates that message is private. (Here is little conflict:
  2241. X       rfmail uses option -p to indicate that mail to public and here
  2242. X       P means that mail is private. Maybe this P should mean that
  2243. SHAR_EOF
  2244. echo "End of part 2"
  2245. echo "File fpack.c is continued in part 3"
  2246. echo "3" > s2_seq_.tmp
  2247. exit 0
  2248.  
  2249.