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

  1. Subject:  v18i004:  Fido/Usenet gateway, Part03/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 4
  8. Archive-name: fnet/part03
  9.  
  10. #!/bin/sh
  11. # this is part 3 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file fpack.c continued
  14. #
  15. CurArch=3
  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 fpack.c"
  26. sed 's/^X//' << 'SHAR_EOF' >> fpack.c
  27. X       mail is public and default is private).
  28. X
  29. X   All letters having arguments have only on space after them, and all
  30. X   rest of the line is considered to be that argument. */
  31. X
  32. Xbool
  33. Xwrite_hdr(source, packet)
  34. X     FILE *source, *packet;
  35. X{
  36. X  char buffer[BUFSIZ];
  37. X  char from[36], to[36], subject[72], date[20];
  38. X  Node msg_node;
  39. X  int attr = 0;
  40. X  struct stat stbuf;
  41. X
  42. X  msg_node.zone = msg_node.net = msg_node.node = msg_node.point = -1;
  43. X
  44. X  /* clean up from, to and subject */
  45. X  *from = 0;
  46. X  *to = 0;
  47. X  *subject = 0;
  48. X  *date = 0;
  49. X
  50. X  while (fgets(buffer, BUFSIZ, source) && *buffer != '\n')
  51. X    {
  52. X      buffer[strlen(buffer) - 1] = 0; /* strip newline */
  53. X      switch (*buffer)
  54. X        {
  55. X        case 'N':
  56. X          if (parsefnetaddress(buffer, &msg_node))
  57. X            {
  58. X              log("Invalid destination: %s", buffer);
  59. X              return False;
  60. X            }
  61. X          break;
  62. X        case 'F':
  63. X          (void) strncpy(from, buffer + 2, 35);
  64. X          from[35] = 0;
  65. X          break;
  66. X        case 'T':
  67. X          (void) strncpy(to, buffer + 2, 35);
  68. X          to[35] = 0;
  69. X          break;
  70. X        case 'S':
  71. X          (void) strncpy(subject, buffer + 2, 71);
  72. X          subject[71] = 0;
  73. X          break;
  74. X        case 'D':
  75. X          (void) strncpy(date, buffer + 2, 19);
  76. X          date[19] = 0;
  77. X          break;
  78. X        case 'P':
  79. X          attr |= ATTR_PRIVATE;
  80. X          break;
  81. X        }
  82. X    }
  83. X
  84. X  /* check if net/node was missing */
  85. X  if (msg_node.net == -1 || msg_node.node == -1)
  86. X    {
  87. X      log("Message with no destination");
  88. X      return False;
  89. X    }
  90. X
  91. X  /* we must have also receiver */
  92. X  if (!*to)
  93. X    {
  94. X      log("Missing receiver in mail header");
  95. X      return False;
  96. X    }
  97. X
  98. X  /* if from is missing, we'll improvise...*/
  99. X  if (!*from)
  100. X    {
  101. X      log("Missing from is header");
  102. X      (void) strcpy(from, "Usenet");
  103. X    }
  104. X
  105. X  /* if subject is missing, let's put there something */
  106. X  if (!*subject)
  107. X    {
  108. X      log("Missing subject in header");
  109. X      (void) strcpy(subject, "Mail from Usenet");
  110. X    }
  111. X
  112. X  /* if date is missing, put there current date */
  113. X  if (!*date)
  114. X    {
  115. X      log("Missing date in header");
  116. X      (void) strcpy(date, fido_date(time((long *) 0)));
  117. X    }
  118. X
  119. X  /* save all header values */
  120. X  (void) write_int(packet, MSGTYPE); /* save msg type */
  121. X  (void) write_int(packet, MY_NODE); /* save our node */
  122. X  (void) write_int(packet, msg_node.node); /* save messages node */
  123. X  (void) write_int(packet, MY_NET); /* save our net */
  124. X  (void) write_int(packet, msg_node.net); /* save messages net */
  125. X  (void) write_int(packet, attr); /* save attributes */
  126. X  (void) write_int(packet, 0); /* cost, not used by us */
  127. X  put_string(packet, date); /* save time of mail */
  128. X  put_string(packet, to); /* save receiver */
  129. X  put_string(packet, from); /* save sender */
  130. X  put_string(packet, subject); /* save subject */
  131. X
  132. X  /* get status of mailfile and log this message */
  133. X  if (fstat(fileno(source), &stbuf) == -1)
  134. X    log("Unable to get stat of msg");
  135. X
  136. X  log("Msg from %s to %s at %s packetized (%ld chars)", from, to,
  137. X      ascnode(msg_node), stbuf.st_size - ftell(source));
  138. X
  139. X  /* done with this header */
  140. X  return True;
  141. X}
  142. X
  143. X/* Write packet header for new packet.
  144. X
  145. X   Tue Oct 11 04:01:49 1988
  146. X   Changed fwrite to write-ints and so on, as there is too many problems
  147. X   with int and specially long alignment on different architectures. This
  148. X   should be more portable!
  149. X   (two extra bytes added for long alignment caused confmail to find
  150. X   message type to be 0 and so it just forgot about that packet thinking
  151. X   that it was in the end!)
  152. X */
  153. X
  154. Xbool
  155. Xwrite_pkthdr(packet)
  156. X     FILE *packet;
  157. X{
  158. X  Packet header;
  159. X  int count;
  160. X  struct tm *tm;
  161. X  time_t clock = time((long *) 0);
  162. X
  163. X  tm = localtime(&clock);
  164. X
  165. X  /* create packet structure */
  166. X  header.orig_node = int16(MY_NODE);
  167. X  header.dest_node = int16(node.node);
  168. X  header.orig_net = int16(MY_NET);
  169. X  header.dest_net = int16(node.net);
  170. X
  171. X  /* save time for header (why all these fields?) */
  172. X  header.year = int16(tm->tm_year + 1900);
  173. X  header.month = int16(tm->tm_mon);
  174. X  header.day = int16(tm->tm_mday);
  175. X  header.hour = int16(tm->tm_hour + 1);
  176. X  header.minute = int16(tm->tm_min);
  177. X  header.second = int16(tm->tm_sec);
  178. X
  179. X  header.rate = int16(MAXBAUD);
  180. X  header.ver = int16(HDRVER);
  181. X  header.product = 0;
  182. X  header.x1 = 0;
  183. X#ifdef FIDO_V11w
  184. X  for (count = 0; count < 16; count++) header.fill[count] = 0;
  185. X#else
  186. X  for (count = 0; count < 8; count++) header.pwd_kludge[count] = 0;
  187. X  header.orig_zone = int16(MY_ZONE);
  188. X  header.dest_zone = int16(node.zone);
  189. X  for (count = 0; count < 16; count++) header.B_fill2[count] = 0;
  190. X  header.B_fill3 = 0;
  191. X#endif
  192. X  /* write header to file */
  193. X  FPUTINT16(header.orig_node, packet);
  194. X  FPUTINT16(header.dest_node, packet);
  195. X  FPUTINT16(header.year, packet);
  196. X  FPUTINT16(header.month, packet);
  197. X  FPUTINT16(header.day, packet);
  198. X  FPUTINT16(header.hour, packet);
  199. X  FPUTINT16(header.minute, packet);
  200. X  FPUTINT16(header.second, packet);
  201. X  FPUTINT16(header.rate, packet);
  202. X  FPUTINT16(header.ver, packet);
  203. X  FPUTINT16(header.orig_net, packet);
  204. X  FPUTINT16(header.dest_net, packet);
  205. X  putc(header.product, packet);
  206. X  putc(header.x1, packet);
  207. X  for (count = 0; count < 8; count++) putc(header.pwd_kludge[count], packet);
  208. X  FPUTINT16(header.orig_zone, packet);
  209. X  FPUTINT16(header.dest_zone, packet);
  210. X  for (count = 0; count < 16; count++) putc(header.B_fill2[count], packet);
  211. X  for (count = 0; count < 4; count++)
  212. X    putc(header.B_fill3 << (8 * count), packet); /* pc long = 4 bytes! */
  213. X
  214. X  if (ferr(packet))
  215. X    {
  216. X      log("$Write error on packet header");
  217. X      return False;
  218. X    }
  219. X
  220. X  debug(1, "New packet created");
  221. X
  222. X  return True;
  223. X}
  224. X
  225. X/*ARGSUSED*/
  226. Xint
  227. Xmain(argc, argv, envp)
  228. X     int argc;
  229. X     char **argv, **envp;
  230. X{
  231. X  DIR *dp;
  232. X  struct dirent *dir;
  233. X  FILE *msg, *packet;
  234. X  char packet_name[16];
  235. X  int c;
  236. X  Node np;
  237. X  char *error;
  238. X
  239. X  /* get options */
  240. X  while ((c = getopt(argc, argv, "vf:")) != EOF)
  241. X    switch (c)
  242. X      {
  243. X      case 'f':
  244. X    if (parsefnetaddress(optarg, &np)) exit(1);
  245. X    node = np;
  246. X        break;
  247. X      case 'v':
  248. X        verbose++;
  249. X        break;
  250. X      default:
  251. X        (void) fprintf(stderr, "Usage: %s [-v] -f fidonet_address\n", *argv);
  252. X        exit(1);
  253. X      }
  254. X
  255. X  /* make sure that we got net/node */
  256. X  if (node.net == -1 || node.node == -1)
  257. X    {
  258. X      log("Missing fidonet node in command line");
  259. X      exit(1);
  260. X    }
  261. X
  262. X  /* try to update nodelist-index */
  263. X  if (error = update_index())
  264. X    {
  265. X      if (*error == '$')
  266. X        log("$Cannot update nodelist-index: %s", error + 1);
  267. X      else
  268. X        log("Cannot update nodelist-index: %s", error);
  269. X      exit(EX_OSERR);
  270. X    }
  271. X
  272. X  /* goto spool directory, everything exiting happens there... */
  273. X  if (chdir(SPOOL) == -1)
  274. X    {
  275. X      log("$Can not chdir to %s", SPOOL);
  276. X      exit(1);
  277. X    }
  278. X
  279. X  /* create packet name */
  280. X  sprintpacketname(packet_name, node);
  281. X
  282. X  if (access(sprintfs("out/%s", packet_name), 0) == 0) {
  283. X    debug(1, "Packet out/%s exists, append to it", packet_name);
  284. X    if ((packet = fopen(sprintfs("out/%s", packet_name), "r+")) == NULL)
  285. X      {
  286. X        log("$Can not open out/%s for update", packet_name);
  287. X        exit(1);
  288. X      }
  289. X    (void) fseek(packet, -2l, 2);
  290. X  }
  291. X  else {
  292. X    debug(1, "New packet out/%s", packet_name);
  293. X    if ((packet = fopen(sprintfs("out/%s", packet_name), "w")) == NULL)
  294. X      {
  295. X        log("$Can not open packet out/%s for writing", packet_name);
  296. X        exit(1);
  297. X      }
  298. X
  299. X    /* protect packet from users...*/
  300. X    (void) chmod(sprintfs("out/%s", packet_name), 0600);
  301. X
  302. X    /* write packet-header, if it fails, exit */
  303. X    if (!write_pkthdr(packet))
  304. X      {
  305. X        (void) unlink(sprintfs("out/%s", packet_name));
  306. X        exit(1);
  307. X      }
  308. X  }
  309. X
  310. X  /* lock packet, wait if it's alredy locked */
  311. X  while (lock(fileno(packet)) == -1 && errno == EAGAIN)
  312. X    (void) sleep((unsigned) 1);
  313. X
  314. X  /* open spool directory */
  315. X  if (dp = opendir("."))
  316. X    {
  317. X      while (dir = readdir(dp))
  318. X        {
  319. X          /* check that file is for us */
  320. X          if (*dir->d_name == 'M' && dir->d_name[1] == '.')
  321. X            {
  322. X              if (msg = fopen(dir->d_name, "r"))
  323. X                {
  324. X                  debug(1, "Adding mailfile %s", dir->d_name);
  325. X
  326. X                  /* save header */
  327. X                  if (write_hdr(msg, packet))
  328. X                    {
  329. X                      /* copy mail text, replace newlines with <cr> <lf> */
  330. X                      while ((c = getc(msg)) && c != EOF)
  331. X                        {
  332. X                          if (c == '\n')
  333. X                            (void) putc('\r', packet);
  334. X                          (void) putc(c, packet);
  335. X                        }
  336. X                      /* null-terminate msg text */
  337. X                      (void) putc(0, packet);
  338. X                    }
  339. X                  (void) fclose(msg);
  340. X                  if (unlink(dir->d_name) == -1)
  341. X                    log("$Unable to unlink %s", dir->d_name);
  342. X                }
  343. X              else
  344. X                log("$Can not open mail %s for reading", dir->d_name);
  345. X            }
  346. X        }
  347. X      (void) closedir(dp);
  348. X    }
  349. X  else
  350. X    {
  351. X      log("$Can not open spool directory %s", SPOOL);
  352. X      exit(1);
  353. X    }
  354. X
  355. X  /* msg type 0 indicates end of packet */
  356. X  (void) write_int(packet, 0);
  357. X
  358. X  (void) fclose(packet);
  359. X
  360. X  exit(0);
  361. X  /* NOTREACHED */
  362. X}
  363. X
  364. X
  365. SHAR_EOF
  366. echo "File fpack.c is complete"
  367. chmod 0644 fpack.c || echo "restore of fpack.c fails"
  368. echo "x - extracting funpack.c (Text)"
  369. sed 's/^X//' << 'SHAR_EOF' > funpack.c &&
  370. X#ifndef lint
  371. Xstatic char *sccsid = "@(#)%M%  %I%  Teemu Torma %H%";
  372. X#endif
  373. X
  374. X/* Unpaketize fido-mail packets and send mail to reciver or send it to
  375. X   news-server.
  376. X
  377. X   @(#)Copyright (c) 1987 by Teemu Torma
  378. X
  379. X   Permission is given to distribute this program and alter this code as
  380. X   needed to adapt it to forign systems provided that this header is
  381. X   included and that the original author's name is preserved. */
  382. X
  383. X#include <stdio.h>
  384. X#include <ctype.h>
  385. X#include <string.h>
  386. X#include <sys/types.h>
  387. X#include <varargs.h>
  388. X#include <time.h>
  389. X#include <dirent.h>
  390. X#include "hsu.h"
  391. X#include "config.h"
  392. X#include "fnet.h"
  393. X#include "fpack.h"
  394. X#include "nodelist.h"
  395. X#include "sysexits.h"
  396. X#include "fnews.h"
  397. X
  398. X#define MAXARGS (32) /* maximum number of arguments */
  399. X
  400. Xextern time_t time();
  401. Xextern char *tzname[];
  402. Xextern int getopt();
  403. Xextern int optind;
  404. Xextern char *optarg;
  405. Xextern void exit(), perror(), free();
  406. Xextern char *malloc();
  407. Xextern time_t dateconv();
  408. Xextern void swab();
  409. X
  410. Xint verbose = INIT_VERBOSE;
  411. Xint newsmode = FALSE;
  412. Xint acceptprivate = FALSE;
  413. Xint trashprivate = FALSE;
  414. X
  415. X#ifdef SCCS
  416. Xchar *version = "%I%";
  417. X#else
  418. Xchar *version = PROGRAMNAME;
  419. X#endif
  420. X
  421. X/* Test if string is totally numeric. */
  422. X
  423. Xbool
  424. Xnumeric(s)
  425. X     register char *s;
  426. X{
  427. X  while (*s)
  428. X    if (!isdigit(*s++))
  429. X      return False;
  430. X  return True;
  431. X}
  432. X
  433. X/* Return msdos interger as machine integer */
  434. X
  435. Xint
  436. Xint16(msint)
  437. X     INT16 msint;
  438. X{
  439. X  static INT16 value;
  440. X
  441. X#ifdef SWAB_BYTES
  442. X  swab((char *) &msint, (char *) &value, 2);
  443. X#else
  444. X  value = msint;
  445. X#endif
  446. X  return (int) value;
  447. X}
  448. X
  449. Xstatic FILE *badtemp = NULL;
  450. X
  451. X/*VARARGS2*/
  452. Xtprintf(fp, fmt, va_alist)
  453. X     FILE *fp;
  454. X     char *fmt;
  455. X{
  456. X  char buffer[BUFSIZ];
  457. X  va_list pvar;
  458. X
  459. X  va_start(pvar);
  460. X  vsprintf(buffer, fmt, pvar);
  461. X  fputs(buffer, fp);
  462. X  if (badtemp) fputs(buffer, badtemp);
  463. X  va_end(pvar);
  464. X}
  465. X
  466. Xtputs(buffer, fp)
  467. X     char *buffer;
  468. X     FILE *fp;
  469. X{
  470. X  fputs(buffer, fp);
  471. X  if (badtemp) fputs(buffer, badtemp);
  472. X}
  473. X
  474. X#define tputc(c, fp) putc(c, fp); if (badtemp) putc(c, badtemp);
  475. X
  476. X/* Replacement for fgets(3S) to understand cr's generated by Fido
  477. X   and 'soft' cr's generated by SEAdog. It return EOF if text is over,
  478. X   ie. 0 is got from file.
  479. X
  480. X   Sat Oct  1 10:15:46 1988
  481. X   Must notice cr without linefeed, as confmail seems to send
  482. X   strange ids without lf.
  483. X
  484. X   Mon Oct  3 01:51:01 1988
  485. X   Notice * Origin header and extract node from it. Useless time consumer
  486. X   when looking for mail.
  487. X   */
  488. X
  489. Xstatic char *
  490. Xffgets(buffer, maxlen, fp)
  491. X     char *buffer;
  492. X     int maxlen;
  493. X     FILE *fp;
  494. X{
  495. X  register int c, ch, index;
  496. X  register char *cp;
  497. X  char buf[BUFSIZ];
  498. X  static char wordsave[BUFSIZ];
  499. X  /* TRUE if last line was origin line without valid node */
  500. X  static int last_line_was_origin = FALSE;
  501. X  /* TRUE if last character caused line wrap */
  502. X  static int last_char_wrapped = FALSE;
  503. X  Node node;
  504. X
  505. X  /* There might be wrapped word lying around */
  506. X  if (*wordsave)
  507. X    {
  508. X      strcpy(buffer, wordsave);
  509. X      strsclean(buffer);
  510. X      debug(20, "Picked up word '%s'", buffer);
  511. X      *wordsave = 0;
  512. X    }
  513. X  else
  514. X    *buffer = 0;
  515. X
  516. X  cp = buffer + strlen(buffer);
  517. X
  518. X  while (--maxlen > 0 && (c = getc(fp)) != EOF && c)
  519. X    {
  520. X      /* Hard carriage return */
  521. X
  522. X      if (c == '\r')
  523. X    c = '\n';
  524. X      else if (c == '\n' || c == 0x8d || c == '\215')
  525. X    {
  526. X      /* Forget about these ! */
  527. X      continue;
  528. X    }
  529. X      else
  530. X    if (c == '\001')
  531. X      {
  532. X        /* Kludge. Stupid idea to put control chars to messages,
  533. X           but thats the way it is, replace with something which
  534. X           doesn't make programs expecting ascii mad */
  535. X        strncpy(cp, "FSC-Control:", 12);
  536. X        cp += 12;
  537. X        c = ' ';
  538. X      }
  539. X
  540. X      /* If last character caused line wrap, and we now got another
  541. X     linefeed, skip this linefeed to avoid unneeded empty lines. */
  542. X
  543. X      if (last_char_wrapped)
  544. X    {
  545. X      if (c == '\n')
  546. X        {
  547. X          last_char_wrapped = FALSE;
  548. X          continue;
  549. X        }
  550. X
  551. X      if (isspace(c) && strempty(buffer)) continue;
  552. X    }
  553. X
  554. X      *cp++ = c;
  555. X
  556. X      if (c == '\n')
  557. X        break;
  558. X
  559. X      *cp = 0;
  560. X
  561. X      /* Try to wrap if line is too long and it is not a seen-by, origin
  562. X     or path line. */
  563. X      if (strlen(buffer) >= MAX_LINELEN - 1 &&
  564. X      strncmp(" * Origin:", buffer, 10) &&
  565. X      strncmp("SEEN-BY:", buffer, 8) &&
  566. X      strncmp("FSC-Control:", buffer, 12)) /* - 1 for \n */
  567. X    {
  568. X      last_char_wrapped = TRUE;
  569. X
  570. X      /* Search for place to cut */
  571. X      for (index = strlen(buffer) - 1; index >= 0; index--)
  572. X        {
  573. X          c = buffer[index];
  574. X          if (index <= MAX_LINELEN / 3)
  575. X        {
  576. X          /* Too long, cut. */
  577. X          *cp++ = c = '\n';
  578. X          goto collected;
  579. X        }
  580. X
  581. X          /* Note: [\]{|}@` are not considered punctuation because
  582. X         they are used in some countries for national characters. */
  583. X          if (isspace(c) || (ispunct(c) && !strchr("[\\]{|}@`", c)))
  584. X        {
  585. X          /* Wrap here! */
  586. X          cp = buffer + index + 1; /* Punctuation left on this line */
  587. X          strcpy(wordsave, cp);
  588. X          debug(20, "saving word '%s'", wordsave);
  589. X          *cp++ = c = '\n';
  590. X          goto collected;
  591. X        }
  592. X        }
  593. X    }
  594. X
  595. X      last_char_wrapped = FALSE;
  596. X    }
  597. X
  598. X collected:
  599. X
  600. X  /* if we got nul, put it back if occurred in the middle of line */
  601. X  if (!c && cp != buffer)
  602. X    (void) ungetc(0, fp);
  603. X
  604. X  *cp = 0; /* Cut it here */
  605. X
  606. X  /* This is really nasty part: Try to work out reply-to path from
  607. X     origin for those people who don't have node in nodelist.
  608. X     This should handle both situations where origin line is split by
  609. X     some stupid mailer, or because origin line was too long (sysops,
  610. X     please don't use long system identifiers, it causes lots of trouble!).
  611. X     It checks that line doesn't start with SEEN-BY: or FSC-Control as
  612. X     those things generally follow origin lines. */
  613. X
  614. X  if (!strncmp(" * Origin:", buffer, 10) || last_line_was_origin) {
  615. X    char *left, *right;
  616. X
  617. X    if (last_line_was_origin)
  618. X      {
  619. X    last_line_was_origin = FALSE;
  620. X    /* If its seen-by or control, it probably isn't continuation! */
  621. X    if (!strncmp("SEEN-BY:", buffer, 8) ||
  622. X        !strncmp("FSC-Control:", buffer, 12))
  623. X      goto out;
  624. X      }
  625. X    else
  626. X      last_line_was_origin = TRUE;
  627. X
  628. X    strcpy(buf, buffer);
  629. X    right = buf;
  630. X
  631. X    for (;;)
  632. X      {
  633. X    if ((left = strchr(right, '(')) && (right = strchr(left + 1, ')')))
  634. X      {
  635. X        *right = 0;
  636. X        if (parsefnetaddress(++left, &node))
  637. X          {
  638. X        debug(1, "Could not parse %s", left);
  639. X          }
  640. X        else
  641. X          {
  642. X        memcpy( (char *) &originnode, (char *) &node, sizeof(Node));
  643. X        debug(1, "Parsed %s to %d:%d/%d.%d", left, originnode.zone,
  644. X              originnode.net, originnode.node, originnode.point);
  645. X          }
  646. X        left = ++right;
  647. X      }
  648. X    else
  649. X      break;
  650. X      }
  651. X  }
  652. X
  653. X out:
  654. X  return ((!c || c == EOF) && cp == buffer) ? (char *) 0 : buffer;
  655. X}
  656. X
  657. X/* Execute sender of fido-message. Argument will be program name, anrgument
  658. X   for that and pid to return. If command is not empty, use it instead
  659. X   of given program and build parameter table. */
  660. X
  661. Xstatic char command[64];
  662. X
  663. XFILE *
  664. Xopen_sender(program, args, pid)
  665. X     char *program, **args;
  666. X     int *pid;
  667. X{
  668. X  FILE *fp;
  669. X  int fd[2], count = 0;
  670. X  char *p, *realargs[MAXARGS];
  671. X  char *cmd, *realprogram;
  672. X
  673. X  cmd = alloca(strlen(command) + 1);
  674. X  strcpy(cmd, command);
  675. X
  676. X  if (*cmd)
  677. X    {
  678. X      while (p = strtok(cmd, SEPARATORS))
  679. X    {
  680. X      realargs[count++] = p;
  681. X      cmd = NULL; /* For strtok */
  682. X    }
  683. X
  684. X      realargs[count++] = NULL;
  685. X      realprogram = *realargs;
  686. X
  687. X      if (realprogram)
  688. X    {
  689. X      program = realprogram;
  690. X      args = realargs;
  691. X    }
  692. X    }
  693. X
  694. X  if (pipe(fd) == -1)
  695. X    {
  696. X      perror("funpack: pipe");
  697. X      return (FILE *) 0;
  698. X    }
  699. X
  700. X  switch (*pid = fork())
  701. X    {
  702. X    case -1:
  703. X      perror("funpack: fork failed");
  704. X      return (FILE *) 0;
  705. X    case 0:
  706. X      (void) close(0);
  707. X      if (dup(fd[0]) == 0)
  708. X        {
  709. X          (void) close(fd[0]);
  710. X          (void) close(fd[1]);
  711. X          if (args)
  712. X            (void) execvp(program, args);
  713. X          else
  714. X            (void) execlp(program, basename(program), (char *) 0);
  715. X          perror(program);
  716. X        }
  717. X      else
  718. X        perror("funpack: dup");
  719. X      exit(EX_OSERR);
  720. X    default:
  721. X      (void) close(fd[0]);
  722. X      if ((fp = fdopen(fd[1], "w")) == NULL)
  723. X        {
  724. X          perror("funpack: fdopen");
  725. X          return (FILE *) 0;
  726. X        }
  727. X    }
  728. X  return fp;
  729. X}
  730. X
  731. Xstatic Packet header;
  732. X
  733. Xread_header(fp)
  734. X     FILE *fp;
  735. X{
  736. X  FGETINT16(header.orig_node, fp);
  737. X  FGETINT16(header.dest_node, fp);
  738. X  FGETINT16(header.year, fp);
  739. X  FGETINT16(header.month, fp);
  740. X  FGETINT16(header.day, fp);
  741. X  FGETINT16(header.hour, fp);
  742. X  FGETINT16(header.minute, fp);
  743. X  FGETINT16(header.second, fp);
  744. X  FGETINT16(header.rate, fp);
  745. X  FGETINT16(header.ver, fp);
  746. X  FGETINT16(header.orig_net, fp);
  747. X  FGETINT16(header.dest_net, fp);
  748. X  header.product = getc(fp);
  749. X  header.x1 = getc(fp);
  750. X  FREAD(header.pwd_kludge, 8, 1, fp);
  751. X  FGETINT16(header.orig_zone, fp);
  752. X  if (header.orig_zone == 0) header.orig_zone = int16(MY_ZONE);
  753. X  FGETINT16(header.dest_zone, fp);
  754. X  if (header.dest_zone == 0) header.dest_zone = int16(MY_ZONE);
  755. X  FREAD(header.B_fill2, 16, 1, fp);
  756. X  FREAD( (char *) &header.B_fill3, 4, 1, fp);
  757. X  return ferr(fp);
  758. X}
  759. X
  760. X/* Return int from file. Int in file is supposed to be 16 bit ms-dos
  761. X   integer. */
  762. X
  763. Xint
  764. Xread_int(fp)
  765. X     FILE *fp;
  766. X{
  767. X  static INT16 value;
  768. X
  769. X  if (fread((char *) &value, 2, 1, fp) != 1)
  770. X    {
  771. X      if (ferr(fp))
  772. X    log("Cannot read file, errno %d : %s", errno, sys_errlist[errno]);
  773. X
  774. X      value = 0;
  775. X    }
  776. X
  777. X  debug(8, "< %02x(%ld)", int16(value), ftell(fp));
  778. X  return int16(value);
  779. X}
  780. X
  781. X/* Read null-terminated string from file. Ensure that buffer is also
  782. X   null-terminated. Remove possible \n:s from end, they are generated by
  783. X   some buggy mailers. */
  784. X
  785. Xvoid
  786. Xget_string(buffer, fp, nbytes)
  787. X     char *buffer;
  788. X     FILE *fp;
  789. X     int nbytes;
  790. X{
  791. X  register int n;
  792. X  char *p;
  793. X
  794. X  debug(8, "get string start %ld", ftell(fp));
  795. X
  796. X  for (n = 0, *buffer = 0; n < nbytes; n++)
  797. X    if ((buffer[n] = getc(fp)) == 0)
  798. X      break;
  799. X    else
  800. X      debug(8, "<%d %c>", buffer[n], buffer[n]);
  801. X
  802. X  /* If still more chars in buffer, skip them until null char found */
  803. X  if (n >= nbytes)
  804. X    {
  805. X      debug(8, "Skipping rest");
  806. X      while(getc(fp));
  807. X    }
  808. X
  809. X  buffer[nbytes] = 0;
  810. X
  811. X  /* Remove \n from end if its there, its a bug */
  812. X  if (p = strchr(buffer, '\n')) *p = 0;
  813. X
  814. X  debug(8, "Getstring at %ld %s", ftell(fp), buffer);
  815. X}
  816. X
  817. X#define NGFLAG_ACCEPT_PRIVATE 0
  818. X#define NGFLAG_COMMAND 1
  819. X#define NGFLAG_TRASH_PRIVATE 2
  820. X
  821. Xstatic char distribution[64];
  822. Xstatic char *ngflags[] = { "accept-private", "command", "trash-private", "" };
  823. X
  824. X/* Like strtok but returns empty string instead of null if no more thigns
  825. X   found */
  826. X
  827. Xchar *estrtok(s, sep)
  828. X     char *s, *sep;
  829. X{
  830. X  char *p;
  831. X
  832. X  if (p = strtok(s, sep)) return p;
  833. X  return "";
  834. X}
  835. X
  836. Xchar *
  837. Xget_ng(config, echo, distrib)
  838. X     FILE *config;
  839. X     char *echo, *distrib;
  840. X{
  841. X  static char conv[BUFLEN];
  842. X  char *gr, *flag;
  843. X
  844. X  debug(2, "Checking echolist '%s'", echo);
  845. X
  846. X  *command = 0;
  847. X  section(SECT_AREA_NG, config);
  848. X  trashprivate = FALSE;
  849. X  acceptprivate = FALSE;
  850. X  while (getcl(conv, BUFLEN, config))
  851. X    {
  852. X      debug(3, "Config line '%s'", conv);
  853. X
  854. X      gr = estrtok(conv, SEPARATORS);
  855. X      if (!strcmp(gr, echo))
  856. X    {
  857. X      /* Matched, take distribution and return newsgroup */
  858. X
  859. X      gr = estrtok(NULL, SEPARATORS);
  860. X      strcpy(distrib, estrtok(NULL, SEPARATORS));
  861. X      while (flag = strtok(NULL, SEPARATORS))
  862. X        switch(listscan(ngflags, flag))
  863. X          {
  864. X           case NGFLAG_ACCEPT_PRIVATE:
  865. X        acceptprivate = TRUE;
  866. X        break;
  867. X
  868. X           case NGFLAG_COMMAND:
  869. X        /* Fails if fnews.cf has DEL char in it, but thats
  870. X           mostly a philosophical question. */
  871. X        strcpy(command, estrtok(NULL, "\377"));
  872. X        break;
  873. X
  874. X           case NGFLAG_TRASH_PRIVATE:
  875. X        trashprivate = TRUE;
  876. X        break;
  877. X
  878. X           case -1:
  879. X           default:
  880. X        log("Bad flag '%s' for newsgroup %s", flag, gr);
  881. X        break;
  882. X          }
  883. X
  884. X      debug(3, "Match, return newsgroup '%s', distribution %s",
  885. X        gr, distrib);
  886. X      return gr;
  887. X    }
  888. X    }
  889. X  log("No newsgroup for '%s' found, return junk, distribution local", echo);
  890. X  strcpy(distrib, "local");
  891. X  return "junk";
  892. X}
  893. X
  894. X/* Check if message is news-message (currenlty: if first line begins
  895. X   with AREA:). If area is found, we'll return name for that area,
  896. X   otherwise NULL. */
  897. X
  898. Xchar *
  899. Xnews_msg(fp)
  900. X     FILE *fp;
  901. X{
  902. X  FILE *config;
  903. X  long offset = ftell(fp);
  904. X  char *cp;
  905. X  static char area[64];
  906. X
  907. X  if (ffgets(area, 64, fp) && !strncmp(area, "AREA:", 5))
  908. X    {
  909. X      /* this is echomail-message */
  910. X      area[strlen(area) - 1] = 0;
  911. X
  912. X      /* strip possible spaces */
  913. X      for (cp = area + 5; *cp && isspace(*cp); cp++);
  914. X
  915. X      if ((config = pfopen(LIBDIR, "fnews.cf", "r")) == NULL)
  916. X    {
  917. X      log("$Unable to open config file");
  918. X      exit(1);
  919. X    }
  920. X
  921. X      strcpy(cp, get_ng(config, cp, distribution));
  922. X      fclose(config);
  923. X
  924. X      /* return converted area-name */
  925. X      return cp;
  926. X    }
  927. X  else
  928. X    {
  929. X      /* this is not echomail message, seek back */
  930. X      (void) fseek(fp, offset, 0);
  931. X      return (char *) 0;
  932. X    }
  933. X  /* NOTREACHED */
  934. X}
  935. X
  936. X/* Return date of message. Date will be read and converted to one
  937. X   long-interger as normal Unix-time will be.
  938. X
  939. X   Both SEAdog and Fido date formats are understood.
  940. X   SEAgod: Mon 1 Jan 86 02:34
  941. X   Fido:   01 Jan 86 02:34:56 */
  942. X
  943. Xtime_t
  944. Xlgetdate(packet)
  945. X     FILE *packet;
  946. X{
  947. X  char buffer[20];
  948. X  int c;
  949. X  time_t timevar;
  950. X  int n;
  951. X
  952. X  /* read date from packet */
  953. X  for (n = 0; n < 20; n++)
  954. X    if ((buffer[n] = getc(packet)) == NULL) break;
  955. X
  956. X  /* Some message-packers do mistakes! Date should be 20 bytes but
  957. X     they start name directly after null terminating 18-char date
  958. X     used in some systems. Check if following char is null or not,
  959. X     and if not, put it back there as it probably is first char in
  960. X     recipent name. This seems to be problem in OMMM, but I'm not
  961. X     sure yet.
  962. X
  963. X     Wed Nov 16 21:11:34 1988 Seems that the bug is in fsc001, as
  964. X     I constantly keep receiving messages which 19 byte date?
  965. X     */
  966. X
  967. X#ifdef FSC_IS_REALLY_CORRECT
  968. X  for (n++; n < 20; n++)
  969. X    if (c = getc(packet))
  970. X      {
  971. X    ungetc(c, packet);
  972. X      }
  973. X#endif
  974. X
  975. X  buffer[19] = 0;
  976. X  debug(8, "Getdate %s at %ld", buffer, ftell(packet));
  977. X
  978. X  /* try to get date */
  979. X  timevar = getdate(buffer, (struct timeb *) NULL);
  980. X  return timevar;
  981. X}
  982. X
  983. X/* Remove 'of net/node' from name. Number will be saved
  984. X   for later use and used as reply-to address, as I think most users use
  985. X   it as their home system or if they are sysops, as their node. */
  986. X
  987. Xsearch_node(from, node)
  988. X     char *from;
  989. X     Node *node;
  990. X{
  991. X  char *s, *p, *of;
  992. X  Node tempnode;
  993. X
  994. X  s = alloca(strlen(from) + 1);
  995. X  strcpy(s, from);
  996. X
  997. X  p = strtok(s, WHITESPACE);
  998. X  while (p)
  999. X    {
  1000. X      if (!stricmp(p, "of"))
  1001. X    {
  1002. X      of = p;
  1003. X      /* Skip possible multiple 'of's */
  1004. X      for (; (p = strtok(NULL, WHITESPACE)) && !stricmp(p, "of"););
  1005. X      /* Of and something else follows, try to parse */
  1006. X      if (p)
  1007. X        {
  1008. X          if (!parsefnetaddress(p, &tempnode))
  1009. X        {
  1010. X          if (node) *node = tempnode;
  1011. X          /* Of net/node should be the last string */
  1012. X          if ((p = strtok(NULL, WHITESPACE)) == NULL)
  1013. X            {
  1014. X              /* Remove 'of ...' from name */
  1015. X              *(from + (int) (of - s)) = 0;
  1016. X              strclean(from);
  1017. X              return; /* Found it */
  1018. X            }
  1019. X          else
  1020. X            continue; /* Something follows, try again */
  1021. X        }
  1022. X        }
  1023. X      else
  1024. X        return; /* no more stuff */
  1025. X    }
  1026. X      p = strtok(NULL, WHITESPACE);
  1027. X    }
  1028. X  return;
  1029. X}
  1030. X
  1031. X/* Remove userids from names, like "James Smith (SMITH)" will become
  1032. X   "James Smith". Simple algorithm now, but its enough. Scandinvian
  1033. X   chars are translated to a and o, and other special chars are
  1034. X   removed. */
  1035. X
  1036. Xremove_id(name)
  1037. X     char *name;
  1038. X{
  1039. X  char *p, *cp;
  1040. X
  1041. X  if (p = strchr(name, '(')) {
  1042. X    while (*p != ')' && *p)
  1043. X      for (cp = p; *cp = *(cp + 1); cp++); /* Remove one char */
  1044. X
  1045. X    if (*p == ')')
  1046. X      for (cp = p; *cp = *(cp + 1); cp++); /* Remove last ) */
  1047. X  }
  1048. X
  1049. X  /* Remove blanks from the end */
  1050. X  while (strlen(name) && isspace(name[strlen(name) - 1]))
  1051. X    name[strlen(name) - 1] = 0;
  1052. X  (void) ascii_convert(name);
  1053. X  fine_convert(name);
  1054. X  stripbad(name);
  1055. X}
  1056. X
  1057. X/* Search alias name which matches with fidonet name, return NULL
  1058. X   if no alias specified. */
  1059. X
  1060. Xchar *get_alias(name)
  1061. X     char *name;
  1062. X{
  1063. X  char buffer[BUFSIZ];
  1064. X  char *cp;
  1065. X  FILE *fp;
  1066. X  static char unixname[BUFSIZ], fidoname[BUFSIZ];
  1067. X
  1068. X  if (fp = fopen(ALIAS, "r"))
  1069. X    {
  1070. X      while (fgets(buffer, BUFSIZ, fp))
  1071. X    {
  1072. X      buffer[strlen(buffer) - 1] = 0;
  1073. X      if (*buffer != '#')
  1074. X        {
  1075. X          if ((cp = strchr(buffer, ' ')) ?
  1076. X          cp : (cp = strchr(buffer, '\t')))
  1077. X        {
  1078. X          *cp = 0; /* Break unixname out */
  1079. X          strcpy(unixname, buffer); /* And save it */
  1080. X          debug(8, "Unix name %s", unixname);
  1081. X        }
  1082. X          else
  1083. X        {
  1084. X          /* No space or tab found, probably bad line */
  1085. X          debug(1, "Bad alias line %s", buffer);
  1086. X          continue;
  1087. X        }
  1088. X
  1089. X          /* Search for name start, there may be space between */
  1090. X          cp++;
  1091. X          while (*cp && isspace(*cp)) cp++;
  1092. X          if (!*cp)
  1093. X        {
  1094. X          debug(1, "Bad alias line %s", buffer);
  1095. X          continue;
  1096. X        }
  1097. X
  1098. X          strcpy(fidoname, cp); /* Save fidonet name */
  1099. X          debug(8, "Fidoname %s", fidoname);
  1100. X
  1101. X          if (!stricmp(fidoname, name))
  1102. X        {
  1103. X          fclose(fp);
  1104. X
  1105. X          /* There may be node specs after name, null them out */
  1106. X          if (cp = strchr(unixname, ',')) *cp = 0;
  1107. X
  1108. X          debug(8, "Fidoname %s matched with %s, return %s",
  1109. X            fidoname, name, unixname);
  1110. X          return unixname;
  1111. X        }
  1112. X        }
  1113. X    }
  1114. X    }
  1115. X
  1116. X  fclose(fp);
  1117. X  return NULL;
  1118. X}
  1119. X
  1120. X/* Save bad article from file given to bad directory */
  1121. X
  1122. Xsavebad(fp)
  1123. X     FILE *fp;
  1124. X{
  1125. X  char *fname, buffer[BUFSIZ];
  1126. X  FILE *badfile;
  1127. X
  1128. X  log("Saving bad article/mail to %s",
  1129. X      fname = sprintfs("%s/bad%ld", BADARTICLES, sequencer(BADSEQ)));
  1130. X  if (badfile = fopen(fname, "w+"))
  1131. X    {
  1132. X      rewind(fp);
  1133. X      while (fgets(buffer, BUFSIZ, fp))
  1134. X    fputs(buffer, badfile);
  1135. X    }
  1136. X  else
  1137. X    {
  1138. X      log("$Could not open bad article file");
  1139. X      return -1;
  1140. X    }
  1141. X  fclose(badfile);
  1142. X  return 0;
  1143. X}
  1144. X
  1145. X/* Unpack packet and all files in it. Packet's header will be stripped
  1146. X   off. For each message check if it is news-msg (First line begins
  1147. X   with AREA:). If it is, send it to news-sender sfnews, otherwise
  1148. X   send it to rmail. Address is given in to-field, or if it wont
  1149. X   fit to it, in the first line of message. In later case to-field
  1150. X   must be "Usenet". */
  1151. X
  1152. Xvoid
  1153. Xunpack(packet, packetnode)
  1154. X     FILE *packet;
  1155. X     Node packetnode;
  1156. X{
  1157. X  int count, attributes, messagetype;
  1158. X  char to[36], from[36], realto[40], realfrom[40], subject[72];
  1159. X  char badname[BUFSIZ];
  1160. X  char *args[MAXARGS];
  1161. X  char buffer[BUFSIZ], *cp, *p;
  1162. X  FILE *sender, *newssender;
  1163. X  int n, pid, stat_loc, c;
  1164. X  Node *entry, mynode, orignode, destnode, fromnode;
  1165. X  char hostname[10];
  1166. X  time_t msg_date;
  1167. X  char *area;
  1168. X
  1169. X  /* get node-entry fo packet-sender */
  1170. X  if (node_entry(packetnode) == NULL)
  1171. X    {
  1172. X      log("Unknown packet sender: %s", ascnode(packetnode));
  1173. X      return;
  1174. X    }
  1175. X
  1176. X  mynode.zone = MY_ZONE;
  1177. X  mynode.net = MY_NET;
  1178. X  mynode.node = MY_NODE;
  1179. X  mynode.point = MY_POINT;
  1180. X
  1181. X  if ((entry = node_entry(mynode)) == NULL)
  1182. X    {
  1183. X      log("Unable to find this net/node from nodelist");
  1184. X      return;
  1185. X    }
  1186. X
  1187. X  /* get our uucp-nodename */
  1188. X  if (gethostname(hostname, 10) == -1)
  1189. X    {
  1190. X      log("$Unable to get hostname");
  1191. X      return;
  1192. X    }
  1193. X
  1194. X  while ((messagetype = read_int(packet)) == MSGTYPE)
  1195. X    {
  1196. X      *args = NULL;
  1197. X      originnode.zone = -1;
  1198. X      fromnode.zone = -1;
  1199. X      orignode.zone = packetnode.zone; /* Orignode zone and point are not */
  1200. X      orignode.point = packetnode.point; /* included in messages. */
  1201. X      destnode.zone = packetnode.zone;
  1202. X      destnode.point = packetnode.point;
  1203. X
  1204. X      /* get nodes information about message */
  1205. X      orignode.node = read_int(packet);
  1206. X      destnode.node = read_int(packet);
  1207. X
  1208. X      /* get nodes from message */
  1209. X      orignode.net = read_int(packet);
  1210. X      destnode.net = read_int(packet);
  1211. X
  1212. X      debug(2, "Original net/node = %s", ascnode(orignode));
  1213. X      debug(2, "Destination net/node = %s", ascnode(destnode));
  1214. X
  1215. X      /* we're not interested about attributes currenty */
  1216. X      attributes = read_int(packet);
  1217. X
  1218. X      /* through away cost */
  1219. X      (void) read_int(packet);
  1220. X
  1221. X      /* get date */
  1222. X      msg_date = lgetdate(packet);
  1223. X
  1224. X      /* get receiver of message */
  1225. X      get_string(to, packet, 35);
  1226. X      search_node(to, (Node *) NULL);
  1227. X      remove_id(to);
  1228. X      debug(2, "Msg is to '%s'", to);
  1229. X
  1230. X      /* get sender of message */
  1231. X      get_string(from, packet, 35);
  1232. X      search_node(from, &fromnode);
  1233. X      remove_id(from);
  1234. X      debug(2, "Msg is from '%s'", from);
  1235. X
  1236. X      /* get subject */
  1237. X      get_string(subject, packet, 71);
  1238. X
  1239. X      /* Remove trailing blanks */
  1240. X      for (count = strlen(subject) - 1; count >= 0 && isspace(subject[count]);
  1241. X       count--) subject[count] = 0;
  1242. X
  1243. X      /* News expects some kind of subject and ignores the message
  1244. X     without one? */
  1245. X      if (!*subject) strcpy(subject, "No subject");
  1246. X
  1247. X      debug(2, "Subject is '%s'", subject);
  1248. X
  1249. X      /* check that message is to this node */
  1250. X      if (!samenode(destnode, mynode))
  1251. X        {
  1252. X          log("Msg from %s to %s at %s: wrong node address",
  1253. X          from, to, ascnode(destnode));
  1254. X          goto error;
  1255. X        }
  1256. X
  1257. X      /* check if this is news-message. Private messages will not
  1258. X         be forwarded to readnews, they go to mail, if received is
  1259. X     known, otherwise they will be thrown away. Exception are
  1260. X     conferences which are marked accept-private. */
  1261. X      newsmode = FALSE;
  1262. X      if ((area = news_msg(packet)) &&
  1263. X      (acceptprivate || !(attributes & ATTR_PRIVATE)))
  1264. X    {
  1265. X      /* This is news-artcile. Open sendfidonews and give area name as
  1266. X         argument to it. Input of sfnews will be just like input
  1267. X         of mail. */
  1268. X
  1269. X      debug(1, "Message is news-article");
  1270. X      newsmode = TRUE;
  1271. X
  1272. X      /* create args for sender */
  1273. X      *args = strsave(RNEWS);
  1274. X#ifdef NEEDED
  1275. X      args[1] = strsave(area);
  1276. X      args[2] = NULL;
  1277. X#else
  1278. X      args[1] = NULL;
  1279. X#endif
  1280. X      /* open sender */
  1281. X      if (!(sender = tmpfile()))
  1282. X        {
  1283. X          log("Can not create temp file, errno %d: %s",
  1284. X          errno, sys_errlist[errno]);
  1285. X          goto error;
  1286. X        }
  1287. X
  1288. X      if ((newssender = open_sender(*args, args, &pid)) == NULL)
  1289. X        {
  1290. X          log("Can not execute %s", *args);
  1291. X          goto error;
  1292. X        }
  1293. X
  1294. X      badtemp = NULL; /* tmp file for news messages will be
  1295. X                 created later. */
  1296. X        }
  1297. X      else
  1298. X        {
  1299. X          debug(1, "Message is for mail");
  1300. X      if (area)
  1301. X        {
  1302. X          debug(1, "Private message for area %s", area);
  1303. X          if (trashprivate) goto error;
  1304. X        }
  1305. X
  1306. X          /* If message receiver is Usenet, then receiver of mail will
  1307. X             be at first-line of message separated by commands/spaces.
  1308. X             If receiver is not usenet, mail will be sent to normal
  1309. X             receiver, but in this case all charactes will be converted
  1310. X             to lower case (Fido changes them, you know). */
  1311. X
  1312. X          if (!strcmp(to, "Usenet"))
  1313. X            {
  1314. X              if (ffgets(buffer, BUFSIZ, packet) == NULL)
  1315. X                {
  1316. X                  log("Missing receiver in msg from %s at %s", from,
  1317. X                      ascnode(orignode));
  1318. X                  goto error;
  1319. X                }
  1320. X              buffer[strlen(buffer) - 1] = 0;
  1321. X            }
  1322. X          else
  1323. X            {
  1324. X          debug(8, "Searching alias for %s", to);
  1325. X          if (p = get_alias(to))
  1326. X        {
  1327. X          (void) strcpy(buffer, p);
  1328. X          debug(8, "Got alias %s", buffer);
  1329. X        }
  1330. X          else
  1331. X        {
  1332. X          if (area)
  1333. X            {
  1334. X              log("Skipping private echo for %s", to);
  1335. X              goto error; /* If private echo message, skip */
  1336. X            }
  1337. X          (void) strcpy(buffer, to);
  1338. X          debug(8, "No alias, using %s", buffer);
  1339. X        }
  1340. X
  1341. X              for (n = 0; buffer[n]; n++)
  1342. X                buffer[n] = tolower(buffer[n]);
  1343. X            }
  1344. X
  1345. X          *args = strsave(basename(RMAIL));
  1346. X          for (n = 1, cp = strtok(buffer, ", \t"); cp && n < MAXARGS;
  1347. X               cp = strtok((char *) 0, ", \t"), n++)
  1348. X            args[n] = strsave(cp);
  1349. X          args[n] = NULL;
  1350. X
  1351. X          for (n = 1; args[n]; n++)
  1352. X            log("Sending mail from %s at %s to %s", from, ascnode(orignode),
  1353. X        args[n]);
  1354. X
  1355. X          /* open rmail for sending message */
  1356. X          if ((sender = open_sender(RMAIL, args, &pid)) == NULL)
  1357. X            {
  1358. X              log("Can not execute %s", RMAIL);
  1359. X              goto error;
  1360. X            }
  1361. X
  1362. X      if (badtemp)
  1363. X        fclose(badtemp);
  1364. X
  1365. X      if ((badtemp =
  1366. X           fopen(strcpy(badname, mktemp("/tmp/funpXXXXXX")), "w+"))
  1367. X          == NULL)
  1368. X        {
  1369. X          log("$Cannot open tmp file %s", badname);
  1370. X          goto error;
  1371. X        }
  1372. X
  1373. X      area = NULL;
  1374. X
  1375. X        }
  1376. X
  1377. X      /* Save real names for further use. Blanks included, */
  1378. X      if (strchr(from, ' '))
  1379. X    {
  1380. X      strcpy(realfrom, " (");
  1381. X      strcat(realfrom, from);
  1382. X      strcat(realfrom, ")");
  1383. X    }
  1384. X      else
  1385. X    *realfrom = 0;
  1386. X
  1387. X      if (strchr(to, ' '))
  1388. X    {
  1389. X      strcpy(realto, " (");
  1390. X      strcat(realto, to);
  1391. X      strcat(realto, ")");
  1392. X    }
  1393. X      else
  1394. X    *realto = 0;
  1395. X
  1396. X      /* change all spaces in name to _'s */
  1397. X      for (n = 0; from[n]; n++)
  1398. X        if (from[n] == ' ') from[n] = '_';
  1399. X      /* Same for to field */
  1400. X      for (n = 0; to[n]; n++)
  1401. X    if (to[n] == ' ') to[n] = '_';
  1402. X
  1403. X      /* set From_ line */
  1404. X      (void) tprintf(sender, "From %d!%s %s remote from %d\n", orignode.node,
  1405. X                     from, date("%a %h %d %T 19%y", (long *) 0), orignode.net);
  1406. X
  1407. X      /* Now generate valid RFC 822 header for mail. Some fields may
  1408. X         be different, in all places there may be comments between (
  1409. X         and )-charactes. */
  1410. X
  1411. X      /* This is imporant for news articles, as without this inews
  1412. X     tries to post it back. This is a bit complicated, as we cannot
  1413. X     put fidonet path here? Hmm... why not, I have to check this out! */
  1414. X      (void) tprintf(sender, "Path: %s!%s\n", RECEIVE_PATH, from);
  1415. X
  1416. X      /* print Received: field */
  1417. X      (void) tprintf(sender, "Received: by %s (funpack%s/%s)\n",
  1418. X             internode(*entry), version, entry->name);
  1419. X      (void) tprintf(sender, "\tid AA%05d; %s\n",
  1420. X                     getpid(), date("%a, %d %h %y %T %o (%z)", (long *) 0));
  1421. X
  1422. X      /* print Date: field */
  1423. X      (void) tprintf(sender, "Date: %s\n", date("%a, %d %h %y %T %o",
  1424. X                                                &msg_date));
  1425. X
  1426. X      /* print From: field */
  1427. X      (void) tprintf(sender, "From: %s@%s%s\n", from, internode(orignode),
  1428. X                     realfrom);
  1429. X
  1430. X      /* print Subject: field */
  1431. X      (void) tprintf(sender, "Subject: %s\n", subject);
  1432. X
  1433. X      /* print Message-Id: field */
  1434. X      (void) tprintf(sender, "Message-Id: <%s.AA%ld@%s>\n",
  1435. X                     date("%y%m%q%H%M", (long *) 0), sequencer(IDSEQUENCE),
  1436. X             internode(*entry));
  1437. X
  1438. X      if (area)
  1439. X    {
  1440. X      (void) tprintf(sender, "Newsgroups: %s\n", area);
  1441. X      if (strlen(distribution))
  1442. X        (void) tprintf(sender, "Distribution: %s\n", distribution);
  1443. X
  1444. X      /* print Reply-To: field */
  1445. X      /* Note: This is not accurate yet, as * Origin can change
  1446. X         address to other node */
  1447. X      (void) tprintf(sender, "Reply-To: %s@%s%s\n",
  1448. X             from, internode(destnode), realfrom);
  1449. X    }
  1450. X      else
  1451. X    {
  1452. X      /* print To: field */
  1453. X      (void) tprintf(sender, "To: ");
  1454. X      for (n = 1; args[n]; n++)
  1455. X        {
  1456. X          (void) tprintf(sender, "%s", args[n]);
  1457. X          if (args[n + 1])
  1458. X        (void) tprintf(sender, ", ");
  1459. X        }
  1460. X      tprintf(sender, "\n");
  1461. X
  1462. X      /* print Reply-To: field */
  1463. X      (void) tprintf(sender, "Reply-To: %s@%s%s\n",
  1464. X             from, internode(orignode), realfrom);
  1465. X    }
  1466. X
  1467. X      /* done with header, now send message text */
  1468. X
  1469. X      tprintf(sender, "\n");
  1470. X      while (ffgets(buffer, BUFSIZ, packet))
  1471. X        (void) tputs(buffer, sender);
  1472. X
  1473. X      /* News messages are a little bit more compilicated. News
  1474. X     article has been saved in temp file, and now we need to
  1475. X     read it through, replace Reply-To with correct return address
  1476. X     taken from origin row, nodelist, or if not found, echo feed.
  1477. X     Then really send mail to newssender. */
  1478. X
  1479. X      if (area)
  1480. X    {
  1481. X      debug(1, "Reading back news article");
  1482. X      rewind(sender);
  1483. X
  1484. X      if (badtemp)
  1485. X        fclose(badtemp);
  1486. X
  1487. X      if ((badtemp =
  1488. X           fopen(strcpy(badname, mktemp("/tmp/funpXXXXXX")), "w+"))
  1489. X          == NULL)
  1490. X        {
  1491. X          log("$Cannot open tmp file %s", badname);
  1492. X          goto error;
  1493. X        }
  1494. X
  1495. X      while (fgets(buffer, BUFSIZ, sender))
  1496. X        {
  1497. X          if (!strncmp(buffer, "Reply-To:", 9))
  1498. X        {
  1499. X          if (search_name(from))
  1500. X            {
  1501. X              debug(1, "%s is not a sysop, try his name", from);
  1502. X              if (fromnode.zone != -1)
  1503. X            originnode = fromnode;
  1504. X              else
  1505. X            {
  1506. X              debug(1, "No node in his name, try * Origin", from);
  1507. X              if (originnode.zone == -1)
  1508. X                {
  1509. X                  debug(1, "No * Origin, replace with echo feed");
  1510. X                  originnode = orignode;
  1511. X                }
  1512. X              else
  1513. X                debug(2, "Origin %s", ascnode(originnode));
  1514. X            }
  1515. X            }
  1516. X
  1517. X          (void) tprintf(newssender, "Reply-To: %s@%s%s\n",
  1518. X                 from, internode(originnode), realfrom);
  1519. X
  1520. X          /* Set Comment-To field */
  1521. X          if (search_name(to))
  1522. X            {
  1523. X              debug(1, "%s is not a sysop, try * Origin", to);
  1524. X              if (originnode.zone == -1)
  1525. X            {
  1526. X              debug(1, "No * Origin, replace with echo feed");
  1527. X              originnode = orignode;
  1528. X            }
  1529. X              else
  1530. X            debug(2, "Origin %s", ascnode(originnode));
  1531. X            }
  1532. X
  1533. X          (void) tprintf(newssender, "Comment-To: %s@%s%s\n", to,
  1534. X                 internode(originnode), realto);
  1535. X        }
  1536. X          else
  1537. X        (void) tputs(buffer, newssender);
  1538. X        }
  1539. X      fclose(newssender); /* sender will vanish when its closed! */
  1540. X    }
  1541. X
  1542. X      /* done with this msg, wait process to finish */
  1543. X      (void) fclose(sender);
  1544. X      while ((n = wait(&stat_loc)) != pid && n != -1);
  1545. X
  1546. X      debug(2, "Wait status: %o", stat_loc);
  1547. X      if (stat_loc)
  1548. X    savebad(badtemp);
  1549. X
  1550. X      fclose(badtemp);
  1551. X      unlink(badname);
  1552. X
  1553. X      debug(1, "Done with message");
  1554. X
  1555. X      /* free argument-list */
  1556. X      for (n = 0; args[n]; n++)
  1557. X        free(args[n]);
  1558. X      continue;
  1559. X
  1560. X      /* in the case of error skip text of message */
  1561. X    error:
  1562. X      while ((c = getc(packet)) && c != EOF);
  1563. X
  1564. X      /* free argument-list */
  1565. X      for (n = 0; args[n]; n++)
  1566. X        free(args[n]);
  1567. X    }
  1568. X
  1569. X  if (messagetype != MSGTYPE && messagetype != EOF && messagetype != 0)
  1570. X    log("Strange ending: %d", messagetype);
  1571. X
  1572. X  debug(1, "Done with packet");
  1573. X}
  1574. X
  1575. X/* ARGSUSED */
  1576. Xint
  1577. Xmain(argc, argv, envp)
  1578. X     int argc;
  1579. X     char **argv, **envp;
  1580. X{
  1581. X  struct dirent *dir;
  1582. X  DIR *dp;
  1583. X  int c;
  1584. X  FILE *packet;
  1585. X  char files[BUFLEN];
  1586. X  Node node;
  1587. X  bool nocheck = False;
  1588. X  char *error, *p;
  1589. X  Node packetnode;
  1590. X
  1591. X  node.zone = -1;
  1592. X  while ((c = getopt(argc, argv, "if:vV:")) != EOF)
  1593. X    switch (c)
  1594. X      {
  1595. X      case 'V':
  1596. X        version = optarg;
  1597. X        break;
  1598. X      case 'i':
  1599. X        nocheck = True;
  1600. X        break;
  1601. X      case 'v':
  1602. X        verbose++;
  1603. X        break;
  1604. X      case 'f':
  1605. X    if (parsefnetaddress(optarg, &node)) exit(1);
  1606. X        break;
  1607. X      default:
  1608. X        fprintf(stderr,
  1609. X        "Usage: %s [-v] [-f [[<zone>:]<net>/]<node>[.<point>]]\n",
  1610. X        *argv);
  1611. X        exit(EX_USAGE);
  1612. X      }
  1613. X
  1614. X  /* create name for unpacking */
  1615. X  if (node.zone == -1)
  1616. X    (void) strcpy(files, "");
  1617. X  else
  1618. X    {
  1619. X      sprintipacketname(files, node);
  1620. X      /* Cut sequence number off */
  1621. X      if (p = strrchr(files, ".")) *p = 0;
  1622. X    }
  1623. X
  1624. X  debug(2, "Unpacking packets beginning with %s", files);
  1625. X
  1626. X  /* try to update nodelist-index */
  1627. X  if (error = update_index())
  1628. X    {
  1629. X      if (*error == '$')
  1630. X        log("$Cannot update nodelist-index: %s", error + 1);
  1631. X      else
  1632. X        log("Cannot update nodelist-index: %s", error);
  1633. X      exit(EX_OSERR);
  1634. X    }
  1635. X
  1636. X  if (chdir(sprintfs("%s/in", SPOOL)) == -1)
  1637. X    {
  1638. X      log("$Cannot chdir to %s/in", SPOOL);
  1639. X      exit(EX_OSERR);
  1640. X    };
  1641. X
  1642. X  if (dp = opendir("."))
  1643. X    {
  1644. X      while (dir = readdir(dp))
  1645. X        if (!strncmp(dir->d_name, files, strlen(files)) && *dir->d_name != '.')
  1646. X          {
  1647. X
  1648. X            /* this packet is right */
  1649. X            debug(1, "Unpacking %s", dir->d_name);
  1650. X
  1651. X            /* open packet */
  1652. X            if (packet = fopen(dir->d_name, "r"))
  1653. X              {
  1654. X                if (read_header(packet))
  1655. X          {
  1656. X            if (feof(packet))
  1657. X              log("Missing packet header");
  1658. X            else
  1659. X              log("Error reading header, errno %d : %s",
  1660. X              errno, sys_errlist[errno]);
  1661. X          }
  1662. X                else
  1663. X          {
  1664. X            packetnode.zone = int16(header.orig_zone);
  1665. X            packetnode.net = int16(header.orig_net);
  1666. X            packetnode.node = int16(header.orig_node);
  1667. X            packetnode.point = 0; /* no points in fidonet header? */
  1668. X            debug(1, "Packet from %s", ascnode(packetnode));
  1669. X            debug(1, "Time %02d:%02d:%02d %d.%d.%d",
  1670. X              int16(header.hour),
  1671. X              int16(header.minute), int16(header.second),
  1672. X              int16(header.day), int16(header.month),
  1673. X              int16(header.year));
  1674. X            debug(1, "Max baud rate %d, version %d, product %d, x %d",
  1675. X              int16(header.rate), int16(header.ver),
  1676. X              header.product, header.x1);
  1677. X            debug(1, "Pwd \"%s\"", header.pwd_kludge);
  1678. X          }
  1679. X
  1680. X                  if (nocheck || ((int16(header.dest_zone) == MY_ZONE ||
  1681. X                   int16(header.dest_zone) == 0) &&
  1682. X                  int16(header.dest_node) == MY_NODE &&
  1683. X                  int16(header.dest_net) == MY_NET))
  1684. X                    unpack(packet, packetnode);
  1685. X                  else
  1686. X                    log("Packet is to %d:%d/%d",
  1687. X            int16(header.dest_zone),
  1688. X                        int16(header.dest_net),
  1689. X                        int16(header.dest_node));
  1690. X                (void) fclose(packet);
  1691. X
  1692. X        /* Move packet to unpacked directory. */
  1693. X        if (link(dir->d_name,
  1694. X             sprintfs("%s/%s", UNPACKED_DIR, dir->d_name)))
  1695. X          log("$Could not link packet %s", dir->d_name);
  1696. X        else
  1697. X          if (unlink(dir->d_name))
  1698. X            log("$Could not unlink packet %s", dir->d_name);
  1699. X              }
  1700. X            else
  1701. X              log("$Unable open packet %s", dir->d_name);
  1702. X          }
  1703. X      (void) closedir(dp);
  1704. X    }
  1705. X  else
  1706. X    {
  1707. X      log("$Unable to open spool directory");
  1708. X      exit(EX_OSERR);
  1709. X    }
  1710. X  exit(EX_OK);
  1711. X  /* NOTREACHED */
  1712. X}
  1713. SHAR_EOF
  1714. chmod 0644 funpack.c || echo "restore of funpack.c fails"
  1715. echo "x - extracting fcall.c (Text)"
  1716. sed 's/^X//' << 'SHAR_EOF' > fcall.c &&
  1717. X#ifndef lint
  1718. Xstatic char *sccsid = "@(#)%M%  %I%  Teemu Torma %H%";
  1719. X#endif
  1720. X
  1721. X/* Dial to host-fido for mail.
  1722. X
  1723. X   @(#)Copyright (c) 1987 by Teemu Torma
  1724. X
  1725. X   Permission is given to distribute this program and alter this code as
  1726. X   needed to adapt it to forign systems provided that this header is
  1727. X   included and that the original author's name is preserved. */
  1728. X
  1729. X#include <stdio.h>
  1730. X#include <string.h>
  1731. X#include <ctype.h>
  1732. X#include <signal.h>
  1733. X#include <termio.h>
  1734. X#include <dial.h>
  1735. X#include <sys/types.h>
  1736. X#include <dirent.h>
  1737. X#include <time.h>
  1738. X#include "hsu.h"
  1739. X#include "config.h"
  1740. X#include "fnet.h"
  1741. X#include "fio.h"
  1742. X#include "nodelist.h"
  1743. X
  1744. Xextern unsigned sleep();
  1745. Xextern void exit();
  1746. Xextern int getopt();
  1747. Xextern int optind;
  1748. Xextern char *optarg;
  1749. X
  1750. Xint line = -1;
  1751. Xint verbose = INIT_VERBOSE;
  1752. X
  1753. X/* Macros to check timeout */
  1754. X
  1755. X#define SetStart() (stime = time((long *) 0))
  1756. X#define Timeout(t) (time((long *) 0) - stime > (t))
  1757. X
  1758. X/* States for session sender. */
  1759. X
  1760. X#define SendInit        (0)
  1761. X#define WaitCxD         (1)
  1762. X#define WhackCRs        (2)
  1763. X#define WaitClear       (3)
  1764. X#define SendMail        (4)
  1765. X#define CheckMail       (5)
  1766. X#define SendFiles       (6)
  1767. X#define CheckFiles      (7)
  1768. X#define TryPickup       (8)
  1769. X
  1770. X/* States for session receiver. */
  1771. X
  1772. X#define WaitTsync       (9)
  1773. X#define RecMail         (10)
  1774. X#define XRecEnd         (11)
  1775. X#define RecFiles        (12)
  1776. X#define ChkFiles        (13)
  1777. X#define AllowPickup     (14)
  1778. X
  1779. X/* States to break up the loops */
  1780. X
  1781. X#define Error           (-1)
  1782. X#define Done            (-2)
  1783. X
  1784. X/* For debugging */
  1785. X
  1786. Xstatic char devicebuffer[100];
  1787. XCALL call; /* call structure for dial(3) */
  1788. X
  1789. X/* Show dialer's error code as message */
  1790. X
  1791. Xvoid
  1792. Xlog_dialerr(code)
  1793. X     int code;
  1794. X{
  1795. X  switch (code)
  1796. X    {
  1797. X    case INTRPT:
  1798. X      log("Interrupt occured during dialing");
  1799. X      break;
  1800. X    case D_HUNG:
  1801. X      log("Dialer hung (no return from write)");
  1802. X      break;
  1803. X    case NO_ANS:
  1804. X      log("No answer");
  1805. X      break;
  1806. X    case ILL_BD:
  1807. X      log("Illegal baud-rate");
  1808. X      break;
  1809. X    case A_PROB:
  1810. X      log("Acu problem (open() failure)");
  1811. X      break;
  1812. X    case L_PROB:
  1813. X      log("Line problem (open() failure)");
  1814. X      break;
  1815. X    case NO_Ldv:
  1816. X      log("Can't open LDEVS file");
  1817. X      break;
  1818. X    case DV_NT_A:
  1819. X      log("Requested device not available");
  1820. X      break;
  1821. X    case DV_NT_K:
  1822. X      log("Requested device %s, line %s telno %s speed %d baud %d, not known",
  1823. X      call.device, call.line, call.telno, call.speed, call.baud);
  1824. X      break;
  1825. X    case NO_BD_A:
  1826. X      log("No device available at requested baud");
  1827. X      break;
  1828. X    case NO_BD_K:
  1829. X      log("No device known at requested baud");
  1830. X      break;
  1831. X    case DV_NT_E:
  1832. X      log("Requested speed does not match");
  1833. X      break;
  1834. X    default:
  1835. X      log("Dial error %d", code);
  1836. X    }
  1837. X}
  1838. X
  1839. X/* Trapper for signals to quit gracefully. Be must do undial to get lock-
  1840. X   file removed */
  1841. X
  1842. Xint
  1843. Xquit(sig)
  1844. X     int sig;
  1845. X{
  1846. X  (void) signal(SIGINT, SIG_IGN);
  1847. X  (void) signal(SIGQUIT, SIG_IGN);
  1848. X  (void) signal(SIGTERM, SIG_IGN);
  1849. X  (void) signal(SIGHUP, SIG_IGN);
  1850. X
  1851. X  if (line >= 0)
  1852. X    undial(line);
  1853. X  if (sig >= 0)
  1854. X    log("Caught signal %d", sig);
  1855. X  exit(1);
  1856. X  /* NOTREACHED */
  1857. X}
  1858. X
  1859. X/* Send files in batch protocol */
  1860. X
  1861. Xbool
  1862. Xsendfiles()
  1863. X{
  1864. X/*   if (batchsend("fio.h")) */
  1865. X  return batchsend((char *) 0);
  1866. X/*   else return 0; */
  1867. X}
  1868. X
  1869. Xbool recfiles()
  1870. X{
  1871. X  return batchrec((char *) 0);
  1872. X}
  1873. X
  1874. X/* ARGSUSED */
  1875. Xint
  1876. Xmain(argc, argv, envp)
  1877. X     int argc;
  1878. X     char **argv, **envp;
  1879. X{
  1880. X  struct termio tio; /* terminal state */
  1881. X  int c;
  1882. X  time_t stime;
  1883. X  int retry_time = 0, no_retrys = 0, wait_line = 0;
  1884. X  int state = SendInit, receive_retrys = MAX_SEND_RETRIES;
  1885. X  bool ok, pickup = False;
  1886. X  Node *node, tnode;
  1887. X  char phonenumber[100];
  1888. X  char packetname[100], ipacketname[100];
  1889. X  char *error, *p;
  1890. X
  1891. X  /* try to update nodelist-index */
  1892. X  if (error = update_index())
  1893. X    {
  1894. X      if (*error == '$')
  1895. X        log("$Cannot update nodelist-index: %s", error + 1);
  1896. X      else
  1897. X        log("Cannot update nodelist-index: %s", error);
  1898. X      exit(EX_OSERR);
  1899. X    }
  1900. X
  1901. X  if (chdir(SPOOL) < 0)
  1902. X    {
  1903. X      log("$Can not chdir to %s", SPOOL);
  1904. X      exit(1);
  1905. X    }
  1906. X
  1907. X  strcpy(packetname, "packet.out");
  1908. X  strcpy(ipacketname, "packet.junk");
  1909. X
  1910. X  call.attr = &tio;
  1911. X  call.baud = 0;
  1912. X  call.speed = 0;
  1913. X  call.line = NULL;
  1914. X  call.telno = NULL;
  1915. X  call.modem = 0;
  1916. X  call.device = devicebuffer;
  1917. X  call.dev_len = sizeof(devicebuffer);
  1918. X
  1919. X  tio.c_iflag = IGNPAR | IGNBRK;
  1920. X  tio.c_oflag = 0;
  1921. X  tio.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
  1922. X  tio.c_lflag = NOFLSH;
  1923. X  tio.c_cc[VMIN] = 1;
  1924. X  tio.c_cc[VTIME] = 0;
  1925. X
  1926. X  if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  1927. X    (void) signal(SIGINT, quit);
  1928. X  if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  1929. X    (void) signal(SIGTERM, quit);
  1930. X  if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  1931. X    (void) signal(SIGQUIT, quit);
  1932. X  if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  1933. X    (void) signal(SIGHUP, quit);
  1934. X
  1935. X  while ((c = getopt(argc, argv, "vmdp:l:b:s:r:n:w:f:")) != EOF)
  1936. X    switch (c)
  1937. X      {
  1938. X       case 'd':
  1939. X        pickup = True;
  1940. X        break;
  1941. X       case 'p':
  1942. X    call.telno = optarg;
  1943. X    break;
  1944. X      case 'v':
  1945. X        verbose++;
  1946. X        break;
  1947. X      case 'l':
  1948. X        call.line = optarg;
  1949. X        break;
  1950. X      case 'b':
  1951. X        call.baud = atoi(optarg);
  1952. X        break;
  1953. X      case 's':
  1954. X        call.speed = atoi(optarg);
  1955. X        break;
  1956. X      case 'r':
  1957. X        retry_time = atoi(optarg);
  1958. X        break;
  1959. X      case 'n':
  1960. X        no_retrys = atoi(optarg);
  1961. X        break;
  1962. X      case 'w':
  1963. X        wait_line = atoi(optarg);
  1964. X        break;
  1965. X       case 'm':
  1966. X    call.modem = 1;
  1967. X    break;
  1968. X       case 'f':
  1969. X
  1970. X    /* Fidonet address to call */
  1971. X
  1972. X    if (parsefnetaddress(optarg, &tnode)) exit(1);
  1973. X    if (!(node = node_entry(tnode))) {
  1974. X      log("Could not get node information");
  1975. X      exit(1);
  1976. X    }
  1977. X
  1978. X    /* Use either maximum speed set or maximum speed of fido system */
  1979. X
  1980. X    if (node->speed > MAXBAUD) {
  1981. X      if (!call.baud) {
  1982. X        call.baud = call.speed = MAXBAUD;
  1983. X      }
  1984. X    } else {
  1985. X      call.baud = call.speed = node->speed;
  1986. X    }
  1987. X    if (call.baud < MINBAUD) call.baud = call.speed = MINBAUD;
  1988. X
  1989. X    /* Translate phone number from nodelist, if not set */
  1990. X
  1991. X    if (!call.telno) {
  1992. X      dial_translation(phonenumber, node->phone);
  1993. X      call.telno = phonenumber;
  1994. X    }
  1995. X
  1996. X    sprintpacketname(packetname, *node);
  1997. X    sprintipacketname(ipacketname, *node);
  1998. X    break;
  1999. X
  2000. X       default:
  2001. X        log("Illegal option for fcall");
  2002. X        exit(1);
  2003. X      }
  2004. X
  2005. X  while (state >= SendInit && state < AllowPickup)
  2006. X    switch (state)
  2007. X      {
  2008. X      case SendInit:
  2009. X        if (call.telno)
  2010. X          log("Dialing to %s", call.telno);
  2011. X        line = dial(call);
  2012. X        state = WaitCxD;
  2013. X        break;
  2014. X      case WaitCxD:
  2015. X        if (line == NO_ANS && retry_time)
  2016. X          if (--no_retrys < 0)
  2017. X            {
  2018. X              log("Too many retries in call");
  2019. X              state = Error;
  2020. X            }
  2021. X          else
  2022. X            {
  2023. X              log("No answer, redial in %d seconds", retry_time);
  2024. X              (void) sleep((unsigned) retry_time);
  2025. X              state = SendInit;
  2026. X            }
  2027. X        else
  2028. X          if ((line == DV_NT_A || line == NO_BD_A) && wait_line)
  2029. X            {
  2030. X              log("No free lines, waiting %d seconds", wait_line);
  2031. X              (void) sleep((unsigned) wait_line);
  2032. X            }
  2033. X          else {
  2034. X            if (line >= 0)
  2035. X              {
  2036. X                log("Call succeeded");
  2037. X                state = WhackCRs;
  2038. X                debug(1, "Wait %d seconds before start", PREWAIT);
  2039. X                (void) sleep((unsigned) PREWAIT);
  2040. X              }
  2041. X            else
  2042. X              {
  2043. X                log_dialerr(line);
  2044. X                log("Dial failed");
  2045. X                state = Error;
  2046. X              }
  2047. X          }
  2048. X        break;
  2049. X      case WhackCRs:
  2050. X        SetStart();
  2051. X        while (state == WhackCRs)
  2052. X          if (Timeout(30))
  2053. X            {
  2054. X              log("No response");
  2055. X              state = Error;
  2056. X            }
  2057. X          else if (readline(1) == '\r')
  2058. X            {
  2059. X              debug(1, "Got CR, wait 1 second");
  2060. X              (void) sleep((unsigned) 1);
  2061. X              state = WaitClear;
  2062. X            }
  2063. X          else
  2064. X            {
  2065. X              debug(2, "Sending <sp><cr>");
  2066. X              sendline(' ');
  2067. X          sendline('\r');
  2068. X            }
  2069. X        break;
  2070. X       case WaitTsync:
  2071. X    SetStart();
  2072. X    while (state == WaitTsync)
  2073. X      if (Timeout(60))
  2074. X        {
  2075. X          log("Garbage, no Tsync, Call ok (?)");
  2076. X          state = AllowPickup;
  2077. X        }
  2078. X      else if ((c = readline(1)) == TSYNCH)
  2079. X        {
  2080. X          debug(1, "Received TSYNCH");
  2081. X          state = RecMail;
  2082. X        }
  2083. X      else if (c == ENQ)
  2084. X        {
  2085. X          debug(1, "Got ENQ, nothing to pick up");
  2086. X          state = AllowPickup;
  2087. X        }
  2088. X    break;
  2089. X       case RecMail:
  2090. X    ok = xtrec(sprintfs("in/%s", ipacketname), False);
  2091. X    state = XRecEnd;
  2092. X    break;
  2093. X       case XRecEnd:
  2094. X    if (ok)
  2095. X      {
  2096. X        log("Mail received successfully");
  2097. X
  2098. X        /* Flush input */
  2099. X
  2100. X        (void) sleep((unsigned) 1);
  2101. X
  2102. X        SetStart();
  2103. X        while (state == XRecEnd)
  2104. X          if (Timeout(60))
  2105. X        {
  2106. X          log("Garbage on line");
  2107. X          state = Error;
  2108. X          break;
  2109. X        }
  2110. X          else if (readline(1) == TIMEOUT)
  2111. X        {
  2112. X          debug(1, "Line is clear, rec files");
  2113. X          state = RecFiles;
  2114. X        }
  2115. X      }
  2116. X    else
  2117. X      {
  2118. X        log("Receiving mail failed or nothing to receive");
  2119. X        log("Moving received packet in/%s to %s", ipacketname,
  2120. X        p = sprintfs("%s/%s", BADARTICLES, ipacketname));
  2121. X        if (link(sprintfs("in/%s", ipacketname), p))
  2122. X          log("$Could not link packet in/%s", ipacketname);
  2123. X        else
  2124. X          if (unlink(sprintfs("in/%s", ipacketname)))
  2125. X        log("$Could not unlink packet in/%s", ipacketname);
  2126. X
  2127. X        state = Error;
  2128. X      }
  2129. X    break;
  2130. X       case RecFiles:
  2131. X    ok = recfiles();
  2132. X    state = ChkFiles;
  2133. X    break;
  2134. X       case ChkFiles:
  2135. X    if (ok)
  2136. X      {
  2137. X        log("Files received succesfully");
  2138. X        (void) sleep((unsigned) 2);
  2139. X        state = AllowPickup;
  2140. X      }
  2141. X    else
  2142. X      {
  2143. X        log("Files not received ok");
  2144. X        state = Error;
  2145. X      }
  2146. X    break;
  2147. X      case WaitClear:
  2148. X        SetStart();
  2149. X        while (state == WaitClear)
  2150. X          if (Timeout(60))
  2151. X            {
  2152. X              log("Garbage on line");
  2153. X              state = Error;
  2154. X              break;
  2155. X            }
  2156. X          else if (readline(WAITCLEAR) == TIMEOUT)
  2157. X            {
  2158. X              debug(1, "Line is clear, send TSYNCH");
  2159. X              sendline(TSYNCH);
  2160. X          clear_input();
  2161. X              state = SendMail;
  2162. X            }
  2163. X        break;
  2164. X      case SendMail:
  2165. X        ok = xtsend(sprintfs("out/%s", packetname), False);
  2166. X    if (!ok && receive_retrys--)
  2167. X      state = WaitClear;
  2168. X    else
  2169. X      state = CheckMail;
  2170. X
  2171. X        break;
  2172. X      case CheckMail:
  2173. X        if (ok)
  2174. X          {
  2175. X            log("Mail sent successfully");
  2176. X        log("Moving mail packet out/%s to %s", packetname,
  2177. X        p = sprintfs("%s/%s.%s", SENTBUNDLE_DIR, packetname,
  2178. X        baseit(sequencer(OPACKETSEQUENCE))));
  2179. X        if (link(sprintfs("out/%s", packetname), p))
  2180. X          log("$Could not link packet out/%s", packetname);
  2181. X        else
  2182. X          if (unlink(sprintfs("out/%s", packetname)))
  2183. X        log("$Could not unlink packet out/%s",packetname);
  2184. X
  2185. X        sequencer(OPACKETSEQUENCE);
  2186. X            state = SendFiles;
  2187. X          }
  2188. X        else
  2189. X          {
  2190. X            log("Mail send failed");
  2191. X            state = Error;
  2192. X          }
  2193. X        break;
  2194. X      case SendFiles:
  2195. X        ok = sendfiles();
  2196. X        state = CheckFiles;
  2197. X        break;
  2198. X      case CheckFiles:
  2199. X        if (ok)
  2200. X          {
  2201. X            log("Files sent successfully");
  2202. X            state = TryPickup;
  2203. X          }
  2204. X        else
  2205. X          {
  2206. X            log("Files not send ok");
  2207. X            state = Error;
  2208. X          }
  2209. X        break;
  2210. X      case TryPickup:
  2211. X        log("Send successful");
  2212. X        if (pickup)
  2213. X          {
  2214. X            log("Starting mail pickup");
  2215. X            state = WaitTsync;
  2216. X          }
  2217. X        else
  2218. X          state = Done;
  2219. X        break;
  2220. X      }
  2221. X
  2222. X  if (state == Error) {
  2223. X    log("Conversation failed");
  2224. X  } else {
  2225. X    log("Conversation complete");
  2226. X  }
  2227. X
  2228. X  if (line >= 0) {
  2229. X    (void) sleep((unsigned) 5);
  2230. X    undial(line);
  2231. X  }
  2232. X  exit(0);
  2233. X  /* NOTREACHED */
  2234. X}
  2235. SHAR_EOF
  2236. chmod 0644 fcall.c || echo "restore of fcall.c fails"
  2237. echo "x - extracting fio.c (Text)"
  2238. sed 's/^X//' << 'SHAR_EOF' > fio.c &&
  2239. X#ifndef lint
  2240. Xstatic char *sccsid = "@(#)%M%  %I%  Teemu Torma %H%";
  2241. X#endif
  2242. X
  2243. X/* Routines for io for fidonet software.
  2244. X
  2245. X   @(#)Copyright (c) 1987 by Teemu Torma
  2246. X
  2247. X   Permission is given to distribute this program and alter this code as
  2248. X   needed to adapt it to forign systems provided that this header is
  2249. X   included and that the original author's name is preserved. */
  2250. X
  2251. X#include <stdio.h>
  2252. X#include <signal.h>
  2253. X#include <termio.h>
  2254. X#include <sys/types.h>
  2255. X#include "fnet.h"
  2256. X#include "fio.h"
  2257. X
  2258. X/* number of characters in input buffer */
  2259. Xint nchars = 0;
  2260. X
  2261. X#ifdef DEBUG
  2262. X/* This is for protocol debugging logs */
  2263. X#define DEBUG_STATE_READ 1
  2264. X#define DEBUG_STATE_WRITE 2
  2265. X#endif
  2266. X
  2267. X/* Signal trapper for readline. */
  2268. X
  2269. Xstatic int
  2270. Xtrap(sig)
  2271. X     int sig;
  2272. X{
  2273. X  (void) signal(sig, trap);
  2274. X  return 0;
  2275. X}
  2276. X
  2277. X/* Read one character from line. We will do buffering up to BUFBIZ
  2278. X   characters. TIMEOUT will be returned it readline timeouts */
  2279. X
  2280. Xint
  2281. Xreadline(timeout)
  2282. X     int timeout;
  2283. X{
  2284. X  int c;
  2285. X  static unsigned char buffer[BUFSIZ];
  2286. X  static int pos = 0;
  2287. X  void (*alrm)();
  2288. X
  2289. X  if (pos < nchars)
  2290. X    /* there are characters in buffer */
  2291. X    c = buffer[pos++];
  2292. X  else
  2293. X    {
  2294. X      /* trap alarm signals and set timeout value */
  2295. X      alrm = signal(SIGALRM, trap);
  2296. X      (void) alarm((unsigned) timeout);
  2297. X
  2298. X      /* read characters */
  2299. X      nchars = read(line, (char *) buffer, BUFSIZ);
  2300. X#ifdef NEEDED
  2301. X      if (!receiving_data) debug(10, "Read returned %d", nchars);
  2302. X#endif
  2303. X
  2304. X      /* turn off alarm and return function value */
  2305. X      (void) alarm((unsigned) 0);
  2306. X      (void) signal(SIGALRM, alrm);
  2307. X
  2308. X      /* if we got characters return first of them, otherwise return
  2309. X         TIMEOUT */
  2310. X
  2311. X      if (nchars <= 0)
  2312. X        c = TIMEOUT;
  2313. X      else
  2314. X    {
  2315. X      c = buffer[pos = 0];
  2316. X      pos++;
  2317. X    }
  2318. X    }
  2319. X
  2320. X  if (!receiving_data) debug(8, "< %02x", c);
  2321. X  return c;
  2322. X}
  2323. X
  2324. X/* Flush line. Both terminal buffers and input buffer of readline will
  2325. X   be flushed */
  2326. X
  2327. Xvoid
  2328. Xflush()
  2329. X{
  2330. X  (void) ioctl(line, TCFLSH, 0);
  2331. X  nchars = 0;
  2332. X}
  2333. X
  2334. X/* Send character c to line. This also clears readline's input buffer
  2335. X   but not terminal buffers because it might takes too much time.
  2336. X   Tue Nov  8 13:49:27 1988
  2337. X   No more clearing buffer, as I try to make it sealink compatible.
  2338. X   */
  2339. X
  2340. Xvoid
  2341. Xsendline(c)
  2342. X     int c;
  2343. X{
  2344. X  unsigned char cc = (c & 0377);
  2345. X
  2346. X  debug(8, "> %02x", cc);
  2347. X  (void) write(line, (char *) &cc, 1);
  2348. X#ifdef NO_SEALINK
  2349. X  nchars = 0;
  2350. X#endif
  2351. X}
  2352. X
  2353. Xclear_input()
  2354. SHAR_EOF
  2355. echo "End of part 3"
  2356. echo "File fio.c is continued in part 4"
  2357. echo "4" > s2_seq_.tmp
  2358. exit 0
  2359.  
  2360.