home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume22 / elm2.3 / part11 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  49.4 KB

  1. Subject:  v22i070:  ELM mail syste, release 2.3, Part11/26
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: c8a975a5 796eb4a4 9cdfc7a1 37097fb0
  5.  
  6. Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
  7. Posting-number: Volume 22, Issue 70
  8. Archive-name: elm2.3/part11
  9.  
  10. ---- Cut Here and unpack ----
  11. #!/bin/sh
  12. # this is part 11 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file src/addr_util.c continued
  15. #
  16. CurArch=11
  17. if test ! -r s2_seq_.tmp
  18. then echo "Please unpack part 1 first!"
  19.      exit 1; fi
  20. ( read Scheck
  21.   if test "$Scheck" != $CurArch
  22.   then echo "Please unpack part $Scheck next!"
  23.        exit 1;
  24.   else exit 0; fi
  25. ) < s2_seq_.tmp || exit 1
  26. echo "x - Continuing file src/addr_util.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> src/addr_util.c
  28. X
  29. X    if(can_access(fullnamefile, READ_ACCESS) != 0)
  30. X      return(NULL);        /* fullname file not accessible to user */
  31. X    if((fp = fopen(fullnamefile, "r")) == NULL)
  32. X      return(NULL);        /* fullname file cannot be opened! */
  33. X    if(fgets(fullname, SLEN, fp) == NULL) {
  34. X      fclose(fp);
  35. X      return(NULL);        /* fullname file empty! */
  36. X    }
  37. X    fclose(fp);
  38. X    no_ret(fullname);    /* remove trailing '\n' */
  39. X#endif
  40. X    return(fullname);
  41. X}
  42. X
  43. Xint
  44. Xtalk_to(sitename)
  45. Xchar *sitename;
  46. X{
  47. X    /** If we talk to the specified site, return true, else
  48. X        we're going to have to expand this baby out, so 
  49. X        return false! **/
  50. X
  51. X    struct lsys_rec  *sysname;
  52. X
  53. X    sysname = talk_to_sys;
  54. X
  55. X    if (sysname == NULL) {
  56. X     dprint(2, (debugfile, 
  57. X        "Warning: talk_to_sys is currently set to NULL!\n"));
  58. X     return(0);
  59. X    }
  60. X
  61. X    while (sysname != NULL) {
  62. X      if (strcmp(sysname->name, sitename) == 0)
  63. X        return(1);
  64. X      else
  65. X        sysname = sysname->next;
  66. X    }
  67. X
  68. X    return(0);
  69. X}
  70. X
  71. Xadd_site(buffer, site, lastsite)
  72. Xchar *buffer, *site, *lastsite;
  73. X{
  74. X    /** add site to buffer, unless site is 'uucp' or site is
  75. X        the same as lastsite.   If not, set lastsite to site.
  76. X    **/
  77. X
  78. X    char local_buffer[SLEN], *stripped;
  79. X    char *strip_parens();
  80. X
  81. X    stripped = strip_parens(site);
  82. X
  83. X    if (strcmp(stripped, "uucp") != 0)
  84. X      if (strcmp(stripped, lastsite) != 0) {
  85. X        if (buffer[0] == '\0')
  86. X          strcpy(buffer, stripped);         /* first in list! */
  87. X        else {
  88. X          sprintf(local_buffer,"%s!%s", buffer, stripped);
  89. X          strcpy(buffer, local_buffer);
  90. X        }
  91. X        strcpy(lastsite, stripped); /* don't want THIS twice! */
  92. X      }
  93. X}
  94. X
  95. X#ifdef USE_EMBEDDED_ADDRESSES
  96. X
  97. Xget_address_from(prefix, line, buffer)
  98. Xchar *prefix, *line, *buffer;
  99. X{
  100. X    /** This routine extracts the address from either a 'From:' line
  101. X        or a 'Reply-To:' line.  The strategy is as follows:  if the
  102. X        line contains a '<', then the stuff enclosed is returned.
  103. X        Otherwise we go through the line and strip out comments
  104. X        and return that.  White space will be elided from the result.
  105. X    **/
  106. X
  107. X    register char *s;
  108. X
  109. X    /**  Skip start of line over prefix, e.g. "From:".  **/
  110. X    line += strlen(prefix);
  111. X
  112. X    /**  If there is a '<' then copy from it to '>' into the buffer.  **/
  113. X    if ( (s = index(line,'<')) != NULL ) {
  114. X    while ( ++s , *s != '\0' && *s != '>' ) {
  115. X        if ( !isspace(*s) )
  116. X        *buffer++ = *s;
  117. X    }
  118. X    *buffer = '\0';
  119. X    return;
  120. X    }
  121. X
  122. X    /**  Otherwise, strip comments and get address with whitespace elided.  **/
  123. X    for ( s = strip_parens(line) ; *s != '\0' ; ++s ) {
  124. X    if ( !isspace(*s) )
  125. X        *buffer++ = *s;
  126. X    }
  127. X    *buffer = '\0';
  128. X
  129. X}
  130. X
  131. X#endif
  132. X
  133. Xtranslate_return(addr, ret_addr)
  134. Xchar *addr, *ret_addr;
  135. X{
  136. X    /** Return ret_addr to be the same as addr, but with the login 
  137. X            of the person sending the message replaced by '%s' for 
  138. X            future processing... 
  139. X        Fixed to make "%xx" "%%xx" (dumb 'C' system!) 
  140. X    **/
  141. X
  142. X    register int loc, loc2, iindex = 0;
  143. X    
  144. X    loc2 = chloc(addr,'@');
  145. X    if ((loc = chloc(addr, '%')) < loc2)
  146. X      loc2 = loc;
  147. X
  148. X    if (loc2 != -1) {    /* ARPA address. */
  149. X      /* algorithm is to get to '@' sign and move backwards until
  150. X         we've hit the beginning of the word or another metachar.
  151. X      */
  152. X      for (loc = loc2 - 1; loc > -1 && addr[loc] != '!'; loc--)
  153. X         ;
  154. X    }
  155. X    else {            /* usenet address */
  156. X      /* simple algorithm - find last '!' */
  157. X
  158. X      loc2 = strlen(addr);    /* need it anyway! */
  159. X
  160. X      for (loc = loc2; loc > -1 && addr[loc] != '!'; loc--)
  161. X          ;
  162. X    }
  163. X    
  164. X    /** now copy up to 'loc' into destination... **/
  165. X
  166. X    while (iindex <= loc) {
  167. X      ret_addr[iindex] = addr[iindex];
  168. X      iindex++;
  169. X    }
  170. X
  171. X    /** now append the '%s'... **/
  172. X
  173. X    ret_addr[iindex++] = '%';
  174. X    ret_addr[iindex++] = 's';
  175. X
  176. X    /** and, finally, if anything left, add that **/
  177. X
  178. X    loc = strlen(addr);
  179. X    while (loc2 < loc) {
  180. X      ret_addr[iindex++] = addr[loc2++];
  181. X      if (addr[loc2-1] == '%')    /* tweak for "printf" */
  182. X        ret_addr[iindex++] = '%';
  183. X    }
  184. X    
  185. X    ret_addr[iindex] = '\0';
  186. X}
  187. X
  188. Xint
  189. Xbuild_address(to, full_to)
  190. Xchar *to, *full_to;
  191. X{
  192. X    /** loop on all words in 'to' line...append to full_to as
  193. X        we go along, until done or length > len.  Modified to
  194. X        know that stuff in parens are comments...Returns non-zero
  195. X        if it changed the information as it copied it across...
  196. X    **/
  197. X
  198. X    register int i, j, changed = 0, in_parens = 0, expanded_information = 0;
  199. X    char word[SLEN], next_word[SLEN], *ptr, buffer[SLEN];
  200. X    char new_to_list[SLEN];
  201. X    char *strpbrk(), *strcat(), *gecos;
  202. X#ifndef DONT_TOUCH_ADDRESSES
  203. X    char *expand_system();
  204. X#endif
  205. X
  206. X    new_to_list[0] = '\0';
  207. X
  208. X    i = get_word(to, 0, word);
  209. X
  210. X    full_to[0] = '\0';
  211. X
  212. X    while (i > 0) {
  213. X
  214. X      j = get_word(to, i, next_word);
  215. X
  216. Xtry_new_word:
  217. X      if(word[0] == '(')
  218. X        in_parens++;
  219. X
  220. X      if (in_parens) {
  221. X        if(word[strlen(word)-1] == ')')
  222. X          in_parens--;
  223. X        strcat(full_to, " ");
  224. X        strcat(full_to, word);
  225. X      }
  226. X      else if (strpbrk(word,"!@:") != NULL) {
  227. X#ifdef DONT_TOUCH_ADDRESSES
  228. X        sprintf(full_to, "%s%s%s", full_to,
  229. X                    full_to[0] != '\0'? ", " : "", word);
  230. X#else
  231. X        sprintf(full_to, "%s%s%s", full_to,
  232. X                    full_to[0] != '\0'? ", " : "", expand_system(word, 1));
  233. X#endif
  234. X      }
  235. X      else if ((ptr = get_alias_address(word, TRUE)) != NULL) {
  236. X        sprintf(full_to, "%s%s%s", full_to, 
  237. X                    full_to[0] != '\0'? ", " : "", ptr);
  238. X        expanded_information++;
  239. X      }
  240. X      else if (strlen(word) > 0) {
  241. X        if (valid_name(word)) {
  242. X          if (j > 0 && next_word[0] == '(')    /* already has full name */
  243. X        gecos = NULL;
  244. X          else                /* needs a full name */
  245. X        gecos=get_full_name(word);
  246. X#if defined(INTERNET) & defined(USE_DOMAIN)
  247. X          sprintf(full_to, "%s%s%s@%s%s%s%s",
  248. X              full_to,
  249. X              (full_to[0] != '\0'? ", " : ""),
  250. X              word,
  251. X              hostfullname,
  252. X              (gecos ? " (" : ""),
  253. X              (gecos ? gecos : ""),
  254. X              (gecos ? ")" : ""));
  255. X#else /* INTERNET and USE_DOMAIN */
  256. X          sprintf(full_to, "%s%s%s%s%s%s",
  257. X              full_to,
  258. X              (full_to[0] != '\0'? ", " : ""),
  259. X              word,
  260. X              (gecos ? " (" : ""),
  261. X              (gecos ? gecos : ""),
  262. X              (gecos ? ")" : ""));
  263. X#endif /* INTERNET and USE_DOMAIN */
  264. X        } else if (check_only) {
  265. X          printf("(alias \"%s\" is unknown)\n\r", word);
  266. X          changed++;
  267. X        }
  268. X        else if (! isatty(fileno(stdin)) ) {    /* batch mode error! */
  269. X          fprintf(stderr,"Cannot expand alias '%s'!\n\r", word);
  270. X          fprintf(stderr,"Use \"checkalias\" to find valid addresses!\n\r");
  271. X          dprint(1, (debugfile,
  272. X              "Can't expand alias %s - bailing out of build_address\n", 
  273. X              word));
  274. X          leave(0);
  275. X        }
  276. X        else {
  277. X          dprint(2,(debugfile,"Entered unknown address %s\n", word));
  278. X          sprintf(buffer, "'%s' is an unknown address.  Replace with: ", 
  279. X                  word);
  280. X          word[0] = '\0';
  281. X          changed++;
  282. X
  283. X          PutLine0(LINES, 0, buffer);
  284. X        
  285. X          (void)optionally_enter(word, LINES, strlen(buffer), FALSE, FALSE);
  286. X          clear_error();
  287. X          if (strlen(word) > 0) {
  288. X            dprint(3,(debugfile, "Replaced with %s in build_address\n", 
  289. X             word));
  290. X        goto try_new_word;
  291. X          }
  292. X          else
  293. X        dprint(3,(debugfile, 
  294. X            "Address removed from TO list by build_address\n"));
  295. X          continue;
  296. X        }
  297. X      }
  298. X
  299. X      /* and this word to the new to list */
  300. X      if(*new_to_list != '\0')
  301. X        strcat(new_to_list, " ");
  302. X      strcat(new_to_list, word);
  303. X
  304. X      if((i = j) > 0)
  305. X        strcpy(word, next_word);
  306. X    }
  307. X
  308. X    /* if new to list is different from original, update original */
  309. X    if (changed)
  310. X      strcpy(to, new_to_list);
  311. X
  312. X    return( expanded_information > 0 ? 1 : 0 );
  313. X}
  314. X
  315. Xint
  316. Xreal_from(buffer, entry)
  317. Xchar *buffer;
  318. Xstruct header_rec *entry;
  319. X{
  320. X    /***** Returns true iff 's' has the seven 'from' fields, (or
  321. X           8 - some machines include the TIME ZONE!!!)
  322. X           Initialize the date and from entries in the record 
  323. X           and also the message received date/time if 'entry'
  324. X           is not NULL.  *****/
  325. X
  326. X    struct header_rec temp_rec, *rec_ptr;
  327. X    char junk[STRING], timebuff[STRING], holding_from[SLEN], hold_tz[12];
  328. X    char mybuf[BUFSIZ], *p, *q;
  329. X    int  eight_fields = 0;
  330. X        int mday, month, year, minutes, seconds, tz, i;
  331. X        long gmttime;
  332. X
  333. X    /* set rec_ptr according to whether the data is to be returned
  334. X     * in the second argument */
  335. X    rec_ptr = (entry == NULL ? &temp_rec : entry);
  336. X
  337. X    rec_ptr->year[0] = '\0';
  338. X    timebuff[0] = '\0';
  339. X    junk[0] = '\0';
  340. X    hold_tz[0] = '\0';
  341. X
  342. X    /* From <user> <day> <month> <day> <hr:min:sec> <year> */
  343. X
  344. X    sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %s", timebuff, junk);
  345. X
  346. X    if (strlen(timebuff) < 3) {
  347. X      dprint(3,(debugfile, 
  348. X        "Real_from returns FAIL [no time field] on\n-> %s\n", 
  349. X        buffer));
  350. X      return(FALSE);
  351. X    }
  352. X
  353. X    if (timebuff[1] != ':' && timebuff[2] != ':') { 
  354. X      dprint(3,(debugfile, 
  355. X        "Real_from returns FAIL [bad time field] on\n-> %s\n", 
  356. X        buffer));
  357. X      return(FALSE);
  358. X    }
  359. X    if (junk[0] != '\0') {    /* try for 8 field entry */
  360. X      junk[0] = '\0';
  361. X      sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %*s %s", timebuff, junk);
  362. X      if (junk[0] != '\0') {
  363. X        dprint(3, (debugfile, 
  364. X          "Real_from returns FAIL [too many fields] on\n-> %s\n", 
  365. X          buffer));
  366. X        return(FALSE);
  367. X      }
  368. X      eight_fields++;
  369. X    }
  370. X
  371. X    /** now get the info out of the record! **/
  372. X
  373. X    if (eight_fields) 
  374. X      sscanf(buffer, "%s %s %s %s %s %s %s %s",
  375. X                junk, holding_from, rec_ptr->dayname, rec_ptr->month, 
  376. X                    rec_ptr->day, rec_ptr->time, hold_tz, rec_ptr->year);
  377. X    else
  378. X      sscanf(buffer, "%s %s %s %s %s %s %s",
  379. X                junk, holding_from, rec_ptr->dayname, rec_ptr->month, 
  380. X                    rec_ptr->day, rec_ptr->time, rec_ptr->year);
  381. X    
  382. X    strncpy(rec_ptr->from, holding_from, STRING-1);
  383. X    rec_ptr->from[STRING-1] = '\0';
  384. X    resolve_received(rec_ptr);
  385. X
  386. X        /* first get everything into lower case */
  387. X        for (p=mybuf, q=mybuf+sizeof mybuf; 
  388. X         *buffer && p<q; 
  389. X         p++, buffer++) {
  390. X      *p = isupper(*buffer) ? tolower(*buffer) : *buffer;
  391. X        }
  392. X    *p = 0;
  393. X    p = mybuf;
  394. X    while (!isspace(*p)) p++;    /* skip "from" */
  395. X    SKIP_WS(p);
  396. X    while (!isspace(*p)) p++;    /* skip from address */
  397. X    SKIP_WS(p);
  398. X    while (!isspace(*p)) p++;    /* skip day of week */
  399. X    SKIP_WS(p);
  400. X    month = prefix(month_name, p);
  401. X    get_unix_date(p,&year, &mday, &minutes, &seconds, &tz);
  402. X    month_len[1] = (year%4) ? 28 : 29;
  403. X    if (mday < 0 || mday>month_len[month]) {
  404. X      dprint(5,(debugfile, "ridiculous day %d of month %d\n",mday,month));
  405. X    }
  406. X
  407. X    minutes -= tz;
  408. X    if (tz > 0) { /* east of Greenwich */
  409. X      if (minutes < 0) {
  410. X        if (--mday < 0) {
  411. X          if (--month < 0) {
  412. X        year--; /* don't worry about 1900! */
  413. X        month = 11;
  414. X          }
  415. X          mday = month_len[month];
  416. X        }
  417. X        minutes += 24*60;
  418. X      }
  419. X    }
  420. X    if (tz < 0) { /* west of Greenwich */
  421. X      if (minutes <= 24*60) {
  422. X        if (++mday > month_len[month]) {
  423. X          if (++month >= 12) {
  424. X        year++; /* don't worry about 1999! yet?? */
  425. X        month = 0;
  426. X          }
  427. X          mday = 0;
  428. X        }
  429. X        minutes -= 24*60;
  430. X      }
  431. X    }
  432. X        gmttime = year - 70;         /* make base year */
  433. X        if (gmttime < 0)
  434. X        gmttime += 100;
  435. X        gmttime = gmttime * 365 + (gmttime + 1) / 4;  /* now we have days adjusted for leap years */
  436. X        for (i = 0; i < month; i++)
  437. X        gmttime += month_len[i];
  438. X        if (month > 1 && (year % 4) == 0)
  439. X        gmttime++;            /* now to month adjusted for leap year if after feb */
  440. X        gmttime += mday - 1;        /* and now to the day */
  441. X        gmttime *= 24 * 60;            /* convert to minutes */
  442. X        gmttime += minutes;
  443. X        rec_ptr->time_sent = gmttime * 60;    /* now unix seconds since 1/1/70 00:00 GMT */
  444. X
  445. X    return(rec_ptr->year[0] != '\0');
  446. X}
  447. X
  448. Xforwarded(buffer, entry)
  449. Xchar *buffer;
  450. Xstruct header_rec *entry;
  451. X{
  452. X    /** Change 'from' and date fields to reflect the ORIGINATOR of 
  453. X        the message by iteratively parsing the >From fields... 
  454. X        Modified to deal with headers that include the time zone
  455. X        of the originating machine... **/
  456. X
  457. X    char machine[SLEN], buff[SLEN], holding_from[SLEN];
  458. X
  459. X    machine[0] = holding_from[0] = '\0';
  460. X
  461. X    sscanf(buffer, "%*s %s %s %s %s %s %s %*s %*s %s",
  462. X                holding_from, entry->dayname, entry->month, 
  463. X                    entry->day, entry->time, entry->year, machine);
  464. X
  465. X    if (isdigit(entry->month[0])) { /* try for veeger address */
  466. X      sscanf(buffer, "%*s %s %s%*c %s %s %s %s %*s %*s %s",
  467. X                holding_from, entry->dayname, entry->day, entry->month, 
  468. X                    entry->year, entry->time, machine);
  469. X    }
  470. X    if (isalpha(entry->year[0])) { /* try for address including tz */
  471. X      sscanf(buffer, "%*s %s %s %s %s %s %*s %s %*s %*s %s",
  472. X                holding_from, entry->dayname, entry->month, 
  473. X                    entry->day, entry->time, entry->year, machine);
  474. X    }
  475. X
  476. X    /* the following fix is to deal with ">From xyz ... forwarded by xyz"
  477. X       which occasionally shows up within AT&T.  Thanks to Bill Carpenter
  478. X       for the fix! */
  479. X
  480. X    if (strcmp(machine, holding_from) == 0)
  481. X      machine[0] = '\0';
  482. X
  483. X    if (machine[0] == '\0')
  484. X      strcpy(buff, holding_from[0] ? holding_from : "anonymous");
  485. X    else
  486. X      sprintf(buff,"%s!%s", machine, holding_from);
  487. X
  488. X    strncpy(entry->from, buff, STRING-1);
  489. X    entry->from[STRING-1] = '\0';
  490. X}
  491. X
  492. Xparse_arpa_who(buffer, newfrom, is_really_a_to)
  493. Xchar *buffer, *newfrom;
  494. Xint is_really_a_to;
  495. X{
  496. X    /** try to parse the 'From:' line given... It can be in one of
  497. X        two formats:
  498. X        From: Dave Taylor <hplabs!dat>
  499. X        or  From: hplabs!dat (Dave Taylor)
  500. X
  501. X        Added: removes quotes if name is quoted (12/12)
  502. X        Added: only copies STRING characters...
  503. X        Added: if no comment part, copy address instead! 
  504. X        Added: if is_really_a_to, this is really a 'to' line
  505. X           and treat as if we allow embedded addresses
  506. X    **/
  507. X
  508. X    int use_embedded_addresses;
  509. X    char temp_buffer[SLEN], *temp;
  510. X    register int i, j = 0, in_parens;
  511. X
  512. X    temp = (char *) temp_buffer;
  513. X    temp[0] = '\0';
  514. X
  515. X    no_ret(buffer);        /* blow away '\n' char! */
  516. X
  517. X    if (lastch(buffer) == '>') {
  518. X      for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
  519. X           buffer[i] != '('; i++)
  520. X        temp[j++] = buffer[i];
  521. X      temp[j] = '\0';
  522. X    }
  523. X    else if (lastch(buffer) == ')') {
  524. X      in_parens = 1;
  525. X      for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '<'; i--) {
  526. X        switch(buffer[i]) {
  527. X        case ')':    in_parens++;
  528. X            break;
  529. X        case '(':    in_parens--;
  530. X            break;
  531. X        }
  532. X        if(!in_parens) break;
  533. X        temp[j++] = buffer[i];
  534. X      }
  535. X      temp[j] = '\0';
  536. X      reverse(temp);
  537. X    }
  538. X
  539. X#ifdef USE_EMBEDDED_ADDRESSES
  540. X    use_embedded_addresses = TRUE;
  541. X#else
  542. X    use_embedded_addresses = FALSE;
  543. X#endif
  544. X
  545. X    if(use_embedded_addresses || is_really_a_to) {
  546. X      /** if we have a null string at this point, we must just have a 
  547. X          From: line that contains an address only.  At this point we
  548. X          can have one of a few possibilities...
  549. X
  550. X          From: address
  551. X          From: <address>
  552. X          From: address ()
  553. X      **/
  554. X        
  555. X      if (strlen(temp) == 0) {
  556. X        if (lastch(buffer) != '>') {       
  557. X          for (i=strlen("From:");buffer[i] != '\0' && buffer[i] != '('; i++)
  558. X        temp[j++] = buffer[i];
  559. X          temp[j] = '\0';
  560. X        }
  561. X        else {    /* get outta '<>' pair, please! */
  562. X          for (i=strlen(buffer)-2;buffer[i] != '<' && buffer[i] != ':';i--)
  563. X        temp[j++] = buffer[i];
  564. X          temp[j] = '\0';
  565. X          reverse(temp);
  566. X        }
  567. X      }
  568. X    }
  569. X      
  570. X    if (strlen(temp) > 0) {        /* mess with buffer... */
  571. X
  572. X      /* remove leading spaces and quotes... */
  573. X
  574. X      while (whitespace(temp[0]) || quote(temp[0]))
  575. X        temp = (char *) (temp + 1);        /* increment address! */
  576. X
  577. X      /* remove trailing spaces and quotes... */
  578. X
  579. X      i = strlen(temp) - 1;
  580. X
  581. X      while (whitespace(temp[i]) || quote(temp[i]))
  582. X       temp[i--] = '\0';
  583. X
  584. X      /* if anything is left, let's change 'from' value! */
  585. X
  586. X      if (strlen(temp) > 0) {
  587. X        strncpy(newfrom, temp, STRING-1);
  588. X        newfrom[STRING-1] = '\0';
  589. X      }
  590. X    }
  591. X}
  592. X
  593. X/*
  594. XQuoting from RFC 822:
  595. X     5.  DATE AND TIME SPECIFICATION
  596. X
  597. X     5.1.  SYNTAX
  598. X
  599. X     date-time   =  [ day "," ] date time        ; dd mm yy
  600. X                         ;  hh:mm:ss zzz
  601. X
  602. X     day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"
  603. X         /  "Fri"  / "Sat" /  "Sun"
  604. X
  605. X     date        =  1*2DIGIT month 2DIGIT        ; day month year
  606. X                         ;  e.g. 20 Jun 82
  607. X
  608. X     month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"
  609. X         /  "May"  /  "Jun" /  "Jul"  /  "Aug"
  610. X         /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
  611. X
  612. X     time        =  hour zone                    ; ANSI and Military
  613. X
  614. X     hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]
  615. X                         ; 00:00:00 - 23:59:59
  616. X
  617. X     zone        =  "UT"  / "GMT"                ; Universal Time
  618. X                         ; North American : UT
  619. X         /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
  620. X         /  "CST" / "CDT"                ;  Central:  - 6/ - 5
  621. X         /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
  622. X         /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
  623. X         /  1ALPHA                       ; Military: Z = UT;
  624. X                         ;  A:-1; (J not used)
  625. X                         ;  M:-12; N:+1; Y:+12
  626. X         / ( ("+" / "-") 4DIGIT )        ; Local differential
  627. X                         ;  hours+min. (HHMM)
  628. X*/
  629. X
  630. X/* Translate a symbolic timezone name (e.g. EDT or NZST) to a number of
  631. X * minutes *east* of gmt (if the local time is t, the gmt equivalent is
  632. X * t - tz_lookup(zone)).
  633. X * Return 0 if the timezone is not recognized.
  634. X */
  635. Xstatic int tz_lookup(str)
  636. Xchar *str;
  637. X{
  638. X    struct tzone *p; 
  639. X
  640. X    for (p = tzone_info; p->str; p++) {
  641. X    if (strcmp(p->str,str)==0) return p->offset;
  642. X    }
  643. X    dprint(5,(debugfile,"unknown time zone %s\n",str));
  644. X    return 0;
  645. X}
  646. X
  647. X/* Return smallest i such that table[i] is a prefix of str.  Return -1 if not
  648. X * found.
  649. X */
  650. Xstatic int prefix(table, str)
  651. Xchar **table;
  652. Xchar *str;
  653. X{
  654. X    int i;
  655. X
  656. X    for (i=0;table[i];i++)
  657. X    if (strncmp(table[i],str,strlen(*table))==0)
  658. X        return i;
  659. X    return -1;
  660. X}
  661. X
  662. X/* The following routines, get_XXX(p,...), expect p to point to a string
  663. X * of the appropriate syntax.  They return decoded values in result parameters,
  664. X * and return p updated to point past the parsed substring (also stripping
  665. X * trailing whitespace).
  666. X * Return 0 on syntax errors.
  667. X */
  668. X
  669. X/* Parse a year: ['1' '9'] digit digit WS
  670. X */
  671. Xstatic char *
  672. Xget_year(p, result)
  673. Xchar *p;
  674. Xint *result;
  675. X{
  676. X    int year;
  677. X
  678. X    if (!isdigit(*p)) {
  679. X    dprint(5,(debugfile,"missing year: %s\n",p));
  680. X    return 0;
  681. X    }
  682. X    year = atoi(p);
  683. X    /* be nice and allow 19xx, althought that's not really kosher */
  684. X    if (year>=1900 && year <=1999) year -= 1900;
  685. X    if (year<0 || year>99) {
  686. X    dprint(5,(debugfile,"ridiculous year %d\n",year));
  687. X    return 0;
  688. X    }
  689. X    SKIP_DIGITS(p);
  690. X    SKIP_WS(p);
  691. X    *result = year;
  692. X    return p;
  693. X}
  694. X
  695. X/* Parse a time: hours ':' minutes [ ':' seconds ] WS
  696. X * Check that 0<=hours<24, 0<=minutes,seconds<60.
  697. X * Also allow the syntax "digit digit digit digit" with implied ':' in the
  698. X * middle.
  699. X * Convert to minutes and seconds, with results in (*m,*s).
  700. X */
  701. Xstatic char *
  702. Xget_time(p,m,s)
  703. Xchar *p;
  704. Xint *m, *s;
  705. X{
  706. X    int hours, minutes, seconds;
  707. X
  708. X    /* hour */
  709. X    if (!isdigit(*p)) {
  710. X    dprint(5,(debugfile,"missing time: %s\n",p));
  711. X    return 0;
  712. X    }
  713. X    hours = atoi(p);
  714. X    SKIP_DIGITS(p);
  715. X    if (*p++ != ':') {
  716. X    /* perhaps they just wrote hhmm instead of hh:mm */
  717. X    minutes = hours % 60;
  718. X    hours /= 60;
  719. X    }
  720. X    else {
  721. X    if (hours<0 || hours>23) {
  722. X        dprint(5,(debugfile,"ridiculous hour: %d\n",hours));
  723. X        return 0;
  724. X    }
  725. X    minutes = atoi(p);
  726. X    if (minutes<0 || minutes>59) {
  727. X        dprint(5,(debugfile,"ridiculous minutes: %d\n",minutes));
  728. X        return 0;
  729. X    }
  730. X    }
  731. X    SKIP_DIGITS(p);
  732. X    if (*p == ':') {
  733. X    p++;
  734. X    seconds = atoi(p);
  735. X    if (seconds<0 || seconds>59) {
  736. X        dprint(5,(debugfile,"ridiculous seconds: %d\n",seconds));
  737. X        return 0;
  738. X    }
  739. X    SKIP_DIGITS(p);
  740. X    }
  741. X    else seconds = 0;
  742. X    minutes += hours*60;
  743. X    SKIP_WS(p);
  744. X    *m = minutes;
  745. X    *s = seconds;
  746. X    return p;
  747. X}
  748. X
  749. X/* Parse a Unix date from which the leading week-day has been stripped.
  750. X * The syntax is "Jun 21 06:45:44 CDT 1989" with timezone optional.
  751. X * i.e., month day time [ zone ] year
  752. X * where day::=digit*, year and time are as defined above,
  753. X * and month and zone are alpha strings starting with a known 3-char prefix.
  754. X * The month has already been processed by the caller, so we just skip over
  755. X * a leading alpha* WS.
  756. X *
  757. X * Unlike the preceding routines, the result is not an updated pointer, but
  758. X * simply 1 for success and 0 for failure.
  759. X */
  760. Xstatic int
  761. Xget_unix_date(p,y,d,m,s,t)
  762. Xchar *p;
  763. Xint *y, *d, *m, *s, *t;
  764. X{
  765. X
  766. X    SKIP_ALPHA(p);
  767. X    SKIP_WS(p);
  768. X    if (!isdigit(*p)) return 0;
  769. X    *d = atoi(p);  /* check the value for sanity after we know the month */
  770. X    SKIP_DIGITS(p);
  771. X    SKIP_WS(p);
  772. X    p = get_time(p,m,s);
  773. X    if (!p) return 0;
  774. X    if (isalpha(*p)) {
  775. X    *t = tz_lookup(p);
  776. X    SKIP_ALPHA(p);
  777. X    SKIP_WS(p);
  778. X    }
  779. X    else *t = 0;
  780. X    p = get_year(p,y);
  781. X    if (!p) return 0;
  782. X    return 1;
  783. X}
  784. X
  785. X
  786. X/* Parse an rfc822 (with extensions) date.  Return 1 on success, 0 on failure.
  787. X */
  788. Xparse_arpa_date(string, entry)
  789. Xchar *string;
  790. Xstruct header_rec *entry;
  791. X{
  792. X    char buffer[BUFSIZ], *p, *q;
  793. X    int mday, month, year, minutes, seconds, tz, i;
  794. X    long gmttime;
  795. X
  796. X    /* first get everything into lower case */
  797. X    for (p=buffer, q=buffer+sizeof buffer; *string && p<q; p++, string++) {
  798. X    *p = isupper(*string) ? tolower(*string) : *string;
  799. X    }
  800. X    *p = 0;
  801. X    p = buffer;
  802. X    SKIP_WS(p);
  803. X
  804. X    if (prefix(day_name,p)>=0) {
  805. X    /* accept anything that *starts* with a valid day name */
  806. X    /* also, don't check whether it's right! */
  807. X
  808. X    (void)strncpy(entry->dayname, p, 3);
  809. X    entry->dayname[3] = 0;
  810. X    SKIP_ALPHA(p);
  811. X    SKIP_WS(p);
  812. X
  813. X    if (*p==',') {
  814. X        p++;
  815. X        SKIP_WS(p);
  816. X    }
  817. X    /* A comma is required here, but we'll be nice guys and look the other
  818. X     * way if it's missing.
  819. X     */
  820. X    }
  821. X
  822. X    /* date */
  823. X
  824. X    /* day of the month */
  825. X    if (!isdigit(*p)) {
  826. X    /* Missing day.  Maybe this is a Unix date?
  827. X     */
  828. X    month = prefix(month_name,p);
  829. X    if (month >= 0 &&
  830. X        get_unix_date(p, &year, &mday, &minutes, &seconds, &tz)) {
  831. X        goto got_date;
  832. X    }
  833. X    dprint(5,(debugfile,"missing day: %s\n",p));
  834. X    return 0;
  835. X    }
  836. X    mday = atoi(p);  /* check the value for sanity after we know the month */
  837. X    SKIP_DIGITS(p);
  838. X    SKIP_WS(p);
  839. X
  840. X    /* month name */
  841. X    month = prefix(month_name,p);
  842. X    if (month < 0) {
  843. X    dprint(5,(debugfile,"missing month: %s\n",p));
  844. X    return 0;
  845. X    }
  846. X    SKIP_ALPHA(p);
  847. X    SKIP_WS(p);
  848. X
  849. X    /* year */
  850. X    if (!(p = get_year(p,&year))) return 0;
  851. X
  852. X    /* time */
  853. X    if (!(p = get_time(p,&minutes,&seconds))) return 0;
  854. X
  855. X    /* zone */
  856. X    for (q=p; *q && !isspace(*q); q++) continue;
  857. X    *q = 0;
  858. X    if (*p=='-' || *p=='+') {
  859. X    char sign = *p++;
  860. X
  861. X    if (isdigit(*p)) {
  862. X        for (i=0; i<4; i++) {
  863. X        if (!isdigit(p[i])) {
  864. X            dprint(5,(debugfile,"ridiculous numeric timezone: %s\n",p));
  865. X            return 0;
  866. X        }
  867. X        p[i] -= '0';
  868. X        }
  869. X        tz = (p[0]*10 + p[1])*60 + p[2]*10 + p[3];
  870. X        if (sign=='-') tz = -tz;
  871. X        sprintf(entry->time_zone, "%d", tz);
  872. X    }
  873. X    else {
  874. X        /* some brain-damaged dates use a '-' before a symbolic time zone */
  875. X        SKIP_WS(p);
  876. X        strncpy(entry->time_zone, p, sizeof(entry->time_zone) - 1);
  877. X        tz = tz_lookup(p);
  878. X    }
  879. X    }
  880. X    else {
  881. X    tz = tz_lookup(p);
  882. X    strncpy(entry->time_zone, p, sizeof(entry->time_zone) - 1);
  883. X    }
  884. X
  885. Xgot_date:
  886. X    month_len[1] = (year%4) ? 28 : 29;
  887. X    if (mday<0 || mday>month_len[month]) {
  888. X    dprint(5,(debugfile,"ridiculous day %d of month %d\n",mday,month));
  889. X    return 0;
  890. X    }
  891. X
  892. X    /* convert back to symbolic form (silly, but the rest of the program
  893. X     * expects it and I'm not about to change all that!)
  894. X     */
  895. X    sprintf(entry->year, "%02d", year);
  896. X    sprintf(entry->month, "%s", month_name[month]);
  897. X    entry->month[0] = toupper(entry->month[0]);
  898. X    sprintf(entry->day, "%d", mday);
  899. X    sprintf(entry->time, "%02d:%02d:%02d",minutes/60,minutes%60,seconds);
  900. X
  901. X    /* shift everything to UTC (aka GMT) before making long time for sorting */
  902. X    minutes -= tz;
  903. X    if (tz > 0) { /* east of Greenwich */
  904. X    if (minutes < 0) {
  905. X        if (--mday < 0) {
  906. X        if (--month < 0) {
  907. X            year--; /* don't worry about 1900! */
  908. X            month = 11;
  909. X        }
  910. X        mday = month_len[month];
  911. X        }
  912. X        minutes += 24*60;
  913. X    }
  914. X    }
  915. X    if (tz < 0) { /* west of Greenwich */
  916. X    if (minutes >= 24*60) {
  917. X        if (++mday > month_len[month]) {
  918. X        if (++month >= 12) {
  919. X            year++; /* don't worry about 1999! */
  920. X            month = 0;
  921. X        }
  922. X        mday = 0;
  923. X        }
  924. X        minutes -= 24*60;
  925. X    }
  926. X    }
  927. X    gmttime = year - 70;         /* make base year */
  928. X    if (gmttime < 0)
  929. X    gmttime += 100;
  930. X    gmttime = gmttime * 365 + (gmttime + 1) / 4;  /* now we have days adjusted for leap years */
  931. X    for (i = 0; i < month; i++)
  932. X    gmttime += month_len[i];
  933. X    if (month > 1 && (year % 4) == 0)
  934. X    gmttime++;            /* now to month adjusted for leap year if after feb */
  935. X    gmttime += mday - 1;        /* and now to the day */
  936. X    gmttime *= 24 * 60;            /* convert to minutes */
  937. X    gmttime += minutes;
  938. X    entry->time_sent = gmttime * 60;    /* now unix seconds since 1/1/70 00:00 GMT */
  939. X
  940. X    return 1;
  941. X}
  942. X
  943. Xfix_arpa_address(address)
  944. Xchar *address;
  945. X{
  946. X    /** Given a pure ARPA address, try to make it reasonable.
  947. X
  948. X        This means that if you have something of the form a@b@b make 
  949. X            it a@b.  If you have something like a%b%c%b@x make it a%b@x...
  950. X    **/
  951. X
  952. X    register int host_count = 0, i;
  953. X    char     hosts[MAX_HOPS][NLEN];    /* array of machine names */
  954. X    char     *host, *addrptr;
  955. X
  956. X    /*  break down into a list of machine names, checking as we go along */
  957. X    
  958. X    addrptr = (char *) address;
  959. X
  960. X    while ((host = get_token(addrptr, "%@", 2)) != NULL) {
  961. X      for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
  962. X          ;
  963. X
  964. X      if (i == host_count) {
  965. X        strcpy(hosts[host_count++], host);
  966. X        if (host_count == MAX_HOPS) {
  967. X           dprint(2, (debugfile, 
  968. X           "Can't build return address - hit MAX_HOPS in fix_arpa_address\n"));
  969. X           error("Can't build return address - hit MAX_HOPS limit!");
  970. X           return(1);
  971. X        }
  972. X      }
  973. X      else 
  974. X        host_count = i + 1;
  975. X      addrptr = NULL;
  976. X    }
  977. X
  978. X    /** rebuild the address.. **/
  979. X
  980. X    address[0] = '\0';
  981. X
  982. X    for (i = 0; i < host_count; i++)
  983. X      sprintf(address, "%s%s%s", address, 
  984. X              address[0] == '\0'? "" : 
  985. X             (i == host_count - 1 ? "@" : "%"),
  986. X              hosts[i]);
  987. X
  988. X    return(0);
  989. X}
  990. X
  991. Xfigure_out_addressee(buffer, mail_to)
  992. Xchar *buffer;
  993. Xchar *mail_to;
  994. X{
  995. X    /** This routine steps through all the addresses in the "To:"
  996. X        list, initially setting it to the first entry (if mail_to
  997. X        is NULL) or, if the user is found (eg "alternatives") to
  998. X        the current "username".
  999. X
  1000. X        Modified to know how to read quoted names...
  1001. X        also modified to look for a comma or eol token and then
  1002. X        try to give the maximal useful information when giving the
  1003. X        default "to" entry (e.g. "Dave Taylor <taylor@hpldat>"
  1004. X        will now give "Dave Taylor" rather than just "Dave")
  1005. X    **/
  1006. X
  1007. X    char *address, *bufptr, mybuf[SLEN];
  1008. X    register int index2 = 0;
  1009. X    
  1010. X    if (equal(mail_to, username)) return;    /* can't be better! */
  1011. X
  1012. X    bufptr = (char *) buffer;           /* use the string directly   */
  1013. X
  1014. X    if (index(buffer,'"') != NULL) {    /* we have a quoted string */
  1015. X      while (*bufptr != '"')
  1016. X        bufptr++;
  1017. X      bufptr++;    /* skip the leading quote */
  1018. X      while (*bufptr != '"' && *bufptr)
  1019. X        mail_to[index2++] = *bufptr++;
  1020. X      mail_to[index2] = '\0';
  1021. X    }
  1022. X
  1023. X    else  {
  1024. X
  1025. X      while ((address = strtok(bufptr, ",\t\n\r")) != NULL) {
  1026. X
  1027. X        if (! okay_address(address, "don't match me!")) {
  1028. X          strcpy(mail_to, username);    /* it's to YOU! */
  1029. X          return;
  1030. X        }
  1031. X        else if (strlen(mail_to) == 0) {    /* it's SOMEthing! */
  1032. X    
  1033. X          /** this next bit is kinda gory, but allows us to use the
  1034. X          existing routines to parse the address - by pretending
  1035. X          it's a From: line and going from there...
  1036. X              Ah well - you get what you pay for, right?
  1037. X          **/
  1038. X
  1039. X          if (strlen(address) > (sizeof mybuf) - 7)    /* ensure it ain't */
  1040. X        address[(sizeof mybuf)-7] = '\0';    /*  too long mon!  */
  1041. X
  1042. X          sprintf(mybuf, "From: %s", address);
  1043. X          parse_arpa_who(mybuf, mail_to, TRUE);
  1044. X/**
  1045. X          get_return_name(address, mail_to, FALSE);
  1046. X**/
  1047. X        }
  1048. X
  1049. X        bufptr = (char *) NULL;    /* set to null */
  1050. X      }
  1051. X    }
  1052. X
  1053. X    return;
  1054. X}
  1055. SHAR_EOF
  1056. echo "File src/addr_util.c is complete"
  1057. chmod 0444 src/addr_util.c || echo "restore of src/addr_util.c fails"
  1058. echo "x - extracting src/alias.c (Text)"
  1059. sed 's/^X//' << 'SHAR_EOF' > src/alias.c &&
  1060. X
  1061. Xstatic char rcsid[] = "@(#)$Id: alias.c,v 4.1 90/04/28 22:42:25 syd Exp $";
  1062. X
  1063. X/*******************************************************************************
  1064. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1065. X *
  1066. X *             Copyright (c) 1986, 1987 Dave Taylor
  1067. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1068. X *******************************************************************************
  1069. X * Bug reports, patches, comments, suggestions should be sent to:
  1070. X *
  1071. X *    Syd Weinstein, Elm Coordinator
  1072. X *    elm@DSI.COM            dsinc!elm
  1073. X *
  1074. X *******************************************************************************
  1075. X * $Log:    alias.c,v $
  1076. X * Revision 4.1  90/04/28  22:42:25  syd
  1077. X * checkin of Elm 2.3 as of Release PL0
  1078. X * 
  1079. X *
  1080. X ******************************************************************************/
  1081. X
  1082. X/** This file contains alias stuff
  1083. X
  1084. X**/
  1085. X
  1086. X#include "headers.h"
  1087. X#include <errno.h>
  1088. X#include <ctype.h>
  1089. X#include <sys/types.h>
  1090. X#include <sys/stat.h>
  1091. X
  1092. X#ifdef BSD
  1093. X#undef        tolower
  1094. X#endif
  1095. X
  1096. X#define    ECHOIT    1     /* echo on for prompting */
  1097. X
  1098. Xchar *get_alias_address();
  1099. Xchar *error_name(), *error_description(), *strip_parens(), *index();
  1100. X
  1101. Xextern int errno;
  1102. X
  1103. X#ifndef DONT_TOUCH_ADDRESSES
  1104. Xchar *expand_system();
  1105. X
  1106. Xextern int  findnode_has_been_initialized;
  1107. X#endif
  1108. X
  1109. Xint
  1110. Xok_alias_name(name)
  1111. Xchar *name;
  1112. X{
  1113. X    while ( *name != '\0' && ok_alias_char(*name) )
  1114. X      ++name;
  1115. X    return ( *name == '\0' );
  1116. X}
  1117. X
  1118. X
  1119. Xread_alias_files()
  1120. X{
  1121. X    /** read the system and user alias files, if present, and if they
  1122. X        have changed since last we read them.
  1123. X    **/
  1124. X
  1125. X    read_system_aliases();
  1126. X    read_user_aliases();
  1127. X}
  1128. X
  1129. Xread_system_aliases()
  1130. X{
  1131. X    /** read the system alias file, if present,
  1132. X        and if it has changed since last we read it.
  1133. X    **/
  1134. X
  1135. X    struct stat hst;
  1136. X    static time_t system_ctime, system_mtime;
  1137. X
  1138. X    /* If hash file hasn't changed, don't bother re-reading. */
  1139. X
  1140. X    if (system_data != -1
  1141. X     && stat(system_hash_file, &hst) == 0
  1142. X     && hst.st_ctime == system_ctime
  1143. X     && hst.st_mtime == system_mtime)
  1144. X      return;
  1145. X
  1146. X    /* Close system data file if it was open. */
  1147. X
  1148. X    if (system_data != -1) {
  1149. X      close(system_data);
  1150. X      system_data = -1;
  1151. X    }
  1152. X
  1153. X    /* Read system hash table.  If we can't, just return. */
  1154. X
  1155. X    if (read_hash_file(system_hash_file, (char *) system_hash_table,
  1156. X                sizeof system_hash_table) < 0)
  1157. X      return;
  1158. X
  1159. X    /* Open system data table. */
  1160. X
  1161. X    if ((system_data = open(system_data_file, O_RDONLY)) == -1) {
  1162. X      dprint(1, (debugfile,
  1163. X              "Warning: Can't open system alias data file %s\n",
  1164. X              system_data_file));
  1165. X      return;
  1166. X    }
  1167. X
  1168. X    /* Remember hash file times. */
  1169. X
  1170. X    system_ctime = hst.st_ctime;
  1171. X    system_mtime = hst.st_mtime;
  1172. X}
  1173. X
  1174. Xread_user_aliases()
  1175. X{
  1176. X    /** read the system alias file, if present,
  1177. X        and if it has changed since last we read it.
  1178. X    **/
  1179. X
  1180. X    struct stat hst;
  1181. X    char fname[SLEN];
  1182. X    static time_t user_ctime, user_mtime;
  1183. X
  1184. X    /* If hash file hasn't changed, don't bother re-reading. */
  1185. X
  1186. X    sprintf(fname, "%s/%s", home, ALIAS_HASH);
  1187. X
  1188. X    if (user_data != -1
  1189. X     && stat(fname, &hst) == 0
  1190. X     && hst.st_ctime == user_ctime
  1191. X     && hst.st_mtime == user_mtime)
  1192. X      return;
  1193. X
  1194. X    /* Close user data file if it was open. */
  1195. X
  1196. X    if (user_data != -1) {
  1197. X      close(user_data);
  1198. X      user_data = -1;
  1199. X    }
  1200. X
  1201. X    /* Read user hash table.  If we can't, just return. */
  1202. X
  1203. X    if (read_hash_file(fname, (char *) user_hash_table,
  1204. X                  sizeof user_hash_table) < 0)
  1205. X      return;
  1206. X
  1207. X    /* Open user data table. */
  1208. X
  1209. X    sprintf(fname, "%s/%s", home, ALIAS_DATA);
  1210. X    if ((user_data = open(fname, O_RDONLY)) == -1) {
  1211. X      dprint(1, (debugfile,
  1212. X         "Warning: Can't open user alias data file %s\n", fname));
  1213. X      return;
  1214. X    }
  1215. X
  1216. X    /* Remember hash file times. */
  1217. X
  1218. X    user_ctime = hst.st_ctime;
  1219. X    user_mtime = hst.st_mtime;
  1220. X}
  1221. X
  1222. Xint
  1223. Xread_hash_file(file, table, table_size)
  1224. Xchar *file, *table;
  1225. Xint table_size;
  1226. X{
  1227. X    /** read the specified alias hash file into the specified table.
  1228. X        it must be _exactly_ the right size or forget it.
  1229. X    **/
  1230. X
  1231. X    struct stat st;
  1232. X    int hash;
  1233. X
  1234. X    /* Open the hash file. */
  1235. X
  1236. X    if ((hash = open(file, O_RDONLY)) == -1) {
  1237. X      dprint(2, (debugfile,
  1238. X        "Warning: Can't open alias hash file %s\n", file));
  1239. X      return -1;
  1240. X    }
  1241. X
  1242. X    /* Be sure the hash file is the correct size. */
  1243. X
  1244. X    if (fstat(hash, &st) == 0 && st.st_size != table_size) {
  1245. X      dprint(2, (debugfile,
  1246. X        "Warning: Alias hash file %s is wrong size (%ld/%d)\n",
  1247. X        file, st.st_size, table_size));
  1248. X      close(hash);
  1249. X      return -1;
  1250. X    }
  1251. X
  1252. X    /* Read the hash file into memory. */
  1253. X
  1254. X    if (read(hash, (char *) table, table_size) != table_size) {
  1255. X      dprint(2, (debugfile,
  1256. X        "Warning: Can't read alias hash file %s\n", file));
  1257. X      close(hash);
  1258. X      return -1;
  1259. X    }
  1260. X
  1261. X    /* Close the hash file; return success. */
  1262. X
  1263. X    close(hash);
  1264. X    return 0;
  1265. X}
  1266. X
  1267. Xint
  1268. Xadd_alias()
  1269. X{
  1270. X    /** add an alias to the user alias text file.  Return zero 
  1271. X        if alias not added in actuality **/
  1272. X
  1273. X    char name[SLEN], *address, address1[LONG_STRING], buffer[LONG_STRING];
  1274. X    char comment[SLEN], ch;
  1275. X    char *strcpy();
  1276. X
  1277. X    strcpy(buffer, "Enter alias name: ");
  1278. X    PutLine0(LINES-2,0, buffer);
  1279. X    CleartoEOLN();
  1280. X    *name = '\0';
  1281. X    optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE);
  1282. X    if (strlen(name) == 0) 
  1283. X      return(0);
  1284. X        if ( !ok_alias_name(name) ) {
  1285. X      error1("Bad character(s) in alias name %s.", name);
  1286. X      return(0);
  1287. X    }
  1288. X    if ((address = get_alias_address(name, FALSE)) != NULL) {
  1289. X      dprint(3, (debugfile, 
  1290. X         "Attempt to add a duplicate alias [%s] in add_alias\n",
  1291. X         address)); 
  1292. X      if (address[0] == '!') {
  1293. X        address[0] = ' ';
  1294. X        error1("Already a group with name %s.", address);
  1295. X      }
  1296. X      else
  1297. X        error1("Already an alias for %s.", address);
  1298. X      return(0);
  1299. X    }
  1300. X
  1301. X    sprintf(buffer, "Enter full name for %s: ", name);
  1302. X    PutLine0(LINES-2,0, buffer);
  1303. X    CleartoEOLN();
  1304. X    *comment = '\0';
  1305. X    optionally_enter(comment, LINES-2, strlen(buffer), FALSE, FALSE);
  1306. X    if (strlen(comment) == 0) strcpy(comment, name);  
  1307. X
  1308. X    sprintf(buffer, "Enter address for %s: ", name);
  1309. X    PutLine0(LINES-2,0, buffer);
  1310. X    CleartoEOLN();
  1311. X    *address1 = '\0';
  1312. X    optionally_enter(address1, LINES-2, strlen(buffer), FALSE, FALSE);
  1313. X    Raw(ON);
  1314. X    if (strlen(address1) == 0) {
  1315. X      error("No address specified!");
  1316. X      return(0);
  1317. X    }
  1318. X    PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1);
  1319. X    CleartoEOLN();
  1320. X    if((ch = want_to("Accept new alias? (y/n) ",'y')) == 'y')
  1321. X      add_to_alias_text(name, comment, address1);
  1322. X    ClearLine(LINES-2);
  1323. X    return(ch == 'y' ? 1 : 0);
  1324. X}
  1325. X
  1326. Xint
  1327. Xdelete_alias()
  1328. X{
  1329. X    /** delete an alias from the user alias text file.  Return zero 
  1330. X        if alias not deleted in actuality **/
  1331. X
  1332. X    char name[SLEN], *address, buffer[LONG_STRING];
  1333. X    char *strcpy();
  1334. X
  1335. X    strcpy(buffer, "Enter alias name for deletion: ");
  1336. X    PutLine0(LINES-2,0, buffer);
  1337. X    CleartoEOLN();
  1338. X    *name = '\0';
  1339. X    optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE);
  1340. X    if (strlen(name) == 0) 
  1341. X      return(0);
  1342. X        if ((address = get_alias_address(name, FALSE))!=NULL)
  1343. X        {
  1344. X                if (address[0] == '!')
  1345. X                {
  1346. X                  address[0] = ' ';
  1347. X                  PutLine1(LINES-1,0,"Group alias: %-60.60s", address);
  1348. X                  CleartoEOLN();
  1349. X            }
  1350. X        else
  1351. X          PutLine1(LINES-1,0,"Aliased address: %-60.60s", address);
  1352. X    }
  1353. X        else 
  1354. X    {
  1355. X          dprint(3, (debugfile, 
  1356. X         "Attempt to delete a non-existent alias [%s] in delete_alias\n",
  1357. X         name)); 
  1358. X         error1("No alias for %s.", name);
  1359. X          return(0);
  1360. X    }
  1361. X    if (want_to("Delete this alias? (y/n) ", 'y') == 'y')
  1362. X    {
  1363. X        if (!delete_from_alias_text(name))
  1364. X        {
  1365. X            CleartoEOS();
  1366. X            return(1);
  1367. X        }
  1368. X    }
  1369. X    CleartoEOS();
  1370. X    return(0);
  1371. X}
  1372. X
  1373. Xint
  1374. Xadd_current_alias()
  1375. X{
  1376. X    /** alias the current message to the specified name and
  1377. X        add it to the alias text file, for processing as
  1378. X        the user leaves the program.  Returns non-zero iff
  1379. X        alias actually added to file **/
  1380. X
  1381. X    char name[SLEN], address1[LONG_STRING], buffer[LONG_STRING], *address;
  1382. X    char comment[SLEN], ch;
  1383. X    struct header_rec *current_header;
  1384. X
  1385. X    if (current == 0) {
  1386. X     dprint(4, (debugfile, 
  1387. X        "Add current alias called without any current message!\n"));
  1388. X     error("No message to alias to!");
  1389. X     return(0);
  1390. X    }
  1391. X    current_header = headers[current - 1];
  1392. X    
  1393. X    strcpy(buffer, "Current message address aliased to: ");
  1394. X    PutLine0(LINES-2,0, buffer);
  1395. X    CleartoEOLN();
  1396. X    *name = '\0';
  1397. X    optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE);
  1398. X    if (strlen(name) == 0)    /* cancelled... */
  1399. X      return(0);
  1400. X        if ( !ok_alias_name(name) ) {
  1401. X      error1("Bad character(s) in alias name %s.", name);
  1402. X      return(0);
  1403. X    }
  1404. X    if ((address = get_alias_address(name, FALSE)) != NULL) {
  1405. X     dprint(3, (debugfile,
  1406. X             "Attempt to add a duplicate alias [%s] in add_current_alias\n",
  1407. X         address)); 
  1408. X      if (address[1] == '!') {
  1409. X        address[0] = ' ';
  1410. X        error1("Already a group with name %s.", address);
  1411. X      }
  1412. X      else 
  1413. X        error1("Already an alias for %s.", address); 
  1414. X          return(0);
  1415. X    }
  1416. X
  1417. X    sprintf(buffer, "Enter full name for %s: ", name);
  1418. X    PutLine0(LINES-2,0, buffer);
  1419. X    CleartoEOLN();
  1420. X
  1421. X    /* use full name in current message for default comment */
  1422. X    tail_of(current_header->from, comment, current_header->to);
  1423. X    if(index(comment, '!') || index(comment, '@'))
  1424. X      /* never mind - it's an address not a full name */
  1425. X      *comment = '\0';
  1426. X
  1427. X    optionally_enter(comment, LINES-2, strlen(buffer), FALSE, FALSE);
  1428. X
  1429. X    /* grab the return address of this message */
  1430. X    get_return(address1, current-1);
  1431. X
  1432. X    strcpy(address1, strip_parens(address1));    /* remove parens! */
  1433. X#ifdef OPTIMIZE_RETURN
  1434. X    optimize_return(address1);
  1435. X#endif
  1436. X    PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1);
  1437. X    CleartoEOLN();
  1438. X    if((ch = want_to("Accept new alias? (y/n) ",'y')) == 'y')
  1439. X      add_to_alias_text(name, comment, address1);
  1440. X    ClearLine(LINES-2);
  1441. X    return(ch == 'y' ? 1 : 0);
  1442. X}
  1443. X
  1444. Xadd_to_alias_text(name, comment, address)
  1445. Xchar *name, *comment, *address;
  1446. X{
  1447. X    /** Add the data to the user alias text file.  Return zero if we
  1448. X        succeeded, 1 if not **/
  1449. X    
  1450. X    FILE *file;
  1451. X    char fname[SLEN];
  1452. X    
  1453. X    sprintf(fname,"%s/%s", home, ALIAS_TEXT);
  1454. X    
  1455. X    save_file_stats(fname);
  1456. X    if ((file = fopen(fname, "a")) == NULL) {
  1457. X      dprint(2, (debugfile, 
  1458. X         "Failure attempting to add alias to file %s within %s",
  1459. X           fname, "add_to_alias_text"));
  1460. X      dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), 
  1461. X           error_description(errno)));
  1462. X      error1("Couldn't open %s to add new alias!", fname);
  1463. X      return(1);
  1464. X    }
  1465. X
  1466. X    if (fprintf(file,"%s = %s = %s\n", name, comment, address) == EOF) {
  1467. X        dprint(2, (debugfile,
  1468. X               "Failure attempting to write alias to file within %s",
  1469. X               fname, "add_to_alias_text"));
  1470. X        dprint(2, (debugfile, "** %s - %s **\n", error_name(errno),
  1471. X               error_description(errno)));
  1472. X        error1("Couldn't write alias to file %s!", fname);
  1473. X        fclose(file);
  1474. X        return(1);
  1475. X    }
  1476. X
  1477. X    fclose(file);
  1478. X
  1479. X    restore_file_stats(fname);
  1480. X
  1481. X    return(0);
  1482. X}
  1483. X
  1484. Xdelete_from_alias_text(name)
  1485. Xchar *name;
  1486. X{
  1487. X    /** Delete the data from the user alias text file.  Return zero if we
  1488. X        succeeded, 1 if not **/
  1489. X    
  1490. X    FILE *file, *tmp_file;
  1491. X    char fname[SLEN], tmpfname[SLEN];
  1492. X    char line_in_file[SLEN+3+SLEN+3+LONG_STRING]; /* name = comment = address */
  1493. X    char name_with_equals[SLEN+2];
  1494. X
  1495. X    strcpy(name_with_equals, name);
  1496. X    strcat(name_with_equals, " ="); 
  1497. X
  1498. X    sprintf(fname,"%s/%s", home, ALIAS_TEXT);
  1499. X    sprintf(tmpfname,"%s/%s.tmp", home, ALIAS_TEXT);
  1500. X    
  1501. X    save_file_stats(fname);
  1502. X
  1503. X    if ((file = fopen(fname, "r")) == NULL) {
  1504. X      dprint(2, (debugfile, 
  1505. X         "Failure attempting to delete alias from file %s within %s",
  1506. X           fname, "delete_from_alias_text"));
  1507. X      dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), 
  1508. X           error_description(errno)));
  1509. X      error1("Couldn't open %s to delete alias!", fname);
  1510. X      return(1);
  1511. X    }
  1512. X
  1513. X    if ((tmp_file = fopen(tmpfname, "w")) == NULL) {
  1514. X      dprint(2, (debugfile, 
  1515. X         "Failure attempting to open temp file %s within %s",
  1516. X           tmpfname, "delete_from_alias_text"));
  1517. X      dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), 
  1518. X           error_description(errno)));
  1519. X      error1("Couldn't open tempfile %s to delete alias!", tmpfname);
  1520. X      return(1);
  1521. X    }
  1522. X
  1523. X    while (fgets(line_in_file, sizeof(line_in_file), file) != (char *)NULL)
  1524. X    {
  1525. X        if (strncmp(name_with_equals, line_in_file,
  1526. X                strlen(name_with_equals)) != 0)
  1527. X            if (fprintf(tmp_file,"%s", line_in_file) == EOF) {
  1528. X                dprint(2, (debugfile, 
  1529. X                       "Failure attempting to write to temp file %s within %s",
  1530. X                       tmpfname, "delete_from_alias_text"));
  1531. X                dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), 
  1532. X                       error_description(errno)));
  1533. X                error1("Couldn't write to tempfile %s!", tmpfname);
  1534. X                fclose(file);
  1535. X                fclose(tmp_file);
  1536. X                unlink(tmpfname);
  1537. X                return(1);
  1538. X            }
  1539. X    }
  1540. X    fclose(file);
  1541. X    fclose(tmp_file);
  1542. X    if (rename(tmpfname, fname) != 0)
  1543. X    {
  1544. X        error1("Couldn't rename tempfile %s after deleting alias!", tmpfname);
  1545. X        return(1);
  1546. X    }
  1547. X
  1548. X    restore_file_stats(fname);
  1549. X
  1550. X    return(0);
  1551. X}
  1552. X
  1553. Xshow_alias_menu()
  1554. X{
  1555. X    MoveCursor(LINES-7,0); CleartoEOS();    
  1556. X        
  1557. X    PutLine0(LINES-7,COLUMNS-45, "Alias commands");
  1558. X    Centerline(LINES-6,
  1559. X      "a)lias current message, d)elete an alias, check a p)erson or s)ystem,");
  1560. X    Centerline(LINES-5,
  1561. X      "l)ist existing aliases, m)ake new alias, or r)eturn");
  1562. X}
  1563. X
  1564. Xalias()
  1565. X{
  1566. X    /** work with alias commands... **/
  1567. X    /** return non-0 if main part of screen overwritten, else 0 **/
  1568. X
  1569. X    char name[NLEN], *address, ch, buffer[SLEN];
  1570. X    int  newaliases = 0, redraw = 0;
  1571. X
  1572. X    if (mini_menu)
  1573. X      show_alias_menu();
  1574. X
  1575. X    /** now let's ensure that we've initialized everything! **/
  1576. X
  1577. X#ifndef DONT_TOUCH_ADDRESSES
  1578. X    
  1579. X    if (! findnode_has_been_initialized) {
  1580. X      if (warnings)
  1581. X        error("Initializing internal tables...");
  1582. X#ifndef USE_DBM
  1583. X      get_connections();
  1584. X      open_domain_file();
  1585. X#endif
  1586. X      init_findnode();
  1587. X      clear_error();
  1588. X          findnode_has_been_initialized = TRUE;
  1589. X    }
  1590. X
  1591. X#endif
  1592. X
  1593. X    define_softkeys(ALIAS);
  1594. X
  1595. X    while (1) {
  1596. X      prompt("Alias: ");
  1597. X      CleartoEOLN();
  1598. X      ch = ReadCh();
  1599. X      MoveCursor(LINES-1,0); CleartoEOS();
  1600. X      
  1601. X      dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch));
  1602. X
  1603. X      switch (tolower(ch)) {
  1604. X        case '?': redraw += alias_help();            break;
  1605. X
  1606. X        case 'a': newaliases += add_current_alias();    break;
  1607. X        case 'd': if (delete_alias()) install_aliases();    break;
  1608. X        case 'l': display_aliases();
  1609. X              redraw++;
  1610. X              if (mini_menu) show_alias_menu();
  1611. X              break;
  1612. X        case 'm': newaliases += add_alias();         break;
  1613. X
  1614. X        case RETURN:
  1615. X        case LINE_FEED:
  1616. X        case 'q':
  1617. X        case 'x':
  1618. X        case 'r': if (newaliases) install_aliases();
  1619. X              clear_error();
  1620. X              return(redraw);
  1621. X        case 'p': if (newaliases) 
  1622. X            error("Warning: new aliases not installed yet!");
  1623. X
  1624. X              strcpy(buffer, "Check for person: ");
  1625. X              PutLine0(LINES-2,0, buffer);
  1626. X              CleartoEOLN();
  1627. X              *name = '\0';
  1628. X              optionally_enter(name, LINES-2, strlen(buffer),
  1629. X            FALSE, FALSE);
  1630. X
  1631. X              if ((address = get_alias_address(name, FALSE))!=NULL) {
  1632. X                    if (address[0] == '!') {
  1633. X                      address[0] = ' ';
  1634. X                      PutLine1(LINES-1,0,"Group alias:%-60.60s", address);
  1635. X                      CleartoEOLN();
  1636. X                }
  1637. X            else
  1638. X              PutLine1(LINES-1,0,"Aliased address: %-60.60s", 
  1639. X              address);
  1640. X              }
  1641. X                  else 
  1642. X            error("Not found.");
  1643. X              break;
  1644. X
  1645. X        case 's': strcpy(buffer, "Check for system: ");
  1646. X              PutLine0(LINES-2,0, buffer);
  1647. X              CleartoEOLN();
  1648. X              *name = '\0';
  1649. X              optionally_enter(name, LINES-2, strlen(buffer),
  1650. X            FALSE, FALSE);
  1651. X              if (talk_to(name)) 
  1652. X#ifdef INTERNET
  1653. X            PutLine1(LINES-1,0,
  1654. X        "You have a direct connection. The address is USER@%s.", 
  1655. X            name);
  1656. X#else
  1657. X            PutLine1(LINES-1,0,
  1658. X        "You have a direct connection. The address is %s!USER.", 
  1659. X            name);
  1660. X#endif
  1661. X              else {
  1662. X                sprintf(buffer, "USER@%s", name);
  1663. X#ifdef DONT_TOUCH_ADDRESSES
  1664. X                 address = buffer;
  1665. X#else
  1666. X                 address = expand_system(buffer, FALSE);
  1667. X#endif
  1668. X                if (strlen(address) > strlen(name) + 7)
  1669. X                  PutLine1(LINES-1,0,"Address is: %.65s", address);
  1670. X                else
  1671. X                  error1("Couldn't expand system %s.", name);
  1672. X              }
  1673. X              break;
  1674. X
  1675. X        case '@': strcpy(buffer, "Fully expand alias: ");
  1676. X              PutLine0(LINES-2,0, buffer);
  1677. X              CleartoEOS();
  1678. X              *name = '\0';
  1679. X              optionally_enter(name, LINES-2, strlen(buffer),
  1680. X            FALSE, FALSE);
  1681. X              if ((address = get_alias_address(name, TRUE)) != NULL) {
  1682. X                    ClearScreen();
  1683. X            PutLine1(3,0,"Aliased address:\n\r%s", address);
  1684. X                    PutLine0(LINES-1,0,"Press <return> to continue.");
  1685. X            (void) getchar();
  1686. X            redraw++;
  1687. X              }
  1688. X                  else 
  1689. X            error("Not found.");
  1690. X              if (mini_menu) show_alias_menu();
  1691. X              break;
  1692. X        default : error("Invalid input!");
  1693. X      }
  1694. X    }
  1695. X}
  1696. X
  1697. Xinstall_aliases()
  1698. X{
  1699. X    /** run the 'newalias' program and update the
  1700. X        aliases before going back to the main program! 
  1701. X    **/
  1702. X
  1703. X
  1704. X    error("Updating aliases...");
  1705. X    sleep(2);
  1706. X
  1707. X    if (system_call(newalias, SH, FALSE, FALSE) == 0) {
  1708. X      error("Re-reading the database in...");
  1709. X      sleep(2);
  1710. X      read_alias_files();
  1711. X      set_error("Aliases updated successfully.");
  1712. X    }
  1713. X    else
  1714. X      set_error("'Newalias' failed.  Please check alias_text.");
  1715. X}
  1716. X
  1717. Xalias_help()
  1718. X{
  1719. X    /** help section for the alias menu... **/
  1720. X    /** return non-0 if main part of screen overwritten, else 0 */
  1721. X    
  1722. X    char ch;
  1723. X    int  redraw=0;
  1724. X    char *alias_prompt = mini_menu ? "Key: " : "Key you want help for: ";
  1725. X
  1726. X    MoveCursor(LINES-3, 0);    CleartoEOS();
  1727. X
  1728. X    if (mini_menu) {
  1729. X      Centerline(LINES-3,
  1730. X "Press the key you want help for, '?' for a key list, or '.' to exit help");
  1731. X    }
  1732. X
  1733. X    lower_prompt(alias_prompt);
  1734. X
  1735. X    while ((ch = ReadCh()) != '.') {
  1736. X      ch = tolower(ch);
  1737. X      switch(ch) {
  1738. X        case '?' : display_helpfile(ALIAS_HELP);    
  1739. X               redraw++;
  1740. X                   if (mini_menu) show_alias_menu();
  1741. X               return(redraw);
  1742. X        case 'a': error(
  1743. X        "a = Add (return) address of current message to alias database.");
  1744. X              break;
  1745. X        case 'd': error("d = Delete a user alias from alias database.");
  1746. X              break;
  1747. X        case 'l': error("l = List all aliases in database.");
  1748. X              break;
  1749. X        case 'm': error(
  1750. X        "m = Make a new user alias, adding to alias database when done.");
  1751. X              break;
  1752. X
  1753. X        case RETURN:
  1754. X        case LINE_FEED:
  1755. X        case 'q':
  1756. X        case 'x':
  1757. X        case 'r': error("Return from alias menu.");
  1758. X                 break;
  1759. X              
  1760. X        case 'p': error("p = Check for a person in the alias database.");
  1761. X              break;
  1762. X    
  1763. X        case 's': error(
  1764. X        "s = Check for a system in the host routing/domain database.");
  1765. X              break;
  1766. X    
  1767. X        default : error("That key isn't used in this section.");
  1768. X                 break;
  1769. X      }
  1770. X      lower_prompt(alias_prompt);
  1771. X    }
  1772. X    return(redraw);
  1773. X}
  1774. X
  1775. Xdisplay_aliases()
  1776. X{
  1777. X    char fname[SLEN];
  1778. X    
  1779. X    sprintf(fname,"%s/%s", home, ALIAS_TEXT);
  1780. X    display_file(fname);
  1781. X    ClearScreen();
  1782. X    return;
  1783. X}
  1784. SHAR_EOF
  1785. chmod 0444 src/alias.c || echo "restore of src/alias.c fails"
  1786. echo "x - extracting src/aliasdb.c (Text)"
  1787. sed 's/^X//' << 'SHAR_EOF' > src/aliasdb.c &&
  1788. X
  1789. Xstatic char rcsid[] = "@(#)$Id: aliasdb.c,v 4.1 90/04/28 22:42:28 syd Exp $";
  1790. X
  1791. X/*******************************************************************************
  1792. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1793. X *
  1794. X *             Copyright (c) 1986, 1987 Dave Taylor
  1795. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1796. X *******************************************************************************
  1797. X * Bug reports, patches, comments, suggestions should be sent to:
  1798. X *
  1799. X *    Syd Weinstein, Elm Coordinator
  1800. X *    elm@DSI.COM            dsinc!elm
  1801. X *
  1802. X *******************************************************************************
  1803. X * $Log:    aliasdb.c,v $
  1804. X * Revision 4.1  90/04/28  22:42:28  syd
  1805. X * checkin of Elm 2.3 as of Release PL0
  1806. X * 
  1807. X *
  1808. X ******************************************************************************/
  1809. X
  1810. X/** Alias database files...
  1811. X
  1812. X**/
  1813. X
  1814. X
  1815. X#include "headers.h"
  1816. X
  1817. X#include <sys/types.h>
  1818. X#include <sys/stat.h>
  1819. X#include <errno.h>
  1820. X
  1821. Xextern int errno;
  1822. X
  1823. X#ifdef USE_DBM
  1824. X# include <dbm.h>
  1825. X#endif
  1826. X
  1827. X#define  absolute(x)        ((x) > 0 ? x : -(x))
  1828. X
  1829. Xchar *find_path_to(), *strcat(), *strcpy();
  1830. Xunsigned long sleep();
  1831. X
  1832. X#ifndef DONT_TOUCH_ADDRESSES
  1833. Xint  findnode_has_been_initialized = FALSE;
  1834. X#endif
  1835. X
  1836. Xfindnode(name, display_error)
  1837. Xchar *name;
  1838. Xint   display_error;
  1839. X{
  1840. X    /** break 'name' into machine!user or user@machine and then
  1841. X        see if you can find 'machine' in the path database..
  1842. X        If so, return name as the expanded address.  If not,
  1843. X        return what was given to us!   If display_error, then
  1844. X        do so...
  1845. X    **/
  1846. X
  1847. X#ifndef DONT_TOUCH_ADDRESSES
  1848. X    
  1849. X    char   old_name[SLEN];
  1850. X    char   address[SLEN];
  1851. X
  1852. X    if (strlen(name) == 0)
  1853. X      return;
  1854. X    
  1855. X    if (! findnode_has_been_initialized) {
  1856. X      if (warnings)
  1857. X        error("Initializing internal tables...");
  1858. SHAR_EOF
  1859. echo "End of part 11"
  1860. echo "File src/aliasdb.c is continued in part 12"
  1861. echo "12" > s2_seq_.tmp
  1862. exit 0
  1863.  
  1864. exit 0 # Just in case...
  1865.