home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / elm2.3 / part12 < prev    next >
Text File  |  1990-06-07  |  51KB  |  1,737 lines

  1. Subject:  v22i071:  ELM mail syste, release 2.3, Part12/26
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 38c20587 15f03fd8 537e0353 5b696aef
  5.  
  6. Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
  7. Posting-number: Volume 22, Issue 71
  8. Archive-name: elm2.3/part12
  9.  
  10. ---- Cut Here and unpack ----
  11. #!/bin/sh
  12. # this is part 12 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file src/aliasdb.c continued
  15. #
  16. CurArch=12
  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/aliasdb.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> src/aliasdb.c
  28. X#ifndef USE_DBM
  29. X      get_connections();
  30. X      open_domain_file();
  31. X#endif
  32. X      init_findnode();
  33. X      clear_error();
  34. X          findnode_has_been_initialized = TRUE;
  35. X    }
  36. X
  37. X    strcpy(old_name, name);        /* save what we were given */
  38. X
  39. X    if (expand_site(name, address) == -1) {
  40. X          if (display_error && name[0] != '!') {
  41. X        dprint(3, (debugfile, "Couldn't expand host %s in address.\n",
  42. X                 name));
  43. X        if (! check_only && warnings) {
  44. X          error1("Couldn't expand system %s.", name);
  45. X          sleep(1);
  46. X        }
  47. X      }
  48. X      strcpy(name, old_name);    /* and restore... */
  49. X    }
  50. X    else
  51. X      strcpy(name, address);
  52. X#endif
  53. X    return;
  54. X}
  55. X
  56. X#if defined(OPTIMIZE_RETURN) || !defined(DONT_TOUCH_ADDRESSES)
  57. Xint
  58. Xexpand_site(cryptic, expanded)
  59. Xchar *cryptic, *expanded;
  60. X{
  61. X
  62. X    /** Given an address of the form 'xyz@site' or 'site!xyz'
  63. X        return an address of the form <expanded address for site>
  64. X            with 'xyz' embedded according to the path database entry.
  65. X        Note that 'xyz' can be eiher a simple address (as in "joe")
  66. X        or a complex address (as in "joe%xerox.parc@Xerox.ARPA")!
  67. X        0 = found, -1 return means unknown site code 
  68. X    
  69. X        Modified to strip out parenthetical comments...
  70. X    **/
  71. X
  72. X#ifdef ACSNET
  73. X
  74. X    strcpy(expanded, cryptic);    /* fast and simple */
  75. X    return(0);
  76. X
  77. X#else
  78. X# ifdef USE_DBM
  79. X    datum  key, contents;
  80. X# endif
  81. X
  82. X    char   name[VERY_LONG_STRING], sitename[VERY_LONG_STRING], 
  83. X               temp[VERY_LONG_STRING], old_name[VERY_LONG_STRING],
  84. X           comment[LONG_STRING];
  85. X    char   *expand_domain(), *addr;
  86. X    register int i = 0, j = 0, in_parens = 0, domain_name;
  87. X
  88. X    strcpy(old_name, cryptic);    /* remember what we were given */
  89. X
  90. X    /** break down **/
  91. X
  92. X    /** first, rip out the comment, if any, noting nested parens **/
  93. X
  94. X    if ((i = chloc(cryptic, '(')) > -1) {
  95. X      comment[j++] = ' ';            /* leading space */
  96. X      do {
  97. X          switch(comment[j++] = cryptic[i++]) {
  98. X        case '(':    in_parens++;
  99. X            break;
  100. X        case ')':    in_parens--;
  101. X            break;
  102. X        }
  103. X      } while(in_parens && cryptic[i] != '\0');
  104. X      comment[j] = '\0';
  105. X
  106. X      /* and remove this from cryptic string too... */
  107. X      if (cryptic[(j = chloc(cryptic,'('))-1] == ' ')
  108. X        cryptic[j-1] = '\0';
  109. X      else
  110. X        cryptic[j] = '\0';
  111. X    }
  112. X    else
  113. X      comment[0] = '\0';
  114. X
  115. X    i = j = 0;    /* reset */
  116. X
  117. X    while (cryptic[i] != AT_SIGN && cryptic[i] != BANG && 
  118. X           cryptic[i] != '\0' && cryptic[i] != '(')
  119. X      sitename[j++] = cryptic[i++];
  120. X
  121. X    sitename[j++] = '\0';
  122. X
  123. X    j = 0;
  124. X    
  125. X    if (cryptic[i] == '\0') return(-1);    /* nothing to expand! */
  126. X
  127. X    domain_name = (cryptic[i] == AT_SIGN);
  128. X
  129. X    i++;
  130. X
  131. X    while (cryptic[i] != '\0' && cryptic[i] != '(' && 
  132. X               ! whitespace(cryptic[i]))
  133. X      name[j++] = cryptic[i++];
  134. X
  135. X    name[j] = '\0';
  136. X
  137. X    if (domain_name) {
  138. X      strcpy(temp, name);
  139. X      strcpy(name, sitename);
  140. X      strcpy(sitename, temp);
  141. X    }
  142. X
  143. X    dprint(5, (debugfile, "\nBroke address into '%s' @ '%s' '%s'\n\n",
  144. X        name, sitename, comment));
  145. X
  146. X#ifdef USE_DBM
  147. X
  148. X    if (size_of_pathfd == 0)
  149. X      return(-1);
  150. X
  151. X    key.dptr  = sitename;
  152. X    key.dsize = strlen(sitename) + 1;
  153. X
  154. X    contents = fetch(key);
  155. X
  156. X    if (contents.dptr == 0) 
  157. X      return(-1);            /* can't find it! */
  158. X
  159. X    sprintf(expanded, contents.dptr, name);
  160. X    strcat(expanded, " ");            /* add a single space... */
  161. X    strcat(expanded, comment);        /*    ...and add comment */
  162. X    return(0);
  163. X#else
  164. X
  165. X#ifndef LOOK_CLOSE_AFTER_SEARCH
  166. X
  167. X    if (talk_to(sitename)) {
  168. X      strcpy(expanded, old_name);    /* restore! */
  169. X      return(0);
  170. X    }
  171. X#endif
  172. X
  173. X    if ((addr = find_path_to(sitename, TRUE)) == NULL) {
  174. X
  175. X#ifdef LOOK_CLOSE_AFTER_SEARCH
  176. X
  177. X        if (talk_to(sitename)) {
  178. X          strcpy(expanded, old_name);    /* restore! */
  179. X          return(0);
  180. X        }
  181. X        else
  182. X#endif
  183. X        if ((addr = expand_domain(cryptic)) != NULL) {
  184. X           strcpy(expanded, addr);    /* into THIS buffer */
  185. X           strcat(expanded, comment);    /* patch in comment */
  186. X           return(0);
  187. X        }
  188. X        else  if (size_of_pathfd == 0) {    /* no path database! */
  189. X          strcpy(expanded, old_name);    /* restore! */
  190. X          return(0);
  191. X        }
  192. X        else {                 /* We just can't get there! */
  193. X          strcpy(expanded, old_name);    /* restore! */
  194. X          return(-1);
  195. X        }
  196. X    }
  197. X    else {            /* search succeeded */
  198. X       sprintf(expanded, addr, name);
  199. X       strcat(expanded, comment);        /* add comment */
  200. X       return(0);
  201. X    }
  202. X#endif
  203. X#endif
  204. X}
  205. X#endif /* defined(OPTIMIZE_RETURN) || !defined(DONT_TOUCH_ADDRESSES) */
  206. X
  207. Xint
  208. Xbinary_search(name, address)
  209. Xchar *name, *address;
  210. X{
  211. X    /* binary search file for name.  Return 0 if found, -1 if not */
  212. X
  213. X    char machine[40];
  214. X    register long first = 0, last, middle;
  215. X    register int  compare;
  216. X
  217. X    address[0] = '\0';
  218. X
  219. X    last = size_of_pathfd;
  220. X
  221. X    do {
  222. X
  223. X      middle = (long) ((first+last) / 2);
  224. X
  225. X      get_entry(machine, address, pathfd, middle);
  226. X
  227. X      compare = strcmp(name, machine);
  228. X
  229. X      if (compare < 0) 
  230. X        last = middle - 1;
  231. X      else if (compare == 0)
  232. X        return(0);
  233. X      else  /* greater */
  234. X        first = middle + 1; 
  235. X    } while (absolute(last) - absolute(first) > FIND_DELTA);
  236. X
  237. X    /* It could be that our target entry lies exactly at `first'.
  238. X     * Since get_entry() compares at the entry beginning after
  239. X     * the passed offset (unless it's 0), we need to decrement it
  240. X     * (unless it's 0), and give it one more try.
  241. X     */
  242. X    get_entry(machine, address, pathfd, (first == 0L ? first : --first));
  243. X    compare = strcmp(name, machine);
  244. X    return(compare == 0 ? 0 : -1);
  245. X}
  246. X
  247. Xget_entry(machine, address, fileid, offset)
  248. Xchar *machine, *address;
  249. XFILE *fileid;
  250. Xlong offset;
  251. X{
  252. X    /** get entry...return machine and address immediately
  253. X        following given offset in fileid.  **/
  254. X
  255. X    (void) fseek(fileid, offset, 0);
  256. X
  257. X    /* To get to the beginning of a record, if we are not at offset 0,
  258. X     * read until we hit an end-of-line */
  259. X
  260. X    if(offset != 0L)
  261. X      while (getc(fileid) != '\n')
  262. X         ;
  263. X
  264. X    fscanf(fileid, "%s\t%s", machine, address);
  265. X}
  266. X
  267. X#ifndef DONT_TOUCH_ADDRESSES
  268. Xinit_findnode()
  269. X{
  270. X    /** Initialize the FILE and 'size_of_file' values for the 
  271. X        findnode procedure **/
  272. X
  273. X    struct stat buffer;
  274. X    char   *path_filename;
  275. X
  276. X#ifdef USE_DBM
  277. X    char buf[BUFSIZ];
  278. X
  279. X    sprintf(buf,"%s.pag", pathfile);
  280. X    path_filename = buf;
  281. X#else
  282. X    path_filename = pathfile;
  283. X#endif
  284. X
  285. X    if (stat(path_filename, &buffer) == -1) {
  286. X      dprint(2, (debugfile, 
  287. X          "Warning: pathalias file \"%s\" wasn't found by %s\n", 
  288. X          path_filename, "init_findnode"));
  289. X      size_of_pathfd = 0;
  290. X      return;
  291. X    }
  292. X
  293. X    size_of_pathfd = (long) buffer.st_size;
  294. X
  295. X#ifdef USE_DBM
  296. X    
  297. X    if (dbminit(pathfile) != 0) {
  298. X      dprint(2, (debugfile,
  299. X         "Warning: couldn't initialize DBM database %s\n", 
  300. X         pathfile));
  301. X      dprint(2, (debugfile, "** %s - %s **\n\n", error_name(errno),
  302. X             error_description(errno)));
  303. X      size_of_pathfd = 0;    /* error flag, in this case */
  304. X      return;
  305. X    }
  306. X     
  307. X    return;
  308. X#else
  309. X
  310. X    if ((pathfd = fopen(pathfile,"r")) == NULL) {
  311. X      dprint(2, (debugfile,
  312. X        "Warning: Can't read pathalias file \"%s\" within %s\n", 
  313. X           pathfile, "init_findnode"));
  314. X      size_of_pathfd = 0;
  315. X    }
  316. X    else
  317. X      dprint(3, (debugfile, "\nOpened '%s' as pathalias database.\n\n", 
  318. X          pathfile));
  319. X#endif
  320. X}
  321. X#endif /* DONT_TOUCH_ADDRESSES */
  322. X
  323. Xchar *find_path_to(machine, printf_format)
  324. Xchar *machine;
  325. Xint   printf_format;
  326. X{
  327. X    /** Returns either the path to the specified machine or NULL if
  328. X        not found.  If "printf_format" is TRUE, then it leaves the
  329. X        '%s' intact, otherwise it assumes that the address is a uucp
  330. X        address for the domain expansion program and removes the
  331. X        last three characters of the expanded name ("!%s") since
  332. X        they're redundant with the expansion!
  333. X        **/
  334. X
  335. X    static char buffer[SLEN];    /* space for path */
  336. X
  337. X    if (size_of_pathfd > 0)
  338. X      if (binary_search(machine, buffer) != -1) {       /* found it! */
  339. X        if (! printf_format && strlen(buffer) > 3)
  340. X          buffer[strlen(buffer)-3] = '\0';
  341. X        return( (char *) buffer);
  342. X      }
  343. X
  344. X    return(NULL);                        /* failed if it's here! */
  345. X}
  346. SHAR_EOF
  347. echo "File src/aliasdb.c is complete"
  348. chmod 0444 src/aliasdb.c || echo "restore of src/aliasdb.c fails"
  349. echo "x - extracting src/aliaslib.c (Text)"
  350. sed 's/^X//' << 'SHAR_EOF' > src/aliaslib.c &&
  351. X
  352. Xstatic char rcsid[] = "@(#)$Id: aliaslib.c,v 4.1 90/04/28 22:42:29 syd Exp $";
  353. X
  354. X/*******************************************************************************
  355. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  356. X *
  357. X *             Copyright (c) 1986, 1987 Dave Taylor
  358. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  359. X *******************************************************************************
  360. X * Bug reports, patches, comments, suggestions should be sent to:
  361. X *
  362. X *    Syd Weinstein, Elm Coordinator
  363. X *    elm@DSI.COM            dsinc!elm
  364. X *
  365. X *******************************************************************************
  366. X * $Log:    aliaslib.c,v $
  367. X * Revision 4.1  90/04/28  22:42:29  syd
  368. X * checkin of Elm 2.3 as of Release PL0
  369. X * 
  370. X *
  371. X ******************************************************************************/
  372. X
  373. X/** Library of functions dealing with the alias system...
  374. X
  375. X **/
  376. X
  377. X#include "headers.h"
  378. X#include <ctype.h>
  379. X
  380. Xchar *get_alias_address(), *get_token(), *strpbrk(), *index();
  381. Xlong lseek();
  382. X
  383. X#ifdef DONT_TOUCH_ADDRESSES
  384. Xchar *expand_system();
  385. X#endif
  386. X
  387. X/*
  388. X * Expand "name" as an alias and return a pointer to static data containing
  389. X * the expansion.  If "name" is not an alias, then NULL is returned.
  390. X */
  391. Xchar *get_alias_address(name, mailing)
  392. Xchar *name;    /* name to expand as an alias                */
  393. Xint mailing;    /* TRUE to fully expand group names & recursive aliases    */
  394. X{
  395. X    static char buffer[VERY_LONG_STRING];
  396. X    char *bufptr;
  397. X    int bufsize;
  398. X
  399. X    /* reads files iff changed since last read */
  400. X    read_alias_files();
  401. X
  402. X    /* if name is an alias then return its expansion */
  403. X    bufptr = buffer;
  404. X    bufsize = sizeof(buffer);
  405. X    if ( do_get_alias(name, &bufptr, &bufsize, mailing, FALSE, 0) )
  406. X      return buffer+2;    /* skip comma/space from add_name_to_list() */
  407. X
  408. X    /* nope...not an alias */
  409. X    return (char *) NULL;
  410. X}
  411. X
  412. X
  413. X/*
  414. X * Determine if "name" is an alias, and if so expand it and store the result in
  415. X * "*bufptr".  TRUE returned if any expansion occurs, else FALSE is returned.
  416. X */
  417. Xint do_get_alias(name, bufptr, bufsizep, mailing, sysalias, depth)
  418. Xchar *name;    /* name to expand as an alias                */
  419. Xchar **bufptr;    /* place to store result of expansion            */
  420. Xint *bufsizep;    /* available space in the buffer            */
  421. Xint mailing;    /* TRUE to fully expand group names & recursive aliases    */
  422. Xint sysalias;    /* TRUE to suppress checks of the user's aliases    */
  423. Xint depth;    /* recursion depth - initially call at depth=0        */
  424. X{
  425. X    char abuf[LONG_STRING];
  426. X    int loc;
  427. X
  428. X    /* update the recursion depth counter */
  429. X    ++depth;
  430. X
  431. X    dprint(6, (debugfile, "%*s->attempting alias expansion on \"%s\"\n",
  432. X        (depth*2), "", name));
  433. X
  434. X    /* strip out (comments) and leading/trailing whitespace */
  435. X    remove_possible_trailing_spaces( name = strip_parens(name) );
  436. X    for ( ; isspace(*name)  ; ++name ) ;
  437. X
  438. X    /* throw back empty addresses */
  439. X    if ( *name == '\0' )
  440. X      return FALSE;
  441. X
  442. X    /* check for a user alias, unless in the midst of sys alias expansion */
  443. X    if ( !sysalias && user_data != -1 ) {
  444. X      if ( (loc = find(name, user_hash_table, MAX_UALIASES)) >= 0 ) {
  445. X        lseek(user_data, ntohl(user_hash_table[loc].byte), 0L);
  446. X        get_line(user_data, abuf);
  447. X        goto do_expand;
  448. X      }
  449. X    }
  450. X
  451. X    /* check for a system alias */
  452. X    if ( system_data != -1 ) {
  453. X      if ( (loc = find(name, system_hash_table, MAX_SALIASES)) >= 0 ) {
  454. X        lseek(system_data, ntohl(system_hash_table[loc].byte), 0L);
  455. X        get_line(system_data, abuf);
  456. X        sysalias = TRUE;
  457. X        goto do_expand;
  458. X      }
  459. X    }
  460. X
  461. X    /* nope...this name wasn't an alias */
  462. X    return FALSE;
  463. X
  464. Xdo_expand:
  465. X
  466. X    /* at this point, alias is expanded into "abuf" - now what to do... */
  467. X
  468. X    dprint(7, (debugfile, "%*s  ->expanded alias to \"%s\"\n",
  469. X        (depth*2), "", abuf));
  470. X
  471. X    /* check for an exact match */
  472. X    loc = strlen(name);
  473. X    if (strncmp(name, abuf, loc) == 0 && (abuf[loc] == ' ' || abuf[loc] == '\0'))
  474. X#ifdef DONT_TOUCH_ADDRESSES
  475. X      return add_name_to_list(abuf, bufptr, bufsizep);
  476. X#else
  477. X      return add_name_to_list(expand_system(abuf, TRUE), bufptr, bufsizep);
  478. X#endif
  479. X
  480. X    /* see if we are stuck in a loop */
  481. X    if ( depth > 12 ) {
  482. X      dprint(2, (debugfile,
  483. X          "alias expansion loop detected at \"%s\" - bailing out\n", name));
  484. X        error1("Error expanding \"%s\" - probable alias definition loop.",
  485. X          name);
  486. X        return FALSE;
  487. X    }
  488. X
  489. X    /* see if the alias equivalence is a group name */
  490. X    if ( mailing && abuf[0] == '!' )
  491. X      return do_expand_group(abuf+1, bufptr, bufsizep, sysalias, depth);
  492. X
  493. X    /* see if the alias equivalence is an email address */
  494. X    if ( strpbrk(abuf,"!@:") != NULL ) {
  495. X#ifdef DONT_TOUCH_ADDRESSES
  496. X      return add_name_to_list(abuf, bufptr, bufsizep);
  497. X#else
  498. X      return add_name_to_list(expand_system(abuf, TRUE), bufptr, bufsizep);
  499. X#endif
  500. X    }
  501. X
  502. X    /* see if the alias equivalence is itself an alias */
  503. X    if ( mailing && do_get_alias(abuf,bufptr,bufsizep,TRUE,sysalias,depth) )
  504. X      return TRUE;
  505. X
  506. X    /* the alias equivalence must just be a local address */
  507. X    return add_name_to_list(abuf, bufptr, bufsizep);
  508. X}
  509. X
  510. X
  511. X/*
  512. X * Expand the comma-delimited group of names in "group", storing the result
  513. X * in "*bufptr".  Returns TRUE if expansion occurs OK, else FALSE in the
  514. X * event of errors.
  515. X */
  516. Xint do_expand_group(group, bufptr, bufsizep, sysalias, depth)
  517. Xchar *group;    /* group list to expand                    */
  518. Xchar **bufptr;    /* place to store result of expansion            */
  519. Xint *bufsizep;    /* available space in the buffer            */
  520. Xint sysalias;    /* TRUE to suppress checks of the user's aliases    */
  521. Xint depth;    /* nesting depth                    */
  522. X{
  523. X    char *name;
  524. X
  525. X    /* go through each comma-delimited name in the group */
  526. X    while ( group != NULL ) {
  527. X
  528. X      /* extract the next name from the list */
  529. X      for ( name = group ; isspace(*name) ; ++name ) ;
  530. X      if ( (group = index(name,',')) != NULL )
  531. X          *group++ = '\0';
  532. X      remove_possible_trailing_spaces(name);
  533. X      if ( *name == '\0' )
  534. X        continue;
  535. X
  536. X      /* see if this name is really an alias */
  537. X      if ( do_get_alias(name, bufptr, bufsizep, TRUE, sysalias, depth) )
  538. X        continue;
  539. X
  540. X      /* verify it is a valid address */
  541. X      if ( !valid_name(name) ) {
  542. X        dprint(3, (debugfile,
  543. X        "Illegal address %s during list expansion in %s\n",
  544. X        name, "do_get_alias"));
  545. X        error1("%s is an illegal address!", name);
  546. X        return FALSE;
  547. X      }
  548. X
  549. X      /* add it to the list */
  550. X      if ( !add_name_to_list(name, bufptr, bufsizep) )
  551. X        return FALSE;
  552. X
  553. X    }
  554. X
  555. X    return TRUE;
  556. X}
  557. X
  558. X
  559. X/*
  560. X * Append "<comma><space>name" to the list, checking to ensure the buffer
  561. X * does not overflow.  Upon return, *bufptr and *bufsizep will be updated to
  562. X * reflect the stuff added to the buffer.  If a buffer overflow would occur,
  563. X * an error message is printed and FALSE is returned, else TRUE is returned.
  564. X */
  565. Xint add_name_to_list(name,bufptr,bufsizep)
  566. Xregister char *name;    /* name to append to buffer            */
  567. Xchar **bufptr;        /* pointer to pointer to end of buffer        */
  568. Xint *bufsizep;        /* pointer to space remaining in buffer        */
  569. X{
  570. X    register char *dest = *bufptr;
  571. X    register int bufsize = *bufsizep;
  572. X
  573. X    if ( bufsize < 2 )
  574. X      return FALSE;
  575. X    *dest++ = ','; --bufsize;
  576. X    *dest++ = ' '; --bufsize;
  577. X
  578. X    while ( *name != '\0' && --bufsize > 0 )
  579. X      *dest++ = *name++ ;
  580. X    *dest = '\0';
  581. X
  582. X    *bufptr = dest;
  583. X    *bufsizep = bufsize;
  584. X    if ( bufsize <= 0 ) {
  585. X      error("Alias expansion is too long.");
  586. X      return FALSE;
  587. X    }
  588. X
  589. X    return TRUE;
  590. X}
  591. X
  592. X
  593. X
  594. X#ifndef DONT_TOUCH_ADDRESSES
  595. Xchar *expand_system(buffer, show_errors)
  596. Xchar *buffer;
  597. Xint   show_errors;
  598. X{
  599. X    /** This routine will check the first machine name in the given path
  600. X        (if any) and expand it out if it is an alias...if not, it will
  601. X        return what it was given.  If show_errors is false, it won't
  602. X        display errors encountered...
  603. X    **/
  604. X
  605. X    dprint(6, (debugfile, "expand_system(%s, show-errors=%s)\n", buffer,
  606. X        onoff(show_errors)));
  607. X    findnode(buffer, show_errors);
  608. X
  609. X    return( (char *) buffer);
  610. X}
  611. X#endif
  612. X
  613. Xint
  614. Xfind(word, table, size)
  615. Xchar *word;
  616. Xstruct alias_rec table[];
  617. Xint size;
  618. X{
  619. X    /** find word and return loc, or -1 **/
  620. X    register int loc;
  621. X
  622. X    if (strlen(word) > 20) {
  623. X      dprint(3, (debugfile, "Overly long alias name entered: %s\n", word));
  624. X      error1("Bad alias name: %s.  Too long.\n", word);
  625. X      return(-1);
  626. X    }
  627. X
  628. X    loc = hash_it(word, size);
  629. X
  630. X    while (stricmp(word, table[loc].name) != 0) {
  631. X      if (table[loc].name[0] == '\0')
  632. X        return(-1);
  633. X      loc = (loc + 1) % size;
  634. X    }
  635. X
  636. X    return(loc);
  637. X}
  638. X
  639. Xint
  640. Xstricmp(s1,s2)
  641. Xregister char *s1, *s2;
  642. X{
  643. X    /* case insensitive comparison */
  644. X    register int d;
  645. X    for (;;) {
  646. X      d = ( isupper(*s1) ? tolower(*s1) : *s1 )
  647. X          - ( isupper(*s2) ? tolower(*s2) : *s2 ) ;
  648. X      if ( d != 0 || *s1 == '\0' || *s2 == '\0' )
  649. X        return d;
  650. X      ++s1;
  651. X      ++s2;
  652. X    }
  653. X    /*NOTREACHED*/
  654. X}
  655. X
  656. Xint
  657. Xhash_it(string, table_size)
  658. Xregister char *string;
  659. Xint   table_size;
  660. X{
  661. X    /** compute the hash function of the string, returning
  662. X        it (mod table_size) **/
  663. X
  664. X    register int sum = 0;
  665. X    for ( ; *string != '\0' ; ++string )
  666. X      sum += (int) ( isupper(*string) ? tolower(*string) : *string );
  667. X
  668. X    return(sum % table_size);
  669. X}
  670. X
  671. Xget_line(fd, buffer)
  672. Xint fd;
  673. Xchar *buffer;
  674. X{
  675. X    /* Read from file fd.  End read upon reading either
  676. X       EOF or '\n' character (this is where it differs
  677. X       from a straight 'read' command!) */
  678. X
  679. X    register int i= 0;
  680. X    char     ch;
  681. X
  682. X    while (read(fd, &ch, 1) > 0)
  683. X      if (ch == '\n' || ch == '\r') {
  684. X        buffer[i] = 0;
  685. X        return;
  686. X      }
  687. X      else
  688. X        buffer[i++] = ch;
  689. X}
  690. SHAR_EOF
  691. chmod 0444 src/aliaslib.c || echo "restore of src/aliaslib.c fails"
  692. echo "x - extracting src/args.c (Text)"
  693. sed 's/^X//' << 'SHAR_EOF' > src/args.c &&
  694. X
  695. Xstatic char rcsid[] = "@(#)$Id: args.c,v 4.1 90/04/28 22:42:31 syd Exp $";
  696. X
  697. X/*******************************************************************************
  698. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  699. X *
  700. X *             Copyright (c) 1986, 1987 Dave Taylor
  701. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  702. X *******************************************************************************
  703. X * Bug reports, patches, comments, suggestions should be sent to:
  704. X *
  705. X *    Syd Weinstein, Elm Coordinator
  706. X *    elm@DSI.COM            dsinc!elm
  707. X *
  708. X *******************************************************************************
  709. X * $Log:    args.c,v $
  710. X * Revision 4.1  90/04/28  22:42:31  syd
  711. X * checkin of Elm 2.3 as of Release PL0
  712. X * 
  713. X *
  714. X ******************************************************************************/
  715. X
  716. X/** starting argument parsing routines for ELM system...
  717. X
  718. X**/
  719. X
  720. X#include "headers.h"
  721. X#include "patchlevel.h"
  722. X
  723. Xextern char *optarg;        /* optional argument as we go */
  724. Xextern int   optind;            /* argnum + 1 when we leave   */
  725. X
  726. Xvoid exit();    /* just keeping lint happy.... */
  727. X
  728. Xchar *
  729. Xparse_arguments(argc, argv, to_whom)
  730. Xint argc;
  731. Xchar *argv[], *to_whom;
  732. X{
  733. X    /** Set flags according to what was given to program.  If we are 
  734. X        fed a name or series of names, put them into the 'to_whom' buffer
  735. X        and if the check_only flag wasn't presented, set mail_only to ON,
  736. X        and if stdin is not a tty, set batch_only  to ON;
  737. X        Return req_mfile, which points to a named mail file or is empty.
  738. X        **/
  739. X
  740. X    register int c = 0;
  741. X    char *strcpy();
  742. X    static char req_mfile[SLEN];
  743. X
  744. X    to_whom[0] = '\0';
  745. X    batch_subject[0] = '\0';
  746. X
  747. X        while ((c = getopt(argc, argv, "?acd:f:hkKms:Vvwz")) != EOF) {
  748. X       switch (c) {
  749. X         case 'a' : arrow_cursor++;        break;
  750. X         case 'c' : check_only++;        break;
  751. X         case 'd' : debug = atoi(optarg);    break;
  752. X         case 'f' : strcpy(req_mfile, optarg);    break;
  753. X         case '?' :
  754. X         case 'h' : args_help();
  755. X         case 'k' : hp_terminal++;    break;
  756. X         case 'K' : hp_terminal++; hp_softkeys++;    break;
  757. X         case 'm' : mini_menu = 0;    break;
  758. X         case 's' : strcpy(batch_subject, optarg);    break;
  759. X             case 'V' : sendmail_verbose++;     break;
  760. X         case 'v' : args_version();
  761. X         case 'w' : warnings = 0;    break;
  762. X         case 'z' : check_size++;   break;
  763. X        }
  764. X     }
  765. X
  766. X
  767. X#ifndef DEBUG
  768. X    if (debug)
  769. X      printf(
  770. X     "Warning: system created without debugging enabled - request ignored\n");
  771. X    debug = 0;
  772. X#endif
  773. X
  774. X    if (optind < argc) {
  775. X      while (optind < argc) {
  776. X        if (strlen(to_whom) + strlen(to_whom[0] != '\0'? " " : "") +
  777. X            strlen(argv[optind]) > SLEN)
  778. X                exit(printf("\n\rToo many addresses, or addresses too long!\n\r"));
  779. X
  780. X        sprintf(to_whom, "%s%s%s", to_whom, 
  781. X                to_whom[0] != '\0'? " " : "", argv[optind]);
  782. X        if(!check_only)
  783. X          mail_only++;
  784. X        optind++;
  785. X      }
  786. X      check_size = 0;    /* NEVER do this if we're mailing!! */
  787. X    }
  788. X
  789. X     if (strlen(batch_subject) > 0 && ! mail_only) 
  790. X       exit(printf(
  791. X     "\n\rDon't understand specifying a subject and no-one to send to!\n\r"));
  792. X
  793. X    if (!isatty(fileno(stdin)) && !check_only) {
  794. X      batch_only = ON;
  795. X      if(*batch_subject == '\0')
  796. X        strcpy(batch_subject, DEFAULT_BATCH_SUBJECT);
  797. X    }
  798. X    return(req_mfile);
  799. X
  800. X
  801. X}
  802. X
  803. Xargs_help()
  804. X{
  805. X    /**  print out possible starting arguments... **/
  806. X
  807. X    printf("\nPossible Starting Arguments for ELM program:\n\n");
  808. X    printf("\targ\t\t\tMeaning\n");
  809. X    printf("\t -a \t\tArrow - use the arrow pointer regardless\n");
  810. X    printf("\t -c \t\tCheckalias - check the given aliases only\n");
  811. X    printf("\t -dn\t\tDebug - set debug level to 'n'\n");
  812. X    printf(
  813. X      "\t -fx\t\tFolder - read folder 'x' rather than incoming mailbox\n");
  814. X    printf("\t -h \t\tHelp - give this list of options\n");
  815. X    printf("\t -k \t\tKeypad - enable HP 2622 terminal keyboard\n");
  816. X    printf("\t -K \t\tKeypad&softkeys - enable use of softkeys + \"-k\"\n");
  817. X    printf("\t -m \t\tMenu - Turn off menu, using more of the screen\n");
  818. X    printf("\t -sx\t\tSubject 'x' - for batchmailing\n");
  819. X        printf("\t -V \t\tEnable sendmail voyeur mode.\n");
  820. X    printf("\t -v \t\tPrint out ELM version information.\n");
  821. X    printf("\t -w \t\tSupress warning messages...\n");
  822. X    printf("\t -z \t\tZero - don't enter ELM if no mail is pending\n");
  823. X    printf("\n");
  824. X    printf("\n");
  825. X    exit(1);
  826. X}
  827. X
  828. Xargs_version()
  829. X{
  830. X    /** print out version information **/
  831. X
  832. X    printf("\nElm Version and Identification Information:\n\n");
  833. X    printf("\tElm %s PL%d, of %s\n",VERSION,PATCHLEVEL,VERS_DATE);
  834. X    printf("\t(C) Copyright 1986, 1987 Dave Taylor\n");
  835. X    printf("\t(C) Copyright 1988, 1989, 1990 USENET Community Trust\n");
  836. X    printf("\t----------------------------------\n");
  837. X    printf("\tConfigured %s\n", CONFIGURE_DATE);
  838. X    printf("\t----------------------------------\n");
  839. X
  840. X#ifdef USE_EMBEDDED_ADDRESSES
  841. X    printf("\tFrom: and Reply-To: addresses are good: USE_EMBEDDED_ADDRESSES\n");
  842. X#else /* USE_EMBEDDED_ADDRESSES */
  843. X    printf("\tFrom: and Reply-To: addresses ignored: not USE_EMBEDDED_ADDRESSES\n");
  844. X#endif /* USE_EMBEDDED_ADDRESSES */
  845. X
  846. X#ifdef OPTIMIZE_RETURN
  847. X    printf("\tReturn addresses will be optimized: OPTIMIZE_RETURN\n");
  848. X#else /* OPTIMIZE_RETURN */
  849. X    printf("\tReturn addresses will not be optimized: not OPTIMIZE_RETURN\n");
  850. X#endif
  851. X
  852. X#ifdef INTERNET
  853. X    printf("\tPrefers Internet address formats: INTERNET\n");
  854. X#else /* INTERNET */
  855. X    printf("\tInternet address formats not used: not INTERNET\n");
  856. X#endif /* INTERNET */
  857. X
  858. X#ifdef DEBUG
  859. X    printf("\tDebug options are available: DEBUG\n");
  860. X#else /* DEBUG */
  861. X    printf("\tNo debug options are available: not DEBUG\n");
  862. X#endif /* DEBUG */
  863. X        
  864. X#ifdef CRYPT
  865. X    printf("\tCrypt function enabled: CRYPT\n");
  866. X#else /* CRYPT */
  867. X    printf("\tCrypt function disabled: not CRYPT\n");
  868. X#endif /* CRYPT */
  869. X
  870. X#ifdef ALLOW_MAILBOX_EDITING
  871. X    printf("\tMailbox editing included: ALLOW_MAILBOX_EDITING\n");
  872. X#else /* ALLOW_MAILBOX_EDITING */
  873. X    printf("\tMailbox editing not included: not ALLOW_MAILBOX_EDITING\n");
  874. X#endif /* ALLOW_MAILBOX_EDITING */
  875. X
  876. X#ifdef ENABLE_CALENDAR
  877. X    printf("\tCalendar file feature enabled: ENABLE_CALENDAR\n");
  878. X    printf("\t\t(Default calendar file is %s)\n",dflt_calendar_file);
  879. X#else /* ENABLE_CALENDAR */
  880. X    printf("\tCalendar file feature disabled: not ENABLE_CALENDAR\n");
  881. X#endif /* ENABLE_CALENDAR */
  882. X
  883. X    printf("\n\n");
  884. X    exit(1);
  885. X
  886. X}
  887. X
  888. SHAR_EOF
  889. chmod 0444 src/args.c || echo "restore of src/args.c fails"
  890. echo "x - extracting src/bouncebk.c (Text)"
  891. sed 's/^X//' << 'SHAR_EOF' > src/bouncebk.c &&
  892. X
  893. Xstatic char rcsid[] = "@(#)$Id: bouncebk.c,v 4.1 90/04/28 22:42:33 syd Exp $";
  894. X
  895. X/*******************************************************************************
  896. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  897. X *
  898. X *             Copyright (c) 1986, 1987 Dave Taylor
  899. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  900. X *******************************************************************************
  901. X * Bug reports, patches, comments, suggestions should be sent to:
  902. X *
  903. X *    Syd Weinstein, Elm Coordinator
  904. X *    elm@DSI.COM            dsinc!elm
  905. X *
  906. X *******************************************************************************
  907. X * $Log:    bouncebk.c,v $
  908. X * Revision 4.1  90/04/28  22:42:33  syd
  909. X * checkin of Elm 2.3 as of Release PL0
  910. X * 
  911. X *
  912. X ******************************************************************************/
  913. X
  914. X/** This set of routines implement the bounceback feature of the mailer.
  915. X    This feature allows mail greater than 'n' hops away (n specified by
  916. X    the user) to have a 'cc' to the user through the remote machine.  
  917. X
  918. X    Due to the vagaries of the Internet addressing (uucp -> internet -> uucp)
  919. X    this will NOT generate bounceback copies with mail to an internet host!
  920. X
  921. X**/
  922. X
  923. X#include "headers.h"
  924. X
  925. Xchar *bounce_off_remote(),        /* forward declaration */
  926. X     *strcat(), *strcpy();
  927. X
  928. Xint
  929. Xuucp_hops(to)
  930. Xchar *to;
  931. X{    
  932. X    /** Given the entire "To:" list, return the number of hops in the
  933. X        first address (a hop = a '!') or ZERO iff the address is to a
  934. X          non uucp address.
  935. X    **/
  936. X
  937. X    register int hopcount = 0, iindex;
  938. X
  939. X    for (iindex = 0; ! whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
  940. X      if (to[iindex] == '!')
  941. X        hopcount++;
  942. X      else if (to[iindex] == '@' || to[iindex] == '%' || to[iindex] == ':')
  943. X        return(0);    /* don't continue! */
  944. X    }
  945. X
  946. X    return(hopcount);
  947. X}
  948. X    
  949. Xchar *bounce_off_remote(to)
  950. Xchar *to;
  951. X{
  952. X    /** Return an address suitable for framing (no, that's not it...)
  953. X        Er, suitable for including in a 'cc' line so that it ends up
  954. X        with the bounceback address.  The method is to take the first 
  955. X        address in the To: entry and break it into machines, then 
  956. X        build a message up from that.  For example, consider the
  957. X        following address:
  958. X            a!b!c!d!e!joe
  959. X        the bounceback address would be;
  960. X            a!b!c!d!e!d!c!b!a!ourmachine!ourname
  961. X        simple, eh?
  962. X    **/
  963. X
  964. X    static char address[LONG_STRING];    /* BEEG address buffer! */
  965. X
  966. X    char   host[MAX_HOPS][NLEN];    /* for breaking up addr */
  967. X    register int hostcount = 0, hindex = 0, 
  968. X           iindex;
  969. X
  970. X    for (iindex = 0; !whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
  971. X      if (to[iindex] == '!') {
  972. X        host[hostcount][hindex] = '\0';
  973. X        hostcount++;
  974. X        hindex = 0;
  975. X      }
  976. X      else 
  977. X        host[hostcount][hindex++] = to[iindex];
  978. X    }
  979. X
  980. X    /* we have hostcount hosts... */
  981. X
  982. X    strcpy(address, host[0]);    /* initialize it! */
  983. X
  984. X    for (iindex=1; iindex < hostcount; iindex++) {
  985. X      strcat(address, "!");
  986. X      strcat(address, host[iindex]);
  987. X    }
  988. X    
  989. X    /* and now the same thing backwards... */
  990. X
  991. X    for (iindex = hostcount -2; iindex > -1; iindex--) {
  992. X      strcat(address, "!");
  993. X      strcat(address, host[iindex]);
  994. X    }
  995. X
  996. X    /* and finally, let's tack on our machine and login name */
  997. X
  998. X    strcat(address, "!");
  999. X    strcat(address, hostname);
  1000. X    strcat(address, "!");
  1001. X    strcat(address, username);
  1002. X
  1003. X    /* and we're done!! */
  1004. X
  1005. X    return( (char *) address );
  1006. X}
  1007. SHAR_EOF
  1008. chmod 0444 src/bouncebk.c || echo "restore of src/bouncebk.c fails"
  1009. echo "x - extracting src/builtin.c (Text)"
  1010. sed 's/^X//' << 'SHAR_EOF' > src/builtin.c &&
  1011. X
  1012. Xstatic char rcsid[] = "@(#)$Id: builtin.c,v 4.1 90/04/28 22:42:34 syd Exp $";
  1013. X
  1014. X/*******************************************************************************
  1015. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1016. X *
  1017. X *             Copyright (c) 1986, 1987 Dave Taylor
  1018. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1019. X *******************************************************************************
  1020. X * Bug reports, patches, comments, suggestions should be sent to:
  1021. X *
  1022. X *    Syd Weinstein, Elm Coordinator
  1023. X *    elm@DSI.COM            dsinc!elm
  1024. X *
  1025. X *******************************************************************************
  1026. X * $Log:    builtin.c,v $
  1027. X * Revision 4.1  90/04/28  22:42:34  syd
  1028. X * checkin of Elm 2.3 as of Release PL0
  1029. X * 
  1030. X *
  1031. X ******************************************************************************/
  1032. X
  1033. X/** This is the built-in pager for displaying messages while in the Elm
  1034. X    program.  It's a bare-bones pager with precious few options. The idea
  1035. X    is that those systems that are sufficiently slow that using an external
  1036. X    pager such as 'more' is too slow, then they can use this!
  1037. X
  1038. X    Also added support for the "builtin+" pager (clears the screen for
  1039. X    each new page) including a two-line overlap for context...
  1040. X
  1041. X**/
  1042. X
  1043. X#include "headers.h"
  1044. X#include <ctype.h>
  1045. X
  1046. X#define  BEEP        007        /* ASCII Bell character */
  1047. X
  1048. Xstatic    unfilled_lines,
  1049. X    form_title;
  1050. X
  1051. Xint    lines_displayed,        /* total number of lines displayed      */
  1052. X    total_lines_to_display,        /* total number of lines in message     */
  1053. X    pages_displayed;         /* for the nth page titles and all      */
  1054. X
  1055. Xstart_builtin(lines_in_message)
  1056. Xint lines_in_message;
  1057. X{
  1058. X    /** clears the screen and resets the internal counters... **/
  1059. X
  1060. X    dprint(8,(debugfile, 
  1061. X        "displaying %d lines from message using internal pager\n",
  1062. X        lines_in_message));
  1063. X
  1064. X    unfilled_lines = LINES;
  1065. X    form_title = 1;
  1066. X    lines_displayed = 0;
  1067. X        pages_displayed = 1;
  1068. X
  1069. X    total_lines_to_display = lines_in_message;
  1070. X}
  1071. X
  1072. Xextern int tabspacing;
  1073. X
  1074. Xint
  1075. Xnext_line(inputptr, output, width)
  1076. Xchar **inputptr, *output;
  1077. Xregister unsigned width;
  1078. X{
  1079. X    /* Copy characters from input to output and copy
  1080. X     * remainder of output to output. In copying use ^X notation for
  1081. X     * control characters, '?' non-ascii characters, expand tabs
  1082. X     * to correct number of spaces till next tab stop.
  1083. X     * Column zero of the next line is considered to be the tab stop
  1084. X     * that follows the last one that fits on a line.
  1085. X     * Copy until newline/return encountered, null char encountered,
  1086. X     * width characters producted in output buffer.
  1087. X     * Formfeed is handled exceptionally. If encountered it
  1088. X     * is removed from input and 1 is returned. Otherwise 0 is returned.
  1089. X     */
  1090. X
  1091. X    register char *optr, *iptr;
  1092. X    register unsigned chars_output, nt;
  1093. X    int ret_val;
  1094. X
  1095. X    optr = output;
  1096. X    iptr = *inputptr;
  1097. X    chars_output = 0;
  1098. X
  1099. X    ret_val = 0;    /* presume no formfeed */
  1100. X    while(1) {
  1101. X
  1102. X      if(chars_output >= width) {        /* no more room on line */
  1103. X        *optr++ = '\n';
  1104. X        *optr++ = '\r';
  1105. X        /* if next input character is newline or return,
  1106. X         * we can skip over it since we are outputing a newline anyway */ 
  1107. X        if((*iptr == '\n') || (*iptr == '\r'))
  1108. X          iptr++;
  1109. X        break;        
  1110. X      } else if (*iptr == '\n' || *iptr == '\r') {    /*newline or return */
  1111. X        *optr++ = '\n';
  1112. X        *optr++ = '\r';
  1113. X        iptr++;
  1114. X        break;            /* end of line */
  1115. X      } else if(*iptr == '\f') {        /* formfeed */
  1116. X        /* if next input character is newline or return,
  1117. X         * we can skip over it since we are outputing a formfeed anyway */ 
  1118. X        if((*++iptr == '\n') || (*iptr == '\r'))
  1119. X          iptr++;
  1120. X        ret_val = 1;
  1121. X        break;            /* leave rest of screen clear */
  1122. X      } else if(*iptr == '\0') {        /* none left in input string */
  1123. X        break;
  1124. X      } else if(*iptr == '\t') {        /* tab stop */
  1125. X        if((nt=next_tab(chars_output+1)) > width) {
  1126. X          *optr++ = '\n';        /* won't fit on this line - autowrap */
  1127. X          *optr++ = '\r';        /* tab by tabbing so-to-speak to 1st */
  1128. X          iptr++;            /* column of next line */
  1129. X          break;
  1130. X        } else {        /* will fit - output proper num of spaces */
  1131. X          while(chars_output < nt-1) {
  1132. X        chars_output++;
  1133. X        *optr++ = ' ';
  1134. X          }
  1135. X          iptr++;
  1136. X        }
  1137. X      } else if(isprint(*iptr)) {
  1138. X        *optr++ = *iptr++;            /* printing character */
  1139. X        chars_output++;
  1140. X      } else {            /* non-white space control character */
  1141. X        if(chars_output + 2 <= width) {
  1142. X          *optr++ = '^';    
  1143. X          *optr++ = (*iptr == '\177' ? '?' : (*iptr&0177) + 'A' - 1);
  1144. X          iptr++;
  1145. X          chars_output += 2;
  1146. X        } else {            /* no space on line for both chars */
  1147. X          break;
  1148. X        }
  1149. X      }
  1150. X    }
  1151. X    *optr = '\0';
  1152. X    *inputptr = iptr;
  1153. X    return(ret_val);
  1154. X}
  1155. X
  1156. X
  1157. Xint
  1158. Xdisplay_line(input_line)
  1159. Xchar *input_line;
  1160. X{
  1161. X    /** Display the given line on the screen, taking into account such
  1162. X        dumbness as wraparound and such.  If displaying this would put
  1163. X        us at the end of the screen, put out the "MORE" prompt and wait
  1164. X        for some input.   Return non-zero if the user terminates the
  1165. X        paging (e.g. 'i') or zero if we should continue. Also, 
  1166. X            this will pass back the value of any character the user types in 
  1167. X        at the prompt instead, if needed... (e.g. if it can't deal with
  1168. X        it at this point)
  1169. X    **/
  1170. X    
  1171. X    char *pending, footer[SLEN], display_buffer[SLEN], ch;
  1172. X    int formfeed, lines_more;
  1173. X
  1174. X#ifdef MMDF
  1175. X    if (strcmp(input_line, MSG_SEPERATOR) == 0)
  1176. X      strcpy(input_line," ");
  1177. X#endif /* MMDF */
  1178. X    pending = input_line;
  1179. X    CarriageReturn();
  1180. X
  1181. X    do {
  1182. X
  1183. X      /* while there is more space on the screen - leave prompt line free */
  1184. X      while(unfilled_lines > 0) {
  1185. X
  1186. X        /* display a screen's lineful of the input line
  1187. X         * and reset pending to point to remainder of input line */
  1188. X        formfeed = next_line(&pending, display_buffer, COLUMNS);
  1189. X
  1190. X        if(*display_buffer == '\0') {    /* no line to display */
  1191. X          if(!formfeed)    /* no "formfeed" to display
  1192. X                      * need more lines for screen */
  1193. X        return(FALSE);
  1194. X        } else
  1195. X          Write_to_screen(display_buffer, 0);
  1196. X
  1197. X        /* if formfeed, clear remainder of screen */
  1198. X        if(formfeed) {
  1199. X          CleartoEOS();
  1200. X          unfilled_lines=0;
  1201. X        }
  1202. X        else
  1203. X          unfilled_lines--;
  1204. X
  1205. X        /* if screen is not full (leave room for prompt)
  1206. X         * but we've used up input line, return */
  1207. X
  1208. X        if(unfilled_lines > 0 && *pending == '\0')
  1209. X          return(FALSE);    /* we need more lines to fill screen */
  1210. X
  1211. X        /* otherwise continue to display next part of input line */
  1212. X      }
  1213. X
  1214. X      /* screen is now full - prompt for user input */
  1215. X      lines_more = total_lines_to_display - lines_displayed;
  1216. X      sprintf(footer,
  1217. X          ( (user_level == 0) ?
  1218. X  " There %s %d line%s left (%d%%). Press <space> for more, or 'i' to return. "
  1219. X          : (user_level == 1) ?
  1220. X  " %s%d line%s more (%d%%). Press <space> for more, 'i' to return. "
  1221. X          :
  1222. X  " %s%d line%s more (you've seen %d%%) "),
  1223. X           (user_level == 0 ?
  1224. X             (lines_more == 1 ? "is" : "are") : ""),
  1225. X           lines_more, plural(lines_more),
  1226. X           (int)((100L * lines_displayed) / total_lines_to_display));
  1227. X      MoveCursor(LINES, 0);
  1228. X      StartBold();
  1229. X      Write_to_screen(footer, 0);
  1230. X      EndBold();
  1231. X
  1232. X      switch(ch = ReadCh()) {
  1233. X
  1234. X        case '\n':
  1235. X        case '\r':    /* scroll down a line */
  1236. X            unfilled_lines = 1;
  1237. X            ClearLine(LINES);
  1238. X            break;
  1239. X
  1240. X        case ' ':    /* scroll a screenful */
  1241. X            unfilled_lines = LINES;
  1242. X            if(clear_pages) {
  1243. X              ClearScreen();
  1244. X              MoveCursor(0,0);
  1245. X              CarriageReturn();
  1246. X
  1247. X              /* output title */
  1248. X              if(title_messages && filter) {
  1249. X                title_for_page(++pages_displayed);
  1250. X                unfilled_lines -= 2;
  1251. X              }
  1252. X            } else ClearLine(LINES);
  1253. X
  1254. X            /* and keep last line to be first line of next
  1255. X             * screenful unless we had a formfeed */
  1256. X            if(!formfeed) {
  1257. X              if(clear_pages)
  1258. X                Write_to_screen(display_buffer, 0);
  1259. X              unfilled_lines--;
  1260. X            }
  1261. X            break;
  1262. X
  1263. X        default:    return(ch);
  1264. X      }
  1265. X      CarriageReturn();
  1266. X    } while(*pending);
  1267. X    return(FALSE);
  1268. X}
  1269. X      
  1270. Xtitle_for_page(page)
  1271. Xint page;
  1272. X{
  1273. X    /** Output a nice title for the second thru last pages of the message 
  1274. X        we're currently reading. Note - this code is very similar to
  1275. X        that which produces the title for the first page, except that
  1276. X        page number replaces the date and the method by which it
  1277. X        gets to the screen **/
  1278. X
  1279. X    static char title1[SLEN], title2[SLEN];
  1280. X    char titlebuf[SLEN], title3[SLEN], who[SLEN];
  1281. X    static t1_len, t2_len;
  1282. X    register int padding, showing_to;
  1283. X
  1284. X    /* format those parts of the title that are constant for a message */
  1285. X    if(form_title) {
  1286. X
  1287. X      showing_to = tail_of(headers[current-1]->from, who,
  1288. X        headers[current-1]->to);
  1289. X
  1290. X      sprintf(title1, "%s %d/%d  ",
  1291. X          headers[current-1]->status & DELETED ? "[deleted]" :
  1292. X          headers[current-1]->status & FORM_LETTER ? "Form": "Message",
  1293. X          current, message_count);
  1294. X      t1_len = strlen(title1);
  1295. X      sprintf(title2, "%s %s", showing_to? "To" : "From", who);
  1296. X      t2_len = strlen(title2);
  1297. X    }
  1298. X    /* format those parts of the title that vary between pages of a mesg */
  1299. X    sprintf(title3, "  Page %d", page);
  1300. X
  1301. X    /* truncate or pad title2 portion on the right
  1302. X     * so that line fits exactly to the rightmost column */
  1303. X    padding = COLUMNS - (t1_len + t2_len + strlen(title3));
  1304. X
  1305. X    sprintf(titlebuf, "%s%-*.*s%s\n\r\n\r", title1, t2_len+padding,
  1306. X        t2_len+padding, title2, title3);
  1307. X        /* extra newline is to give a blank line after title */
  1308. X
  1309. X    Write_to_screen(titlebuf, 0);
  1310. X    form_title = 0;
  1311. X}
  1312. SHAR_EOF
  1313. chmod 0444 src/builtin.c || echo "restore of src/builtin.c fails"
  1314. echo "x - extracting src/calendar.c (Text)"
  1315. sed 's/^X//' << 'SHAR_EOF' > src/calendar.c &&
  1316. X
  1317. Xstatic char rcsid[] = "@(#)$Id: calendar.c,v 4.1 90/04/28 22:42:36 syd Exp $";
  1318. X
  1319. X/*******************************************************************************
  1320. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1321. X *
  1322. X *             Copyright (c) 1986, 1987 Dave Taylor
  1323. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1324. X *******************************************************************************
  1325. X * Bug reports, patches, comments, suggestions should be sent to:
  1326. X *
  1327. X *    Syd Weinstein, Elm Coordinator
  1328. X *    elm@DSI.COM            dsinc!elm
  1329. X *
  1330. X *******************************************************************************
  1331. X * $Log:    calendar.c,v $
  1332. X * Revision 4.1  90/04/28  22:42:36  syd
  1333. X * checkin of Elm 2.3 as of Release PL0
  1334. X * 
  1335. X *
  1336. X ******************************************************************************/
  1337. X
  1338. X/** This routine implements a rather snazzy idea suggested by Warren
  1339. X    Carithers of the Rochester Institute of Technology that allows
  1340. X    mail to contain entries formatted in a manner that will allow direct
  1341. X    copying into a users calendar program.
  1342. X
  1343. X    All lines in the current message beginning with "->", e.g.
  1344. X
  1345. X    -> Mon 04/21 1:00p meet with chairman candidate
  1346. X
  1347. X    get copied into the user's calendar file.
  1348. X
  1349. X**/
  1350. X
  1351. X#include "headers.h"
  1352. X
  1353. X#ifdef ENABLE_CALENDAR        /* if not defined, this will be an empty file */
  1354. X
  1355. X#include <errno.h>
  1356. X
  1357. Xextern int errno;
  1358. X
  1359. Xchar *error_name(), *error_description(), *strcpy();
  1360. X
  1361. Xscan_calendar()
  1362. X{
  1363. X    FILE *calendar;
  1364. X    int  count;
  1365. X
  1366. X    /* First step is to open the calendar file for appending... **/
  1367. X
  1368. X    if (can_open(calendar_file, "a") != 0) {
  1369. X      dprint(2, (debugfile,
  1370. X          "Error: wrong permissions to append to calendar %s\n",
  1371. X          calendar_file));
  1372. X      dprint(2, (debugfile, "** %s - %s **\n",
  1373. X          error_name(errno), error_description(errno)));
  1374. X      error1("Not able to append to file %s!", calendar_file);
  1375. X      return; 
  1376. X    }
  1377. X
  1378. X    save_file_stats(calendar_file);
  1379. X
  1380. X    if ((calendar = fopen(calendar_file,"a")) == NULL) {
  1381. X      dprint(2, (debugfile, 
  1382. X        "Error: couldn't append to calendar file %s (scan)\n", 
  1383. X        calendar_file));
  1384. X      dprint(2, (debugfile, "** %s - %s **\n",
  1385. X          error_name(errno), error_description(errno)));
  1386. X      error1("Couldn't append to file %s!", calendar_file);
  1387. X      return; 
  1388. X    }
  1389. X    
  1390. X    count = extract_info(calendar);
  1391. X
  1392. X    fclose(calendar);
  1393. X
  1394. X    restore_file_stats(calendar_file);
  1395. X
  1396. X    if (count > 0)
  1397. X      error2("%d entr%s saved in calendar file.", 
  1398. X         count, count > 1 ? "ies" : "y");
  1399. X    else 
  1400. X      error("No calendar entries found in that message.");
  1401. X
  1402. X    return;
  1403. X}
  1404. X
  1405. Xint
  1406. Xextract_info(save_to_fd)
  1407. XFILE *save_to_fd;
  1408. X{
  1409. X    /** Save the relevant parts of the current message to the given
  1410. X        calendar file.  The only parameter is an opened file
  1411. X        descriptor, positioned at the end of the existing file **/
  1412. X        
  1413. X    register int entries = 0, lines;
  1414. X    char buffer[SLEN], *cp, *is_cal_entry();
  1415. X
  1416. X        /** get to the first line of the message desired **/
  1417. X
  1418. X        if (fseek(mailfile, headers[current-1]->offset, 0) == -1) {
  1419. X             dprint(1,(debugfile, 
  1420. X        "ERROR: Attempt to seek %d bytes into file failed (%s)",
  1421. X        headers[current-1]->offset, "extract_info"));
  1422. X             error1("ELM [seek] failed trying to read %d bytes into file.",
  1423. X             headers[current-1]->offset);
  1424. X             return(0);
  1425. X        }
  1426. X
  1427. X        /* how many lines in message? */
  1428. X
  1429. X        lines = headers[current-1]->lines;
  1430. X
  1431. X        /* now while not EOF & still in message... scan it! */
  1432. X
  1433. X    while (lines) {
  1434. X
  1435. X          if(fgets(buffer, SLEN, mailfile) == NULL)
  1436. X        break;
  1437. X
  1438. X      if(buffer[strlen(buffer)-1] == '\n')
  1439. X        lines--;                    /* got a full line */
  1440. X
  1441. X      if((cp = is_cal_entry(buffer)) != NULL) {
  1442. X        entries++;
  1443. X        fprintf(save_to_fd,"%s", cp);
  1444. X      }
  1445. X
  1446. X    }
  1447. X    dprint(4,(debugfile,
  1448. X        "Got %d calender entr%s.\n", entries, entries > 1? "ies":"y"));
  1449. X
  1450. X    return(entries);
  1451. X}
  1452. X
  1453. Xchar *
  1454. Xis_cal_entry(string)
  1455. Xregister char *string;
  1456. X{
  1457. X    /* If string is of the form
  1458. X     *    ->{optional white space} {stuff}
  1459. X     * return a pointer to stuff, otherwise return NULL.
  1460. X     */
  1461. X    
  1462. X    if(strncmp(string, "->", 2) == 0) {
  1463. X      for(string +=2 ; whitespace(*string); string++)
  1464. X          ;
  1465. X      return(string);
  1466. X    }
  1467. X    return(NULL);
  1468. X}
  1469. X
  1470. X#endif
  1471. SHAR_EOF
  1472. chmod 0444 src/calendar.c || echo "restore of src/calendar.c fails"
  1473. echo "x - extracting src/conn_to.c (Text)"
  1474. sed 's/^X//' << 'SHAR_EOF' > src/conn_to.c &&
  1475. X
  1476. Xstatic char rcsid[] = "@(#)$Id: conn_to.c,v 4.1 90/04/28 22:42:37 syd Exp $";
  1477. X
  1478. X/*******************************************************************************
  1479. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1480. X *
  1481. X *             Copyright (c) 1986, 1987 Dave Taylor
  1482. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1483. X *******************************************************************************
  1484. X * Bug reports, patches, comments, suggestions should be sent to:
  1485. X *
  1486. X *    Syd Weinstein, Elm Coordinator
  1487. X *    elm@DSI.COM            dsinc!elm
  1488. X *
  1489. X *******************************************************************************
  1490. X * $Log:    conn_to.c,v $
  1491. X * Revision 4.1  90/04/28  22:42:37  syd
  1492. X * checkin of Elm 2.3 as of Release PL0
  1493. X * 
  1494. X *
  1495. X ******************************************************************************/
  1496. X
  1497. X/** This contains the routine(s) needed to have the Elm mailer figure
  1498. X    out what machines the current machine can talk to.
  1499. X    It will invoke uuname to a file, then read the file in!
  1500. X**/
  1501. X
  1502. X#include "headers.h"
  1503. X
  1504. Xchar *strcpy();
  1505. X
  1506. X#ifndef DONT_TOUCH_ADDRESSES
  1507. Xget_connections()
  1508. X{
  1509. X
  1510. X    /** get the direct connections that this machine has
  1511. X        using the uuname routine to get the names.
  1512. X    **/
  1513. X
  1514. X    FILE *fd;
  1515. X    char  buffer[SLEN], filename[SLEN];
  1516. X    struct lsys_rec *system_record, *previous_record;
  1517. X    int   loc_on_line;
  1518. X
  1519. X
  1520. X    if (! warnings) {        /* skip this - they don't care! */
  1521. X      talk_to_sys = NULL;
  1522. X      return;
  1523. X    }
  1524. X
  1525. X    if (strlen(uuname) == 0) {    /* skip this - no way to get connections */
  1526. X      warnings = NO;
  1527. X      talk_to_sys = NULL;
  1528. X      dprint(1, (debugfile, "No uuname - clearing warnings\n"));
  1529. X      error("Warning: no uuname command, clearing option warnings");
  1530. X      return;
  1531. X    }
  1532. X
  1533. X    sprintf(filename, "%s%s%d", temp_dir, temp_uuname, getpid());
  1534. X    sprintf(buffer,"%s > %s", uuname, filename);
  1535. X
  1536. X    if (system_call(buffer, SH, FALSE, FALSE) != 0) {
  1537. X      dprint(1, (debugfile, "Can't get uuname info - system() failed!\n"));
  1538. X      goto unable_to_get;
  1539. X    }
  1540. X    
  1541. X    if ((fd = fopen(filename, "r")) == NULL) {
  1542. X      dprint(1, (debugfile,
  1543. X        "Can't get uuname info - can't open file %s for reading\n",
  1544. X         filename));
  1545. X      goto unable_to_get;
  1546. X    }
  1547. X    
  1548. X    previous_record = NULL;
  1549. X
  1550. X    while (fgets(buffer, SLEN, fd) != NULL) {
  1551. X      no_ret(buffer);
  1552. X      if (previous_record == NULL) {
  1553. X        dprint(2, (debugfile, "uuname\tdirect connection to %s, ", buffer));
  1554. X        loc_on_line = 30 + strlen(buffer);
  1555. X        previous_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys);
  1556. X
  1557. X        strcpy(previous_record->name, buffer);
  1558. X        previous_record->next = NULL;
  1559. X        talk_to_sys = previous_record;
  1560. X      }
  1561. X      else {    /* don't have to check uniqueness - uuname does that! */
  1562. X        if (loc_on_line + strlen(buffer) > 80) {
  1563. X          dprint(2, (debugfile, "\n\t"));
  1564. X          loc_on_line = 8;
  1565. X        }
  1566. X        dprint(2, (debugfile, "%s, ", buffer));
  1567. X        loc_on_line += (strlen(buffer) + 2);
  1568. X        system_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys);
  1569. X      
  1570. X        strcpy(system_record->name, buffer);
  1571. X        system_record->next = NULL;
  1572. X        previous_record->next = system_record;
  1573. X        previous_record = system_record;
  1574. X      }
  1575. X    }
  1576. X
  1577. X    fclose(fd);
  1578. X
  1579. X    (void) unlink(filename);        /* kill da temp file!! */
  1580. X
  1581. X    dprint(2, (debugfile, "\n"));        /* for a nice format! Yeah! */
  1582. X
  1583. X    return;                    /* it all went okay... */
  1584. X
  1585. Xunable_to_get:
  1586. X    unlink(filename);    /* insurance */
  1587. X    error("Warning: couldn't figure out system connections...");
  1588. X    talk_to_sys = NULL;
  1589. X}
  1590. X#endif
  1591. SHAR_EOF
  1592. chmod 0444 src/conn_to.c || echo "restore of src/conn_to.c fails"
  1593. echo "x - extracting src/curses.c (Text)"
  1594. sed 's/^X//' << 'SHAR_EOF' > src/curses.c &&
  1595. X
  1596. Xstatic char rcsid[] = "@(#)$Id: curses.c,v 4.1 90/04/28 22:42:39 syd Exp $";
  1597. X
  1598. X/*******************************************************************************
  1599. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1600. X *
  1601. X *             Copyright (c) 1986, 1987 Dave Taylor
  1602. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1603. X *******************************************************************************
  1604. X * Bug reports, patches, comments, suggestions should be sent to:
  1605. X *
  1606. X *    Syd Weinstein, Elm Coordinator
  1607. X *    elm@DSI.COM            dsinc!elm
  1608. X *
  1609. X *******************************************************************************
  1610. X * $Log:    curses.c,v $
  1611. X * Revision 4.1  90/04/28  22:42:39  syd
  1612. X * checkin of Elm 2.3 as of Release PL0
  1613. X * 
  1614. X *
  1615. X ******************************************************************************/
  1616. X
  1617. X/**  This library gives programs the ability to easily access the
  1618. X     termcap information and write screen oriented and raw input
  1619. X     programs.  The routines can be called as needed, except that
  1620. X     to use the cursor / screen routines there must be a call to
  1621. X     InitScreen() first.  The 'Raw' input routine can be used
  1622. X     independently, however.
  1623. X
  1624. X**/
  1625. X
  1626. X/** NOTE THE ADDITION OF: the #ifndef ELM stuff around routines that
  1627. X    we don't use.  This is for code size and compile time speed...
  1628. X**/
  1629. X
  1630. X#include "headers.h"
  1631. X
  1632. X#ifdef TERMIOS
  1633. X#  include <termios.h>
  1634. X# if __convex__
  1635. X#  include <sys/ioctl.h>    /* non-standard, for TIOCGWINSZ */
  1636. X# endif
  1637. X#else
  1638. X# ifdef TERMIO
  1639. X#  include <termio.h>
  1640. X# else
  1641. X#  include <sgtty.h>
  1642. X# endif
  1643. X#endif
  1644. X
  1645. X#include <ctype.h>
  1646. X
  1647. X#ifdef PTEM
  1648. X#  include <sys/types.h>
  1649. X#  include <sys/stream.h>
  1650. X#  include <sys/ptem.h>
  1651. X#endif
  1652. X
  1653. X#ifdef BSD
  1654. X#undef tolower
  1655. X#endif
  1656. X
  1657. X#define TTYIN    0
  1658. X
  1659. X#ifdef SHORTNAMES
  1660. X# define _clearinverse    _clrinv
  1661. X# define _cleartoeoln    _clrtoeoln
  1662. X# define _cleartoeos    _clr2eos
  1663. X# define _transmit_off    xmit_off
  1664. X# define _transmit_on    xmit_on
  1665. X#endif
  1666. X
  1667. X#ifdef TERMIOS
  1668. Xstruct termios _raw_tty,
  1669. X           _original_tty;
  1670. X#define    ttgetattr(fd,where)    tcgetattr((fd),(where))
  1671. X#define    ttsetattr(fd,where)    tcsetattr((fd),TCSADRAIN,(where))
  1672. X#else    /*TERMIOS*/
  1673. X# ifdef TERMIO
  1674. Xstruct termio _raw_tty, 
  1675. X              _original_tty;
  1676. X#define    ttgetattr(fd,where)    ioctl((fd),TCGETA,(where))
  1677. X#define    ttsetattr(fd,where)    ioctl((fd),TCSETAW,(where))
  1678. X# else
  1679. Xstruct sgttyb _raw_tty,
  1680. X          _original_tty;
  1681. X#define    ttgetattr(fd,where)    ioctl((fd),TIOCGETP,(where))
  1682. X#define    ttsetattr(fd,where)    ioctl((fd),TIOCSETP,(where))
  1683. X# endif    /*TERMIO*/
  1684. X#endif    /*TERMIOS*/
  1685. X
  1686. Xstatic int _inraw = 0;                  /* are we IN rawmode?    */
  1687. X
  1688. X#define DEFAULT_LINES_ON_TERMINAL    24
  1689. X#define DEFAULT_COLUMNS_ON_TERMINAL    80
  1690. X
  1691. Xstatic int _memory_locked = 0;        /* are we IN memlock??   */
  1692. Xstatic int _line  = -1,            /* initialize to "trash" */
  1693. X           _col   = -1;
  1694. X
  1695. Xstatic int _intransmit;            /* are we transmitting keys? */
  1696. X
  1697. Xstatic
  1698. Xchar *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
  1699. X     *_setbold, *_clearbold, *_setunderline, *_clearunderline, 
  1700. X     *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse,
  1701. X     *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off,
  1702. X     *_set_memlock, *_clear_memlock;
  1703. X
  1704. Xstatic int _lines, _columns, _automargin, _eatnewlineglitch;
  1705. Xint tabspacing;
  1706. X
  1707. Xstatic char _terminal[1024];              /* Storage for terminal entry */
  1708. Xstatic char _capabilities[1024];           /* String for cursor motion */
  1709. X
  1710. Xstatic char *ptr = _capabilities;    /* for buffering         */
  1711. X
  1712. Xint    outchar();            /* char output for tputs */
  1713. Xchar  *tgetstr(),                    /* Get termcap capability */
  1714. X      *tgoto();                /* and the goto stuff    */
  1715. X
  1716. XInitScreen()
  1717. X{
  1718. X    /* Set up all this fun stuff: returns zero if all okay, or;
  1719. X        -1 indicating no terminal name associated with this shell,
  1720. X        -2..-n  No termcap for this terminal type known
  1721. X   */
  1722. X
  1723. X    int  tgetent(),      /* get termcap entry */
  1724. X         err;
  1725. X    char termname[40];
  1726. X    char *strcpy(), *getenv();
  1727. X    
  1728. X    if (getenv("TERM") == NULL) return(-1);
  1729. SHAR_EOF
  1730. echo "End of part 12"
  1731. echo "File src/curses.c is continued in part 13"
  1732. echo "13" > s2_seq_.tmp
  1733. exit 0
  1734.  
  1735. exit 0 # Just in case...
  1736.