home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume19 / nn / part14 < prev    next >
Encoding:
Internet Message Format  |  1989-06-22  |  48.8 KB

  1. Subject:  v19i075:  NN, a Usenet news reader, Part14/15
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: storm@texas.dk (Kim F. Storm)
  7. Posting-number: Volume 19, Issue 75
  8. Archive-name: nn/part14
  9.  
  10. #!/bin/sh
  11. # this is part 14 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file s-tower32.h continued
  14. #
  15. CurArch=14
  16. if test ! -r s2_seq_.tmp
  17. then echo "Please unpack part 1 first!"
  18.      exit 1; fi
  19. ( read Scheck
  20.   if test "$Scheck" != $CurArch
  21.   then echo "Please unpack part $Scheck next!"
  22.        exit 1;
  23.   else exit 0; fi
  24. ) < s2_seq_.tmp || exit 1
  25. echo "x - Continuing file s-tower32.h"
  26. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> s-tower32.h
  27. X */
  28. X
  29. X/* #define    HAVE_MKDIR            /* */
  30. X
  31. X/*
  32. X *    Define HAVE_GETHOSTNAME if your system provides a BSD like 
  33. X *    gethostname routine.
  34. X *    Otherwise, define HAVE_UNAME if uname() is avaiable.
  35. X *    As a final resort, define HOSTNAME to the name of your system.
  36. X */
  37. X
  38. X#define    HAVE_UNAME            /* System V */
  39. X
  40. X/*
  41. X *    Define DETATCH_TERMINAL to be a command sequence which 
  42. X *    will detatch a process from the control terminal
  43. X *    Also include files needed to perform this HERE.
  44. X *    If not possible, just define it (empty)
  45. X */
  46. X
  47. X#define    DETATCH_TERMINAL setpgrp();    /* System V */
  48. X
  49. X/* 
  50. X *    Specify where the Bourne Shell is.
  51. X */
  52. X
  53. X#define SHELL        "/bin/sh"
  54. X
  55. X/*
  56. X *    Specify the default mailer to be invoked by nnmail
  57. X */
  58. X
  59. X#define    MAILX        "/usr/bin/mailx"    /* SV */
  60. X
  61. X/*
  62. X *    Specify the default pager & options.
  63. X */
  64. X
  65. X#define    PAGER        "pg -n -s"
  66. X
  67. X/*
  68. X *    Specify the default print command and options.
  69. X */
  70. X
  71. X#define    PRINTER        "lp -s"
  72. X
  73. X
  74. X/*
  75. X *    Define the maximum length of any pathname that may occur
  76. X */
  77. X
  78. X#define    FILENAME     128
  79. NO_NEWS_IS_GOOD_NEWS
  80. echo "File s-tower32.h is complete"
  81. chmod 0644 s-tower32.h || echo "restore of s-tower32.h fails"
  82. set `wc -c s-tower32.h`;Sum=$1
  83. if test "$Sum" != "2624"
  84. then echo original size 2624, current size $Sum;fi
  85. echo "x - extracting s-usg3-1.h (Text)"
  86. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > s-usg3-1.h &&
  87. X/*
  88. X *    This version is for System V Release 3.1
  89. X */
  90. X
  91. X
  92. X/*
  93. X *    Include header files containing the following definitions:
  94. X *
  95. X *         off_t, time_t, struct stat
  96. X */
  97. X
  98. X#include <sys/types.h>
  99. X#include <sys/stat.h>
  100. X
  101. X/*
  102. X *    Define if your system has system V like ioctls
  103. X */
  104. X
  105. X#define    HAVE_TERMIO            /* */
  106. X
  107. X/*
  108. X *    Define to use terminfo database.
  109. X *    Otherwise, termcap is used
  110. X */
  111. X
  112. X#define    USE_TERMINFO            /* */
  113. X
  114. X/*
  115. X *    Specify the library containing the termcap/terminfo access routines.
  116. X *    Notice:  nn does not use curses.
  117. X *    Notice:  You must also specify whether termcap or terminfo is
  118. X *         used when you edit config.h (see below).
  119. X */
  120. X
  121. X#define    TERMLIB -lcurses
  122. X
  123. X/*
  124. X *    Define HAVE_STRCHR if strchr() and strrchr() are available
  125. X */
  126. X
  127. X#define HAVE_STRCHR            /* */
  128. X
  129. X/*
  130. X *    Define if a signal handler has type void (see signal.h)
  131. X */
  132. X
  133. X#define    SIGNAL_HANDLERS_ARE_VOID    /* */
  134. X
  135. X/*
  136. X *    Define if signals must be set again after they are caught
  137. X */
  138. X
  139. X#define    RESET_SIGNAL_WHEN_CAUGHT    /* */
  140. X
  141. X/*
  142. X *    Define MICRO_ALARM to timeout in 0.1 seconds if possible
  143. X */
  144. X
  145. X#define MICRO_ALARM()    alarm(1)    /* System V */
  146. X
  147. X/*
  148. X *    Define if your system has BSD like job control (SIGTSTP works)
  149. X */
  150. X
  151. X/* #define HAVE_JOBCONTROL            /* */
  152. X
  153. X/*
  154. X *    Define if your system provides the "directory(3X)" access routines
  155. X *
  156. X *    If true, include the header file(s) required by the package below
  157. X *    (remember that <sys/types.h> or equivalent is included above)
  158. X *    Also typedef Direntry to the proper struct type.
  159. X */
  160. X
  161. X#define    HAVE_DIRECTORY            /* */
  162. X
  163. X#include <dirent.h>            /* System V */
  164. X
  165. Xtypedef struct dirent Direntry;        /* System V */
  166. X
  167. X/*
  168. X *    Define if your system has a mkdir() library routine
  169. X */
  170. X
  171. X#define    HAVE_MKDIR            /* */
  172. X
  173. X/*
  174. X *    Define HAVE_GETHOSTNAME if your system provides a BSD like 
  175. X *    gethostname routine.
  176. X *    Otherwise, define HAVE_UNAME if uname() is avaiable.
  177. X *    As a final resort, define HOSTNAME to the name of your system.
  178. X */
  179. X
  180. X#define    HAVE_UNAME            /* System V */
  181. X
  182. X/*
  183. X *    Define DETATCH_TERMINAL to be a command sequence which 
  184. X *    will detatch a process from the control terminal
  185. X *    Also include files needed to perform this HERE.
  186. X *    If not possible, just define it (empty)
  187. X */
  188. X
  189. X#define    DETATCH_TERMINAL setpgrp();    /* System V */
  190. X
  191. X/* 
  192. X *    Specify where the Bourne Shell is.
  193. X */
  194. X
  195. X#define SHELL        "/bin/sh"
  196. X
  197. X/*
  198. X *    Specify the default mailer to be invoked by nnmail
  199. X */
  200. X
  201. X#define    MAILX        "/usr/bin/mailx"    /* SV */
  202. X
  203. X/*
  204. X *    Specify the default pager & options.
  205. X */
  206. X
  207. X#define    PAGER        "pg -n -s"
  208. X
  209. X/*
  210. X *    Specify the default print command and options.
  211. X */
  212. X
  213. X#define    PRINTER        "lp -s"
  214. X
  215. X
  216. X/*
  217. X *    Define the maximum length of any pathname that may occur
  218. X */
  219. X
  220. X#define    FILENAME     128
  221. NO_NEWS_IS_GOOD_NEWS
  222. chmod 0644 s-usg3-1.h || echo "restore of s-usg3-1.h fails"
  223. set `wc -c s-usg3-1.h`;Sum=$1
  224. if test "$Sum" != "2611"
  225. then echo original size 2611, current size $Sum;fi
  226. echo "x - extracting save.c (Text)"
  227. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > save.c &&
  228. X#include <signal.h>
  229. X#include <errno.h>
  230. X#include "config.h"
  231. X#include "term.h"
  232. X#include "keymap.h"
  233. X#include "news.h"
  234. X
  235. X/*
  236. X * save (or print) articles
  237. X */
  238. X
  239. X/* #define PAGED_OUTPUT        /* does not work yet!! */
  240. X
  241. Xexport char *default_save_file = "+$F";
  242. Xexport int  use_mail_folders = 0;
  243. Xexport int  save_report = 1;
  244. Xexport int  quick_save = 0;
  245. Xexport int  conf_append = 0;
  246. X
  247. Xexport char *save_counter_format = "%d";    /* format of save counter */
  248. X
  249. Xexport char printer[FILENAME] = PRINTER;    /* lp -s -ol        */
  250. Xexport char *patch_cmd = "patch";
  251. X
  252. Xextern int file_completion();
  253. X
  254. Ximport char *temp_file;
  255. X
  256. Xstatic int save_mode;
  257. Xstatic char *unshar_cmd;
  258. X
  259. X#define    HEADER_HANDLING    0x0f    /* what should we do with the header */
  260. X
  261. X#define NO_HEADER    0    /* save without a header */
  262. X#define    FULL_HEADER    1    /* save with full header */
  263. X#define SHORT_HEADER    2    /* save with partial header */
  264. X#define    SHORT_HEADER_DG    3    /* save with partial header (digest) */
  265. X
  266. X
  267. X#define    SEPARATE_FILES    0x0100    /* save as separate files */
  268. X#define UNIQUE_FILES    0x0200    /* save in unique files */
  269. X#define    FILE_IS_NEW    0x0400    /* this is a new file */
  270. X#define APPEND_ARTNUM    0x0800    /* append article number to file name */
  271. X#define    IS_PIPE        0x1000    /* output is on pipe */
  272. X#define    DO_UNSHAR    0x2000    /* unshar article (or patch) */
  273. X#define    DO_PATCH    0x4000    /* patch article */
  274. X
  275. X/* open modes for open_news_article for the various HEADER_HANDLINGs */
  276. X
  277. Xstatic int open_mode[] = {
  278. X    SKIP_HEADER,
  279. X    0,
  280. X    FILL_NEWS_HEADER | SKIP_HEADER,
  281. X    FILL_DIGEST_HEADER | SKIP_HEADER
  282. X};
  283. X
  284. Xstatic FILE *save_file;            /* output stream for saved files */
  285. Xstatic char *save_name;            /* save file name */
  286. X
  287. X#ifdef PAGED_OUTPUT
  288. Xstatic FILE *pager_stream = NULL;    /* unshar/patch output stream */
  289. Xstatic char pager_redir[40];
  290. X#endif
  291. X
  292. Xstatic int counter_index;        /* index into save_name of '*' */
  293. Xstatic int uniq_counter;        /* separate files counter */
  294. X
  295. Xstatic char last_dir[FILENAME] = "";
  296. X
  297. Xchar *init_save(command, mode_textp)
  298. Xchar command;
  299. Xchar **mode_textp;
  300. X{
  301. X    char *mode_text;
  302. X    static char last_input[FILENAME] = "";
  303. X    static char name_buf[512];    /* buffer for file name & command expansion */
  304. X    char *start, *last, *np;
  305. X    char *ckdir_path();
  306. X
  307. X    uniq_counter = 0;
  308. X
  309. X    switch (command) {
  310. X
  311. X     case K_SAVE_FULL_HEADER:
  312. X    save_mode = FULL_HEADER;
  313. X    mode_text = "Save";
  314. X    goto cont_save;
  315. X
  316. X     case K_SAVE_SHORT_HEADER:
  317. X    save_mode = SHORT_HEADER;
  318. X    mode_text = "Output";
  319. X    goto cont_save;
  320. X    
  321. X     case K_SAVE_NO_HEADER:
  322. X    save_mode = NO_HEADER;
  323. X    mode_text = "Write";
  324. X
  325. X     cont_save:
  326. X    if (quick_save && (current_group->group_flag & G_FOLDER) == 0) {
  327. X        if (current_group->save_file)
  328. X        save_name = current_group->save_file;
  329. X        else
  330. X        save_name = default_save_file;
  331. X        strcpy(last_input, save_name);
  332. X        save_name = last_input;
  333. X    } else {
  334. X        prompt("\1%s on\1 (+~|) ", mode_text);
  335. X
  336. X        save_name = get_s(last_input, current_group->save_file, NONE, 
  337. X              file_completion);
  338. X        if (save_name == NULL || *save_name == NUL) return NULL;
  339. X
  340. X        if (save_name[1] == NUL && save_name[0] == '+')
  341. X        save_name = default_save_file;
  342. X        else
  343. X        if (current_group->save_file == NULL ||
  344. X            strcmp(save_name, current_group->save_file))
  345. X            strcpy(last_input, save_name);
  346. X    }
  347. X    
  348. X    if (*save_name == '|') {
  349. X        mode_text = "Pipe";
  350. X        save_name++;
  351. X        save_mode |= IS_PIPE;
  352. X        if (*save_name == '|' || *save_name == '*') {
  353. X        save_mode |= SEPARATE_FILES;
  354. X        save_name++;
  355. X        }
  356. X    } else {
  357. X        counter_index = strlen(save_name) - 1;
  358. X        np = save_name + counter_index;
  359. X        if (*np == '*')
  360. X        save_mode |= SEPARATE_FILES | UNIQUE_FILES;
  361. X        else
  362. X        if (counter_index > 0 && strcmp(--np, "$N") == 0) {
  363. X            if (current_group->group_flag & G_FOLDER) {
  364. X            msg("$N is not defined in a folder");
  365. X            return NULL;
  366. X            }
  367. X            counter_index--;
  368. X            strcpy(np, "*");
  369. X            save_mode |= SEPARATE_FILES | APPEND_ARTNUM;
  370. X        }
  371. X    }
  372. X    break;
  373. X
  374. X     case K_PATCH:
  375. X    save_mode = NO_HEADER | SEPARATE_FILES | DO_UNSHAR | DO_PATCH;
  376. X    mode_text = "Patch";
  377. X    unshar_cmd = patch_cmd;
  378. X    goto patch1;
  379. X    
  380. X     case K_UNSHAR:
  381. X    save_mode = NO_HEADER | SEPARATE_FILES | DO_UNSHAR;
  382. X    mode_text = "Unshar";
  383. X    unshar_cmd = SHELL;
  384. X    
  385. X     patch1:
  386. X    prompt("\1%s Directory:\1 ", mode_text);
  387. X    save_name = get_s(last_dir, NONE, NONE, file_completion);
  388. X    if (save_name == NULL) return NULL;
  389. X    if (*save_name == NUL) 
  390. X        save_name = NULL;
  391. X    else {
  392. X        strcpy(last_dir, save_name);
  393. X    }
  394. X    
  395. X    break;
  396. X    
  397. X     case K_PRINT:
  398. X
  399. X    save_mode = SHORT_HEADER | IS_PIPE;
  400. X
  401. X    prompt("\1Print command:\1 ");
  402. X    save_name = get_s(NONE, printer, NONE, NO_COMPLETION);
  403. X    if (save_name == NULL || *save_name == NUL) return NULL;
  404. X
  405. X    strcpy(printer, save_name);
  406. X    mode_text = "Print";
  407. X    break;
  408. X
  409. X     default:
  410. X    msg("Illegal save command: %d", command);
  411. X    return NULL;
  412. X    }
  413. X
  414. X    if (save_name) {
  415. X    
  416. X    if (save_mode & IS_PIPE || *save_name == '+' || *save_name == '~') {
  417. X        if (!expand_file_name(name_buf, save_name))
  418. X        return NULL;
  419. X        if (save_mode & SEPARATE_FILES)
  420. X        counter_index = strlen(name_buf) - 1;
  421. X    } else
  422. X        strcpy(name_buf, save_name);
  423. X    
  424. X    save_name = name_buf;
  425. X    
  426. X    if (!(save_mode & IS_PIPE)) {
  427. X        if (file_exist(save_name, (save_mode & DO_UNSHAR) ? "wd" : "wf")) {
  428. X        if (conf_append && (save_mode & DO_UNSHAR) == 0) {
  429. X            printf("\rAppend to: %s ? ", save_name);
  430. X            clrline();
  431. X            if (!yes(0)) return NULL;
  432. X        }
  433. X        } else {
  434. X        if (errno != ENOENT) {
  435. X            msg("Cannot access %s", save_name);
  436. X            return NULL;
  437. X        }
  438. X
  439. X        if (save_mode & DO_UNSHAR) {
  440. X            strcat(save_name, "/");
  441. X        }
  442. X
  443. X        start = ckdir_path(save_name);
  444. X        if (start == NULL) {
  445. X            msg("No permission");
  446. X            return NULL;
  447. X        }
  448. X        
  449. X        last = strrchr(start, '/');
  450. X        /* last != NULL => non-existing directories */
  451. X        
  452. X        if (!(save_mode & SEPARATE_FILES) || last) {
  453. X            printf("\rCreate ");
  454. X            for (np = save_name; *np; np++) {
  455. X            if (np == start) putchar('\"');
  456. X            putchar(*np);
  457. X            if ((save_mode & SEPARATE_FILES) && np == last) break;
  458. X            }
  459. X            printf("\" ?");
  460. X            clrline();
  461. X            if (yes(last != NULL) <= 0) return NULL;
  462. X        }
  463. X        
  464. X        if (last && !mkdirs_in_path(save_name, start)) 
  465. X            return NULL;
  466. X        }
  467. X    }    
  468. X    }
  469. X    
  470. X    if (mode_textp) *mode_textp = mode_text;
  471. X
  472. X    save_mode |= FILE_IS_NEW;    /* so save() will open it */
  473. X
  474. X#ifdef PAGED_OUTPUT
  475. X    if (save_mode & DO_UNSHAR) {
  476. X    int was_raw = no_raw();
  477. X    pager_stream = popen(pager, "w");
  478. X    if (was_raw) raw();
  479. X    
  480. X    if (pager_stream == NULL) {
  481. X        pager_redir[0] = NUL;
  482. X        msg("Warning: Pager '%s' not found");
  483. X    } else
  484. X        sprintf(pager_redir, " 1>&%d 2>&1 ; ", fileno(pager_stream));
  485. X    system("fdcheck");
  486. X    }
  487. X#endif
  488. X    
  489. X    return save_name;
  490. X}
  491. X
  492. X
  493. Xsave(ah)
  494. Xarticle_header *ah;
  495. X{
  496. X    register FILE *art;
  497. X    register c, lcount, mode;
  498. X    news_header_buffer hdrbuf;
  499. X    int was_raw = 0;
  500. X    char copybuf[1024];
  501. X
  502. X    if (ah->a_group) init_group(ah->a_group);
  503. X    
  504. X    mode = save_mode & HEADER_HANDLING;
  505. X    if (mode == SHORT_HEADER && ah->flag & A_DIGEST) 
  506. X    mode = SHORT_HEADER_DG;
  507. X    
  508. X    art = open_news_article(ah, open_mode[mode], hdrbuf, (char *)NULL);
  509. X    if (art == NULL) {
  510. X    msg("Cannot read %s", group_path_name);
  511. X    return 0;
  512. X    }
  513. X
  514. X    if (save_mode & UNIQUE_FILES) {
  515. X    do {
  516. X        uniq_counter++;
  517. X        sprintf(save_name + counter_index, 
  518. X            save_counter_format, uniq_counter);
  519. X    } while (file_exist(save_name, (char *)NULL));
  520. X
  521. X    save_mode |= FILE_IS_NEW;
  522. X    } else
  523. X    if (save_mode & APPEND_ARTNUM)
  524. X        sprintf(save_name + counter_index, "%d", ah->a_number);
  525. X        
  526. X    if (save_mode & FILE_IS_NEW) 
  527. X    if (save_mode & IS_PIPE) {
  528. X        if ((save_file = popen(save_name, "w")) == NULL) {
  529. X        msg("Cannot pipe to %s", save_name);
  530. X        fclose(art);
  531. X        return 0;
  532. X        }
  533. X    } else
  534. X    if (save_mode & DO_UNSHAR) {
  535. X        if ((save_mode & DO_PATCH) == 0 && !unshar_position(art)) {
  536. X        fclose(art);
  537. X        return 0;
  538. X        }
  539. X        was_raw = no_raw();
  540. X        if (save_name) 
  541. X#ifdef PAGED_OUTPUT
  542. X        sprintf(copybuf, "cd %s && %s %s", save_name, unshar_cmd, pager_redir);
  543. X        else
  544. X        sprintf(copybuf, "%s %s", unshar_cmd, pager_redir);
  545. X#else
  546. X        sprintf(copybuf, 
  547. X            "cd %s && %s | tee %s 2>&1 ; cat %s >> %s.Result ; rm %s",
  548. X            save_name != NULL ? save_name : ".", unshar_cmd,
  549. X            temp_file, temp_file, 
  550. X            (save_mode & DO_PATCH) ? "Patch" : "Unshar",
  551. X            temp_file);
  552. X#endif
  553. X        save_file = popen(copybuf, "w");
  554. X        if (save_file == NULL) {
  555. X        msg("Cannot exec: '%s'", copybuf);
  556. X        if (was_raw) raw();
  557. X        fclose(art);
  558. X        return 0;
  559. X        }
  560. X#ifdef PAGED_OUTPUT
  561. X        fprintf(pager_stream, "\r\n%s %s\r\n", 
  562. X            save_mode & DO_PATCH ? "PATCHING FROM" : "UNPACKING",
  563. X            ah->subject ? ah->subject : "ARTICLE");
  564. X        fflush(pager_stream);
  565. X#else
  566. X        printf("\r\n%s %s\r\n", 
  567. X           save_mode & DO_PATCH ? "PATCHING FROM" : "UNPACKING",
  568. X           ah->subject ? ah->subject : "ARTICLE"); fl;
  569. X#endif
  570. X    } else {
  571. X        if ((save_file = open_file(save_name, OPEN_APPEND)) == NULL) {
  572. X        msg("Cannot write %s", save_name);
  573. X        fclose(art);
  574. X        return 0;
  575. X        }
  576. X        if (ftell(save_file) != (off_t)0)
  577. X        save_mode &= ~FILE_IS_NEW;
  578. X    }
  579. X    
  580. X    clrline();
  581. X    s_pipe = 0;
  582. X
  583. X    if (use_mail_folders && mode != NO_HEADER) {
  584. X    time_t now;
  585. X    char *ctime();
  586. X    
  587. X    time(&now);
  588. X    fprintf(save_file, "From %s %s", 
  589. X        current_group->group_name, ctime(&now));
  590. X    }
  591. X
  592. X    if (mode == FULL_HEADER) {
  593. X    int cnt = ah->fpos - ah->hpos;
  594. X    while (--cnt >= 0) {
  595. X        if ((c = getc(art)) == EOF) break;
  596. X        putc(c, save_file);
  597. X    }
  598. X    } else
  599. X    if (mode == SHORT_HEADER) {
  600. X    if (news.ng_from)
  601. X        fprintf(save_file, "From: %s\n", news.ng_from);
  602. X    if (news.ng_date)
  603. X        fprintf(save_file, "Date: %s\n", news.ng_date);
  604. X    if (news.ng_subj)
  605. X        fprintf(save_file, "Subject: %s\n", news.ng_subj);
  606. X    fputc(NL, save_file);
  607. X    } else
  608. X    if (mode == SHORT_HEADER_DG) {
  609. X    if (digest.dg_from)
  610. X        fprintf(save_file, "From: %s\n", digest.dg_from);
  611. X    if (digest.dg_date)
  612. X        fprintf(save_file, "Date: %s\n", digest.dg_date);
  613. X    if (digest.dg_subj)
  614. X        fprintf(save_file, "Subject: %s\n", digest.dg_subj);
  615. X    fputc(NL, save_file);
  616. X    }
  617. X
  618. X    fflush(save_file);
  619. X    if (s_pipe) goto broken_pipe;
  620. X
  621. X    mode = mode != NO_HEADER && (save_mode & (IS_PIPE | DO_UNSHAR)) == 0;
  622. X    
  623. X    lcount = 0; 
  624. X    while (ftell(art) < ah->lpos && fgets(copybuf, 512, art)) {
  625. X    lcount++;
  626. X    if (mode && is_header_line(copybuf))
  627. X        fputc('~', save_file);
  628. X    fputs(copybuf, save_file);
  629. X    if (s_pipe) goto broken_pipe;
  630. X    }
  631. X    
  632. X    if (mode) {
  633. X    putc(NL, save_file);
  634. X    lcount++;
  635. X    }
  636. X
  637. Xbroken_pipe:    
  638. X    fclose(art);
  639. X
  640. X    if (save_mode & DO_UNSHAR) {
  641. X    pclose(save_file);
  642. X    save_file = NULL;
  643. X    } else {
  644. X    if (s_pipe)
  645. X        msg("Command did not read complete article!");
  646. X    else
  647. X        if (save_report)
  648. X        msg((save_mode & IS_PIPE)     ? "%s: %d lines piped" :
  649. X        (save_mode & FILE_IS_NEW) ? "%s created: %d lines written" :
  650. X        "%s: %d lines appended", save_name, lcount);
  651. X    
  652. X    if (s_pipe || (save_mode & SEPARATE_FILES))
  653. X        end_save();
  654. X    else
  655. X        save_mode &= ~FILE_IS_NEW;
  656. X    }
  657. X    
  658. X#ifdef MAIL_READING
  659. X    if (mail_auto_delete && (save_mode & IS_PIPE) == 0)
  660. X    if (current_group->group_flag & G_MAILBOX)
  661. X        if ((ah->flag & A_CANCEL) == 0) 
  662. X        fcancel(ah);
  663. X#endif    
  664. X    if (was_raw) raw();    
  665. X
  666. X    return !s_pipe || (save_mode & SEPARATE_FILES);
  667. X}
  668. X
  669. X
  670. Xend_save()
  671. X{
  672. X    if (save_file) {
  673. X    if (save_mode & (IS_PIPE | DO_UNSHAR))
  674. X        pclose(save_file);
  675. X    else
  676. X        fclose(save_file);
  677. X    save_file = NULL;
  678. X    }
  679. X    
  680. X#ifdef PAGED_OUTPUT
  681. X    if (pager_stream != NULL) {
  682. X    pclose(pager_stream);
  683. X    pager_stream = NULL;
  684. X    }
  685. X#else
  686. X    if (save_mode & DO_UNSHAR) {
  687. X    import char *delayed_msg;
  688. X    
  689. X    delayed_msg = (save_mode & DO_PATCH) ?
  690. X        "Output is saved in Patch.Result" :
  691. X        "Output is saved in Unshar.Result";
  692. X    }
  693. X#endif
  694. X}
  695. X
  696. X
  697. Xchar *run_mkdir(dir, name_buf)
  698. Xchar *dir, *name_buf;
  699. X{
  700. X    if (dir == NULL) {
  701. X    prompt("\1Directory: \1");
  702. X    dir = get_s(last_dir, NONE, NONE, file_completion);
  703. X    if (dir == NULL || *dir == NUL) return NULL;
  704. X    strcpy(last_dir, dir);
  705. X    }
  706. X    
  707. X    if (*dir == '+' || *dir == '~') {
  708. X    if (!expand_file_name(name_buf, dir))
  709. X        return NULL;
  710. X    dir = name_buf;
  711. X    }
  712. X    
  713. X    if (file_exist(dir, (char *)NULL)) {
  714. X    msg("Directory %s already exists", dir);
  715. X    return NULL;
  716. X    }
  717. X    
  718. X    if (mkdir(dir, 0755)) {
  719. X    msg("Cannot make %s", dir);
  720. X    return NULL;
  721. X    }
  722. X    
  723. X    return dir;
  724. X}
  725. X
  726. X
  727. Xchange_dir(dir, in_init)
  728. Xchar *dir;
  729. Xint in_init;
  730. X{
  731. X    char dir_buf[FILENAME];
  732. X        
  733. X    if (dir == NULL) {
  734. X    prompt("\1Directory: \1");
  735. X    dir = get_s(last_dir, NONE, NONE, file_completion);
  736. X    }
  737. X
  738. X    if (dir == NULL || *dir == NUL) return 0;
  739. X    
  740. X    strcpy(last_dir, dir);
  741. X        
  742. X    if (*dir == '+' || *dir == '~') {
  743. X    if (!expand_file_name(dir_buf, dir)) return in_init;
  744. X    dir = dir_buf;
  745. X    }
  746. X
  747. X    if (chdir(dir) == 0) {
  748. X    if (!in_init) msg("Directory: %s", dir);
  749. X    return 0;
  750. X    }
  751. X    
  752. X    if (in_init) return 1;
  753. X    
  754. X    if (errno == EACCES)
  755. X    msg("Cannot access directory %s", dir);
  756. X    else {
  757. X    /* should ask and create directory here */
  758. X    msg("Directory not found: %s", dir);
  759. X    }
  760. X    
  761. X    return 0;
  762. X}
  763. X
  764. X
  765. X
  766. X/*
  767. X * return pointer to first path name component, that does not exist
  768. X */
  769. X
  770. Xstatic char *ckdir_path(name)
  771. Xchar *name;
  772. X{
  773. X    char *slash;
  774. X    char *component;
  775. X    
  776. X    component = name;
  777. X    
  778. X    while (slash = strchr(component, '/')) {
  779. X    if (slash == component) {
  780. X        /*  ...//...  */
  781. X        component++;
  782. X        continue;
  783. X    }
  784. X    *slash = NUL;
  785. X    if (file_exist(name, "drx")) {
  786. X        *slash++ = '/';
  787. X        component = slash;
  788. X        continue;
  789. X    }
  790. X    if (file_exist(name, (char *)NULL)) {
  791. X        *slash = '/';
  792. X        return NULL;
  793. X    }
  794. X    *slash = '/';
  795. X    break;
  796. X    }
  797. X    return component;
  798. X}
  799. X
  800. X/*
  801. X * create directories in path name, starting from start
  802. X */
  803. X
  804. Xstatic mkdirs_in_path(name, start)
  805. Xchar *name, *start;
  806. X{
  807. X    char *slash;
  808. X    char *component;
  809. X    
  810. X    component = start;
  811. X    
  812. X    while (slash = strchr(component, '/')) {
  813. X    if (slash == component) {
  814. X        /*  ...//...  */
  815. X        component++;
  816. X        continue;
  817. X    }
  818. X    *slash = NUL;
  819. X    if (mkdir(name, 0755)) {
  820. X        msg("Cannot make %s/", name);
  821. X        *slash = '/';
  822. X        return 0;
  823. X    }
  824. X    *slash++ = '/';
  825. X    component = slash;
  826. X    }
  827. X    return 1;
  828. X}
  829. X
  830. NO_NEWS_IS_GOOD_NEWS
  831. chmod 0644 save.c || echo "restore of save.c fails"
  832. set `wc -c save.c`;Sum=$1
  833. if test "$Sum" != "13813"
  834. then echo original size 13813, current size $Sum;fi
  835. echo "x - extracting selection.c (Text)"
  836. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > selection.c &&
  837. X/*
  838. X *    save selected articles (if any) between invocations
  839. X */
  840. X
  841. X#include "config.h"
  842. X#include "articles.h"
  843. X
  844. X#define    SLMAGIC    0x536c6374
  845. X#define GNAME_LGT 32
  846. X
  847. Xstatic struct sel_header {
  848. X    char        sl_group[GNAME_LGT];
  849. X    int32        sl_magic;
  850. X    int32        sl_count;
  851. X    int32        sl_first;
  852. X    int32        sl_last;
  853. X} header;
  854. X
  855. X#ifndef NETWORK_DATABASE
  856. X#undef ntohl
  857. X#undef htonl
  858. X#undef NETWORK_BYTE_ORDER
  859. X#define ntohl(x) (x)
  860. X#define htonl(x) (x)
  861. X#define NETWORK_BYTE_ORDER
  862. X#endif
  863. X
  864. Xstruct sel_art {
  865. X    int32        sl_number;
  866. X    int32        sl_fpos;
  867. X    int32        sl_flag;
  868. X};
  869. X
  870. X
  871. Xsave_selection(gh, first, last)
  872. Xgroup_header *gh;
  873. Xarticle_number first, last;
  874. X{
  875. X    register article_header *ah, **ahp;
  876. X    register int art;
  877. X    register int save_count, seen_count, flags;
  878. X    struct sel_art elem;
  879. X    FILE *f;
  880. X    char buffer[16];
  881. X
  882. X    if (gh->group_flag & (G_FOLDER | G_READ)) return;
  883. X
  884. X    for (save_count = seen_count = 0, art = n_articles; --art >= 0; ) {
  885. X    flags = articles[art]->flag; 
  886. X    if (flags & A_SEEN) seen_count++;
  887. X    if (flags & A_SELECT) save_count++;
  888. X    }
  889. X    
  890. X    if (save_count == 0 && 
  891. X    (seen_count == 0 || seen_count == n_articles)) return;
  892. X
  893. X    sprintf(buffer, "S.%d", (int)(gh->group_num));
  894. X    f = open_file(relative(nn_directory, buffer), OPEN_CREATE|MUST_EXIST);
  895. X    
  896. X    strncpy(header.sl_group, gh->group_name, GNAME_LGT);
  897. X    header.sl_magic = htonl(SLMAGIC);
  898. X    header.sl_count = htonl(save_count);
  899. X    header.sl_first = htonl(first);
  900. X    header.sl_last  = htonl(last);
  901. X    
  902. X    fwrite(&header, sizeof(header), 1, f);
  903. X
  904. X    unsort_articles(1);
  905. X    
  906. X    for (ahp = articles, art = 0; art < n_articles; ahp++, art++) {
  907. X    ah = *ahp;
  908. X    if (elem.sl_flag = htonl(ah->flag & (A_SELECT | A_SEEN))) {
  909. X        
  910. X        elem.sl_number = htonl(ah->a_number);
  911. X        elem.sl_fpos   = htonl(ah->fpos);
  912. X        
  913. X        fwrite(&elem, sizeof(elem), 1, f);
  914. X    }
  915. X    }
  916. X    
  917. X    fclose(f);
  918. X
  919. X    gh->group_flag |= G_SELECTION;
  920. X}
  921. X
  922. X
  923. Xstatic FILE *sel_file;
  924. X
  925. Xhas_selection(gh, first_p, last_p)
  926. Xgroup_header *gh;
  927. Xarticle_number *first_p, *last_p;
  928. X{
  929. X    FILE *f;
  930. X    char buffer[16];
  931. X
  932. X    if (gh->group_flag & (G_FOLDER | G_READ)) return 0;
  933. X    
  934. X    sprintf(buffer, "S.%d", (int)(gh->group_num));    
  935. X    f = open_file(relative(nn_directory, buffer), OPEN_READ|OPEN_UNLINK);
  936. X    if (f == NULL) return 0;
  937. X
  938. X    if (fread(&header, sizeof(header), 1, f) != 1
  939. X    || ntohl(header.sl_magic) != SLMAGIC
  940. X    || strncmp(header.sl_group, gh->group_name, GNAME_LGT)) {
  941. X    fclose(f);
  942. X    return 0;
  943. X    }
  944. X
  945. X    if ((gh->group_flag & G_SELECTION) == 0) {
  946. X    clrdisp();
  947. X    raw();
  948. X    prompt("Group %s: use old selections (%s)? ", 
  949. X           gh->group_name, date_time(m_time(f)));
  950. X    if (yes(0) <= 0) {
  951. X        fclose(f);
  952. X        return 0;
  953. X    } 
  954. X    }
  955. X    
  956. X#ifndef NETWORK_BYTE_ORDER
  957. X    header.sl_first = ntohl(header.sl_first);
  958. X    header.sl_last = ntohl(header.sl_last);
  959. X#endif
  960. X    *first_p = header.sl_first;
  961. X    *last_p = header.sl_last;
  962. X    sel_file = f;
  963. X    
  964. X    return 1;
  965. X}
  966. X
  967. X
  968. Xdo_selections(ok)
  969. Xint ok;
  970. X{
  971. X    register long art;
  972. X    struct sel_art elem;
  973. X    register article_header *ah, **ahp;
  974. X
  975. X    if (!ok) goto out;
  976. X    
  977. X    elem.sl_number = -1;
  978. X    
  979. X    for (ahp = articles, art = 0; art < n_articles; ahp++, art++) {
  980. X    ah = *ahp;
  981. X
  982. X    if (ah->a_number > header.sl_last) break;
  983. X    
  984. X    while (ah->a_number > elem.sl_number) {
  985. X        if (fread(&elem, sizeof(elem), 1, sel_file) != 1) goto out;
  986. X#ifndef NETWORK_BYTE_ORDER
  987. X        elem.sl_number = ntohl(elem.sl_number);
  988. X#endif
  989. X    }
  990. X    
  991. X#ifndef NETWORK_BYTE_ORDER
  992. X    elem.sl_fpos = ntohl(elem.sl_fpos);
  993. X#endif
  994. X    while (ah->a_number == elem.sl_number && ah->fpos > elem.sl_fpos) {
  995. X        if (fread(&elem, sizeof(elem), 1, sel_file) != 1) goto out;
  996. X#ifndef NETWORK_BYTE_ORDER
  997. X        elem.sl_number = ntohl(elem.sl_number);
  998. X        elem.sl_fpos = ntohl(elem.sl_fpos);
  999. X#endif
  1000. X    }
  1001. X    
  1002. X    if (ah->a_number != elem.sl_number || ah->fpos != elem.sl_fpos) 
  1003. X        continue;
  1004. X    
  1005. X    ah->flag |= ntohl(elem.sl_flag);
  1006. X    }
  1007. X    
  1008. Xout:
  1009. X    
  1010. X    fclose(sel_file);
  1011. X}
  1012. X
  1013. NO_NEWS_IS_GOOD_NEWS
  1014. chmod 0644 selection.c || echo "restore of selection.c fails"
  1015. set `wc -c selection.c`;Sum=$1
  1016. if test "$Sum" != "3865"
  1017. then echo original size 3865, current size $Sum;fi
  1018. echo "x - extracting sequence.c (Text)"
  1019. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > sequence.c &&
  1020. X/*
  1021. X * read presentation sequence file
  1022. X */
  1023. X
  1024. X#include "config.h"
  1025. X#include "debug.h"
  1026. X
  1027. Xexport group_header *group_sequence;
  1028. Xexport char *read_mail = NULL;
  1029. X
  1030. Xstatic int seq_break_enabled = 1;    /* !! enabled */
  1031. X
  1032. Xstatic group_header *tail_sequence = NULL;
  1033. Xstatic group_header *final_sequence = NULL;
  1034. X
  1035. Xstatic int gs_more_groups;
  1036. X
  1037. X
  1038. Xonly_folder_args(args)
  1039. Xchar **args;
  1040. X{
  1041. X    register char *arg;
  1042. X
  1043. X    while (arg = *args++) {
  1044. X    if (*arg == '+' || *arg == '~' || *arg == '/') continue;
  1045. X    if (file_exist(arg, "fr")) continue;
  1046. X    return 0;
  1047. X    }
  1048. X    return 1;
  1049. X}
  1050. X
  1051. X
  1052. Xnamed_group_sequence(groups)
  1053. Xchar **groups;
  1054. X{
  1055. X    register group_header *gh;
  1056. X    group_header *get_group_search();
  1057. X    register char *group;
  1058. X    int found, any, errors;
  1059. X
  1060. X    group_sequence = NULL;
  1061. X    
  1062. X    any = errors = 0;
  1063. X    while (group = *groups++) {
  1064. X        
  1065. X    if (gh = lookup(group)) {
  1066. X        if (gh->group_flag & G_DONE) continue;
  1067. X        any++;
  1068. X        enter_normal(gh);
  1069. X        continue;
  1070. X    }
  1071. X
  1072. X    if (file_exist(group, "fr")) {
  1073. X        faked_entry(group, G_FOLDER);
  1074. X        any++;
  1075. X        continue;
  1076. X    }
  1077. X
  1078. X    if (*group == '+' || *group == '~') {
  1079. X        char exp_file[FILENAME];
  1080. X        group_header fake_group;
  1081. X        
  1082. X        current_group = &fake_group;
  1083. X        fake_group.group_name = group;
  1084. X        group_file_name = NULL;
  1085. X        if (expand_file_name(exp_file, group) && file_exist(exp_file, "fr")) {
  1086. X        faked_entry(copy_str(exp_file), G_FOLDER);
  1087. X        any++;
  1088. X        continue;
  1089. X        }
  1090. X
  1091. X        printf("Folder %s not found\n", group); fl;
  1092. X        errors++;
  1093. X        continue;
  1094. X    }
  1095. X    
  1096. X    found = 0;
  1097. X    start_group_search(group);
  1098. X    while (gh = get_group_search()) {
  1099. X        if ((gh->group_flag & G_SUBSCRIPTION) == 0) continue;
  1100. X        found++;
  1101. X        enter_normal(gh);
  1102. X    }
  1103. X     
  1104. X    if (!found) {
  1105. X        printf("Group %s not found\n", group); fl;
  1106. X        errors++;
  1107. X    } else
  1108. X        any++;
  1109. X    }
  1110. X
  1111. X    end_sequence();
  1112. X    
  1113. X    if (errors) user_delay(2);
  1114. X    
  1115. X    return any;
  1116. X}
  1117. X
  1118. XFILE *loc_seq_hook = NULL;    /* sequence in local "init" file */
  1119. XFILE *glob_seq_hook = NULL;    /* sequence in global "init" file */
  1120. X
  1121. Xnormal_group_sequence()
  1122. X{
  1123. X    register group_header *gh;
  1124. X
  1125. X    group_sequence = NULL;
  1126. X    gs_more_groups = 1;
  1127. X    
  1128. X    /* visit_p_f returns non-zero if terminated by !! */
  1129. X
  1130. X    if (visit_presentation_file(nn_directory, "seq", loc_seq_hook))
  1131. X    goto final;
  1132. X    
  1133. X    if (visit_presentation_file(lib_directory, "sequence", glob_seq_hook))
  1134. X    goto final;
  1135. X    
  1136. X    Loop_Groups_Sorted(gh) {
  1137. X    if (gh->group_flag & G_DONE) continue;
  1138. X    
  1139. X    if ((gh->group_flag & G_SUBSCRIPTION) == 0) continue;
  1140. X
  1141. X    enter_normal(gh);
  1142. X    }
  1143. X
  1144. X final:
  1145. X    if (final_sequence) {
  1146. X    enter_normal(final_sequence);
  1147. X    tail_sequence = NULL;
  1148. X    }
  1149. X
  1150. X#ifdef MAIL_READING
  1151. X    mail_check();
  1152. X#endif
  1153. X    
  1154. X    end_sequence();
  1155. X}
  1156. X
  1157. Xstatic end_sequence()
  1158. X{
  1159. X    register group_header *gh, *backp;
  1160. X
  1161. X    if (tail_sequence)
  1162. X    tail_sequence->next_group = NULL;
  1163. X    
  1164. X    /* set up backward pointers */
  1165. X
  1166. X    backp = NULL;
  1167. X    gh = group_sequence; 
  1168. X    while (gh) {
  1169. X    gh->prev_group = backp;
  1170. X    backp = gh;
  1171. X    gh = gh->next_group;
  1172. X    }
  1173. X
  1174. X#ifdef SEQ_DUMP
  1175. X    if (Debug & SEQ_DUMP) {
  1176. X    for (gh = group_sequence; gh; gh = gh->next_group)
  1177. X        printf("%s\t", gh->group_name);
  1178. X    putchar(NL);
  1179. X
  1180. X    nn_exit(0);
  1181. X    }
  1182. X#endif
  1183. X    
  1184. X}
  1185. X
  1186. X#ifdef MAIL_READING
  1187. Xstatic mail_check()
  1188. X{
  1189. X    static group_header mail_group;
  1190. X    struct stat st;
  1191. X    
  1192. X    if (read_mail == NULL) return;
  1193. X    if (stat(read_mail, &st) < 0) return;
  1194. X    if (st.st_size == 0 || st.st_mtime < st.st_atime) return;
  1195. X    
  1196. X    mail_group.group_name = read_mail;
  1197. X    gh->group_flag = G_FOLDER | G_MAILBOX | G_RC_UPDATED | G_READ;
  1198. X
  1199. X    /* "invent" an unread article for read_news */
  1200. X    gh->last_article = 1;
  1201. X    gh->last_l_article = 2;
  1202. X    
  1203. X    
  1204. X    if (tail_sequence) {
  1205. X    mail_group.next_group = group_sequence;
  1206. X    group_sequence = mail_group;
  1207. X    } else
  1208. X    enter_normal(&mail_group);
  1209. X}
  1210. X#endif
  1211. X
  1212. Xstatic visit_presentation_file(directory, seqfile, hook)
  1213. Xchar *directory, *seqfile;
  1214. XFILE *hook;
  1215. X{
  1216. X    import int group_name_args;
  1217. X    
  1218. X    register FILE *sf;
  1219. X    register c;
  1220. X    register group_header *gh;
  1221. X    group_header *get_group_search();
  1222. X    char group[FILENAME];
  1223. X    char savefile[FILENAME], *dflt_save;
  1224. X    register char *gp;
  1225. X    int mode;
  1226. X    
  1227. X#define    SHOW_NORMAL    0    /*   : put this in at current pos */
  1228. X#define    SHOW_NEVER    1    /* ! : ignore these groups */
  1229. X#define    SHOW_FIRST    2    /* < : show these groups first */
  1230. X#define    SHOW_LAST    3    /* > : show this as late as possible */
  1231. X
  1232. X#define    SHOW_MODES    " !<>"
  1233. X
  1234. X    if (gs_more_groups == 0) return 0;
  1235. X    
  1236. X    if (hook != NULL)
  1237. X    sf = hook;    /* hook to init file */
  1238. X    else
  1239. X    if ((sf = open_file(relative(directory, seqfile), OPEN_READ)) == NULL)
  1240. X        return 0;
  1241. X
  1242. X#ifdef SEQ_TEST
  1243. X    if (Debug & SEQ_TEST)
  1244. X    printf("Sequence file %s/%s\n", directory, seqfile);
  1245. X#endif
  1246. X    
  1247. X    mode = SHOW_NORMAL;
  1248. X    savefile[0] = NUL;
  1249. X    
  1250. X    while (gs_more_groups) {
  1251. X    
  1252. X    if ((c = getc(sf)) == EOF) break;
  1253. X    if (!isascii(c) || isspace(c)) continue;
  1254. X
  1255. X    switch (c) {
  1256. X     case '!':
  1257. X        if (mode == SHOW_NEVER && seq_break_enabled) {
  1258. X        fclose(sf);
  1259. X        return 1;
  1260. X        }
  1261. X        
  1262. X        mode = SHOW_NEVER;
  1263. X        continue;
  1264. X
  1265. X     case '<':
  1266. X        mode = SHOW_FIRST;
  1267. X        continue;
  1268. X        
  1269. X     case '>':
  1270. X        mode = SHOW_LAST;
  1271. X        continue;
  1272. X
  1273. X     case '@':
  1274. X        seq_break_enabled = 0;
  1275. X        mode = SHOW_NORMAL;
  1276. X        continue;
  1277. X        
  1278. X     case '#':
  1279. X        do c = getc(sf);
  1280. X        while (c != EOF && c != NL);
  1281. X        mode = SHOW_NORMAL;
  1282. X        continue;
  1283. X
  1284. X    }
  1285. X    
  1286. X    gp = group; 
  1287. X    do {
  1288. X        *gp++ = c;
  1289. X        c = getc(sf);
  1290. X    } while (c != EOF && isascii(c) && !isspace(c));
  1291. X    
  1292. X    *gp = NUL;
  1293. X    
  1294. X    while (c != EOF && (!isascii(c) || isspace(c))) c = getc(sf);
  1295. X    if (c == '+' || c == '~' || c == '/') {
  1296. X        gp = savefile;
  1297. X        if (c == '+') {
  1298. X        c = getc(sf);
  1299. X        if (c == EOF || (isascii(c) && isspace(c)))
  1300. X            goto use_same_savefile;
  1301. X        *gp++ = '+';
  1302. X        }
  1303. X        do {
  1304. X        *gp++ = c;
  1305. X        c = getc(sf);
  1306. X        } while (c != EOF && isascii(c) && !isspace(c));
  1307. X        *gp = NUL;
  1308. X        dflt_save = savefile[0] ? copy_str(savefile) : NULL;
  1309. X    } else {
  1310. X        dflt_save = NULL;
  1311. X        if (c != EOF) ungetc(c, sf);
  1312. X    }
  1313. X    
  1314. X     use_same_savefile:    
  1315. X
  1316. X    start_group_search(group);
  1317. X    
  1318. X    while (gh = get_group_search()) {
  1319. X
  1320. X        gh->save_file = dflt_save;
  1321. X        
  1322. X        if (group_name_args == 0 &&
  1323. X        (gh->group_flag & G_SUBSCRIPTION) == 0) continue;
  1324. X
  1325. X#ifdef SEQ_TEST
  1326. X        if (Debug & SEQ_TEST && mode != SHOW_NORMAL)
  1327. X        printf("SEQ(%c), %s\n", SHOW_MODES[mode], gh->group_name);
  1328. X#endif
  1329. X        
  1330. X        switch (mode) {
  1331. X         case SHOW_FIRST:
  1332. X        if (tail_sequence) {
  1333. X            gh->next_group = group_sequence;
  1334. X            group_sequence = gh;
  1335. X            break;
  1336. X        }
  1337. X        /* fall thru */
  1338. X
  1339. X         case SHOW_NORMAL:
  1340. X        enter_normal(gh);
  1341. X        break;
  1342. X        
  1343. X         case SHOW_NEVER:
  1344. X        break;
  1345. X        
  1346. X         case SHOW_LAST:
  1347. X        gh->next_group = final_sequence;
  1348. X        final_sequence = gh;
  1349. X        break;
  1350. X        }
  1351. X    }
  1352. X    
  1353. X    mode = SHOW_NORMAL;
  1354. X    }        
  1355. X
  1356. X    fclose(sf);
  1357. X    return 0;
  1358. X}
  1359. X
  1360. X
  1361. Xstatic enter_normal(gh)
  1362. Xgroup_header *gh;
  1363. X{
  1364. X    gh->group_flag |= G_DONE;
  1365. X    if (tail_sequence)
  1366. X    tail_sequence->next_group = gh;
  1367. X    else
  1368. X    group_sequence = gh;
  1369. X        
  1370. X    tail_sequence = gh;
  1371. X
  1372. X#ifdef SEQ_TEST
  1373. X    if (Debug & SEQ_TEST)
  1374. X        printf("SEQ(NORMAL) %s\n", gh->group_name);
  1375. X#endif
  1376. X}
  1377. X
  1378. X
  1379. Xstatic faked_entry(name, flag)
  1380. Xchar *name;
  1381. Xint flag;
  1382. X{
  1383. X    group_header *gh;
  1384. X    
  1385. X    gh = (group_header *)calloc(1, sizeof(group_header));
  1386. X    mem_check(gh, 1, "group header");
  1387. X    
  1388. X    gh->group_name = name;
  1389. X    gh->group_flag = flag | G_RC_UPDATED | G_READ;
  1390. X
  1391. X    /* "invent" an unread article for read_news */
  1392. X    gh->last_article = 1;
  1393. X    gh->last_l_article = 2;
  1394. X    
  1395. X    enter_normal(gh);
  1396. X}
  1397. X
  1398. X
  1399. Xstatic char *gs_group;
  1400. Xstatic int gs_length, gs_index, gs_mode;
  1401. X
  1402. X#define    GS_PREFIX    1    /* group. */
  1403. X#define    GS_SUFFIX    2    /* .group */
  1404. X#define GS_INFIX    3    /* .group. */
  1405. X#define GS_NEW_GROUP    4    /* new group */
  1406. X
  1407. Xstatic start_group_search(group)
  1408. Xchar *group;
  1409. X{
  1410. X    char *dot;
  1411. X    
  1412. X    if (strcmp(group, "NEW") == 0) {
  1413. X    gs_mode = GS_NEW_GROUP;
  1414. X    gs_length = 127;
  1415. X    } else {
  1416. X    gs_mode = GS_PREFIX;
  1417. X    
  1418. X    if (strncmp(group, "all.", 4) == 0) group += 3;
  1419. X    
  1420. X    if (*group == '.') gs_mode = GS_SUFFIX;
  1421. X    
  1422. X    if ((dot = strrchr(group, '.')) != NULL && dot != group) {
  1423. X        if (dot[1] == NUL || strcmp(dot+1, "all") == 0) {
  1424. X        *dot = NUL;
  1425. X        if (gs_mode == GS_SUFFIX) gs_mode = GS_INFIX;
  1426. X        }
  1427. X    }
  1428. X    
  1429. X    gs_length = strlen(group);
  1430. X    gs_group = group;
  1431. X    }    
  1432. X
  1433. X    gs_index = 0;
  1434. X    gs_more_groups = 0;
  1435. X}
  1436. X
  1437. X
  1438. Xstatic group_header *get_group_search()
  1439. X{
  1440. X    register group_header *gh;
  1441. X    register int c, tail;
  1442. X    
  1443. X    while (gs_index < master.number_of_groups) {
  1444. X    gh = sorted_groups[gs_index++];
  1445. X    if (gh->group_flag & G_DONE) continue;
  1446. X
  1447. X    gs_more_groups++;
  1448. X
  1449. X    if ((tail = gh->group_name_length - gs_length) < 0) continue;
  1450. X    
  1451. X    switch (gs_mode) {
  1452. X        
  1453. X     case GS_NEW_GROUP:
  1454. X        if ((gh->group_flag & G_NEW) == 0) continue;
  1455. X        break;
  1456. X        
  1457. X     case GS_PREFIX:
  1458. X        if ((c = (gh->group_name)[gs_length]) != NUL && c != '.') continue;
  1459. X        if (strncmp(gh->group_name, gs_group, gs_length)) continue;
  1460. X        break;
  1461. X        
  1462. X     case GS_SUFFIX:
  1463. X        if (strcmp(gh->group_name + tail, gs_group)) continue;
  1464. X        break;
  1465. X        
  1466. X     case GS_INFIX:
  1467. X        user_error(".name. notation not supported (yet)");
  1468. X        break;
  1469. X    }
  1470. X
  1471. X    gs_more_groups--;
  1472. X    gh->group_flag |= G_DONE;
  1473. X    
  1474. X    return gh;
  1475. X    }
  1476. X    
  1477. X    return NULL;
  1478. X}
  1479. NO_NEWS_IS_GOOD_NEWS
  1480. chmod 0644 sequence.c || echo "restore of sequence.c fails"
  1481. set `wc -c sequence.c`;Sum=$1
  1482. if test "$Sum" != "8980"
  1483. then echo original size 8980, current size $Sum;fi
  1484. echo "x - extracting term.c (Text)"
  1485. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > term.c &&
  1486. X/*
  1487. X * terminal interface
  1488. X */
  1489. X
  1490. X#include <signal.h> 
  1491. X#include <errno.h>
  1492. X#include "config.h"
  1493. X#include "term.h"
  1494. X#include "keymap.h"
  1495. X
  1496. X#ifdef RESIZING
  1497. X#include <sys/ioctl.h>            /* for TIOCGWINSZ */
  1498. X
  1499. Xint s_resized;
  1500. X#endif
  1501. X
  1502. Xexport char *term_name;
  1503. Xexport int  show_current_time = 1;
  1504. Xexport int  conf_dont_sleep = 0;
  1505. Xexport int  prompt_length;
  1506. Xexport int  slow_mode = 0;
  1507. Xexport int  any_message = 0;
  1508. X
  1509. Xexport char help_key = '?';
  1510. Xexport char comp1_key = SP;
  1511. Xexport char comp2_key = TAB;
  1512. Xexport char erase_key, kill_key;
  1513. Xexport char delword_key = CTRL('W');
  1514. X
  1515. X#ifdef USE_TERMINFO
  1516. X
  1517. X#include <curses.h>
  1518. X#ifndef auto_left_margin
  1519. X#include <term.h>
  1520. X#endif
  1521. X
  1522. X#define HAS_CAP(str) (str && *str)
  1523. X
  1524. X#else
  1525. X
  1526. X#define USE_TERMCAP
  1527. X
  1528. Xchar *tgoto();
  1529. Xchar PC;
  1530. Xchar *BC, *UP;
  1531. Xshort ospeed;
  1532. X
  1533. Xstatic char XBC[64], XUP[64];
  1534. Xstatic char cursor_home[64];
  1535. Xstatic char cursor_address[64];
  1536. Xstatic char clear_screen[64];
  1537. Xstatic char clr_eol[64];
  1538. Xstatic char clr_eos[64];
  1539. Xstatic char enter_standout_mode[64], exit_standout_mode[64];
  1540. Xstatic char enter_underline_mode[64], exit_underline_mode[64];
  1541. Xstatic char bell[256];
  1542. Xstatic char key_down[64], key_up[64], key_right[64], key_left[64];
  1543. X
  1544. Xint  magic_cookie_glitch;    /* magic cookie size */
  1545. X
  1546. X#define putp(str)    tputs(str, 0, outc)
  1547. X
  1548. X#define HAS_CAP(str)    (*str)
  1549. X
  1550. Xstatic outc(c)
  1551. X{
  1552. X    putchar(c);
  1553. X}
  1554. X
  1555. X#endif    /* USE_TERMCAP */
  1556. X
  1557. Xint  Lines, Columns;    /* screen size */
  1558. Xint  cookie_size;    /* size of magic cookie */
  1559. Xint  two_cookies;    /* space needed to enter&exit standout mode */
  1560. Xint  STANDOUT;        /* terminal got standout mode */
  1561. Xint  WRAP;        /* terminal got automatic margins */
  1562. X
  1563. X#ifdef HAVE_TERMIO
  1564. X
  1565. X#define KEY_BURST 50    /* read bursts of 50 chars (or timeout after 100 ms) */
  1566. X
  1567. X#ifdef USE_TERMCAP
  1568. X#include <termio.h>
  1569. X#endif
  1570. X
  1571. Xstatic struct termio norm_tty, raw_tty;
  1572. X
  1573. X#define    IntrC    norm_tty.c_cc[VINTR]
  1574. X#define    EraseC    norm_tty.c_cc[VERASE]
  1575. X#define KillC    norm_tty.c_cc[VKILL]
  1576. X#define SuspC    CTRL('Z')    /* norm_tty.c_cc[SWTCH] */
  1577. X
  1578. X#else    /* V7/BSD TTY DRIVER */
  1579. X
  1580. X#include <sgtty.h>
  1581. X
  1582. Xstatic struct sgttyb norm_tty, raw_tty;
  1583. Xstatic struct tchars norm_chars;
  1584. X
  1585. X#define    IntrC    norm_chars.t_intrc
  1586. X#define    EraseC    norm_tty.sg_erase
  1587. X#define KillC    norm_tty.sg_kill
  1588. X
  1589. X#ifdef TIOCGLTC
  1590. Xstatic struct     ltchars spec_chars;
  1591. X#define SuspC    spec_chars.t_suspc
  1592. X#else
  1593. X#define    SuspC    CTRL('Z')
  1594. X#endif
  1595. X
  1596. X#endif
  1597. X
  1598. X#ifdef USE_TERMCAP
  1599. X
  1600. Xopt_cap(cap, buf)
  1601. Xchar *cap, *buf;
  1602. X{
  1603. X    char *tgetstr();
  1604. X    
  1605. X    *buf = NUL;
  1606. X    return tgetstr(cap, &buf) != NULL;
  1607. X}
  1608. X
  1609. Xget_cap(cap, buf)
  1610. Xchar *cap, *buf;
  1611. X{
  1612. X    if (!opt_cap(cap, buf)) 
  1613. X    user_error("TERMCAP entry for %s has no '%s' capability",
  1614. X           term_name, cap);
  1615. X}           
  1616. X
  1617. X#endif  /* USE_TERMCAP */
  1618. X
  1619. Xstatic int multi_keys = 0;
  1620. X
  1621. Xstatic struct multi_key {
  1622. X    char *cur_key;
  1623. X    char *keys;
  1624. X    int code;
  1625. X} multi_key_list[MULTI_KEYS];
  1626. X
  1627. Xenter_multi_key(code, keys)
  1628. Xint code;
  1629. Xchar *keys;
  1630. X{
  1631. X    register i;
  1632. X    
  1633. X    /* lookup code to see if it is already defined... */
  1634. X    for (i = 0; i < multi_keys; i++)
  1635. X    if (multi_key_list[i].code == code)
  1636. X        goto replace_key;
  1637. X    
  1638. X    i = multi_keys++;
  1639. X    
  1640. X    /* now i points to matching or empty slot */
  1641. X    if (i >= MULTI_KEYS) {
  1642. X    /* should never happen */
  1643. X    log_entry('E', "too many multi keys");
  1644. X    return;
  1645. X    }
  1646. X    
  1647. X replace_key:
  1648. X
  1649. X    multi_key_list[i].keys = keys;
  1650. X    multi_key_list[i].code = code;
  1651. X}
  1652. X
  1653. Xdump_multi_keys()
  1654. X{
  1655. X    register i;
  1656. X    register char *cp;
  1657. X    extern char *key_name();
  1658. X    
  1659. X    clrdisp();
  1660. X    pg_init(0, 1);
  1661. X    
  1662. X    for (i = 0; i < multi_keys; i++) {
  1663. X    if (pg_next() < 0) break;
  1664. X    printf("%d\t%s\t", i, key_name(multi_key_list[i].code));
  1665. X    for (cp = multi_key_list[i].keys; *cp; cp++) {
  1666. X        putchar(SP);
  1667. X        fputs(key_name(*cp), stdout);
  1668. X    }
  1669. X    }
  1670. X
  1671. X    pg_end();
  1672. X}
  1673. X
  1674. X    
  1675. X#ifdef RESIZING
  1676. X
  1677. Xsig_type winch()
  1678. X{
  1679. X    struct winsize winsize;
  1680. X
  1681. X    (void) signal(SIGWINCH, winch);
  1682. X    if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
  1683. X    && (winsize.ws_row != Lines || winsize.ws_col != Columns)) { 
  1684. X    Lines = winsize.ws_row;
  1685. X    Columns = winsize.ws_col;
  1686. X    s_redraw = 1;
  1687. X    s_resized = 1;
  1688. X    }
  1689. X}
  1690. X#endif /* RESIZING */
  1691. X
  1692. X
  1693. Xinit_term()
  1694. X{
  1695. X#ifdef USE_TERMCAP
  1696. X    char tbuf[1024];
  1697. X#endif
  1698. X    
  1699. X    if ((term_name = getenv("TERM")) == NULL)
  1700. X    user_error("No TERM variable in enviroment");
  1701. X    
  1702. X#ifdef USE_TERMINFO
  1703. X    setupterm(0,1,0);
  1704. X    Columns = columns;
  1705. X    Lines = lines;
  1706. X    cookie_size = magic_cookie_glitch;
  1707. X    WRAP = auto_right_margin;
  1708. X    if (HAS_CAP(flash_screen)) strcpy(bell, flash_screen);
  1709. X    if (! HAS_CAP(cursor_home))
  1710. X    cursor_home = copy_str(tgoto(cursor_address, 0, 0));
  1711. X#else
  1712. X    
  1713. X    if (tgetent(tbuf, term_name) <= 0)
  1714. X    user_error("Unknown terminal type: %s", term_name);
  1715. X    
  1716. X    if (opt_cap("bc", XBC)) BC = XBC;
  1717. X    if (opt_cap("up", XUP)) UP = XUP;
  1718. X    opt_cap("pc", cursor_address);    /* temp. usage */
  1719. X    PC = cursor_address[0];
  1720. X    
  1721. X    get_cap("cm", cursor_address);
  1722. X    if (!opt_cap("ho", cursor_home))
  1723. X    strcpy(cursor_home, tgoto(cursor_address, 0, 0));
  1724. X
  1725. X    get_cap("cl", clear_screen);
  1726. X    get_cap("ce", clr_eol);
  1727. X    opt_cap("cd", clr_eos);
  1728. X    
  1729. X#ifdef RESIZING
  1730. X    {
  1731. X    struct winsize winsize;
  1732. X
  1733. X    if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
  1734. X        && winsize.ws_row != 0 && winsize.ws_col != 0) { 
  1735. X        Lines = winsize.ws_row;
  1736. X        Columns = winsize.ws_col;
  1737. X        (void) signal(SIGWINCH, winch);
  1738. X#ifdef SV_INTERRUPT
  1739. X        siginterrupt(SIGWINCH, 1);    /* make read from tty interruptable */
  1740. X#endif /* SV_INTERRUPT */
  1741. X    }
  1742. X    }
  1743. X    if (Lines == 0 || Columns == 0) {
  1744. X#endif /* RESIZING */
  1745. X    Lines = tgetnum("li");
  1746. X    Columns = tgetnum("co");
  1747. X#ifdef RESIZING
  1748. X    }
  1749. X#endif /* RESIZING */
  1750. X
  1751. X    opt_cap("so", enter_standout_mode);
  1752. X    opt_cap("se", exit_standout_mode);
  1753. X    
  1754. X    opt_cap("us", enter_underline_mode);
  1755. X    opt_cap("ue", exit_underline_mode);
  1756. X
  1757. X    opt_cap("kd", key_down);
  1758. X    opt_cap("ku", key_up);
  1759. X    opt_cap("kr", key_right);
  1760. X    opt_cap("kl", key_left);
  1761. X
  1762. X    cookie_size = tgetnum("sg");
  1763. X    
  1764. X    WRAP = tgetflag("am");
  1765. X    
  1766. X    if (!opt_cap("vb", bell) && !opt_cap("bl", bell)) 
  1767. X    strcpy(bell, "\007");
  1768. X    
  1769. X#endif /* !USE_TERMINFO */
  1770. X    
  1771. X    STANDOUT = HAS_CAP(enter_standout_mode);
  1772. X    if (STANDOUT) {
  1773. X    if (cookie_size < 0) cookie_size = 0;
  1774. X    two_cookies = 2 * cookie_size;
  1775. X    } else
  1776. X    cookie_size = two_cookies = 0;
  1777. X    
  1778. X    
  1779. X#ifdef HAVE_TERMIO
  1780. X    
  1781. X    ioctl(0, TCGETA, &norm_tty);
  1782. X    
  1783. X    raw_tty = norm_tty;
  1784. X    
  1785. X    raw_tty.c_iflag &= ~(BRKINT|INLCR|ICRNL|IGNCR);
  1786. X    raw_tty.c_iflag |= IGNBRK|IGNPAR|ISTRIP;
  1787. X    raw_tty.c_oflag &= ~OPOST;
  1788. X    raw_tty.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|NOFLSH);
  1789. X    
  1790. X    /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */
  1791. X    raw_tty.c_cc[VEOF] = KEY_BURST;
  1792. X    raw_tty.c_cc[VEOL] = ((raw_tty.c_cflag & CBAUD) > B1200) ? 1 : 2;
  1793. X    
  1794. X#else    
  1795. X    
  1796. X    ioctl(0, TIOCGETP, &norm_tty);
  1797. X    
  1798. X    ioctl(0, TIOCGETC, &norm_chars);
  1799. X    
  1800. X#ifdef TIOCGLTC
  1801. X    ioctl(0, TIOCGLTC, &spec_chars);
  1802. X#endif
  1803. X    
  1804. X    ospeed = norm_tty.sg_ospeed;
  1805. X    if (ospeed < B2400) slow_mode++;
  1806. X    
  1807. X    raw_tty = norm_tty;
  1808. X    
  1809. X    raw_tty.sg_flags |= RAW;
  1810. X    raw_tty.sg_flags &= ~(ECHO|CRMOD);
  1811. X
  1812. X#ifdef SV_INTERRUPT
  1813. X    siginterrupt(SIGALRM, 1);        /* make read from tty interruptable */
  1814. X#endif
  1815. X#endif
  1816. X
  1817. X    if (HAS_CAP(key_down))  enter_multi_key(K_down_arrow, key_down);
  1818. X    if (HAS_CAP(key_up)) enter_multi_key(K_up_arrow, key_up);
  1819. X    if (HAS_CAP(key_right)) enter_multi_key(K_right_arrow, key_right);
  1820. X    if (HAS_CAP(key_left)) enter_multi_key(K_left_arrow, key_left);
  1821. X    
  1822. X    erase_key = EraseC;
  1823. X    kill_key  = KillC;
  1824. X}
  1825. X
  1826. Xhome()
  1827. X{
  1828. X    putp(cursor_home);
  1829. X}
  1830. X
  1831. Xgotoxy(c, l)
  1832. X{
  1833. X    putp(tgoto(cursor_address, c, l));
  1834. X}
  1835. X
  1836. Xclrdisp()
  1837. X{
  1838. X#ifdef USE_TERMINFO
  1839. X    putp(clear_screen);        /* tputs is broken on UNISYS I've been told */
  1840. X#else
  1841. X    tputs(clear_screen, Lines, outc);
  1842. X#endif
  1843. X}
  1844. X
  1845. Xclrline()
  1846. X{
  1847. X    putp(clr_eol);
  1848. X    fl;
  1849. X}
  1850. X
  1851. Xclrpage(lineno)
  1852. Xregister int lineno;
  1853. X{
  1854. X    register int olineno= lineno;
  1855. X    if (HAS_CAP(clr_eos)) {
  1856. X#ifdef USE_TERMINFO
  1857. X    putp(clr_eos);
  1858. X#else    
  1859. X    tputs(clr_eos, Lines - lineno, outc);
  1860. X#endif
  1861. X    } else {
  1862. X    clrline();
  1863. X    lineno++;
  1864. X    for (; lineno < Lines; lineno++) {
  1865. X        gotoxy(0, lineno);
  1866. X        putp(clr_eol);
  1867. X    }
  1868. X    gotoxy(0, olineno);
  1869. X    fl;
  1870. X    }
  1871. X}
  1872. X
  1873. Xstatic char so_buf[512], *so_p;
  1874. Xstatic int so_c, so_l, so_b, so_active = 0;
  1875. X
  1876. Xso_gotoxy(c, l, blank)
  1877. X{
  1878. X    if (!STANDOUT && c >= 0) {
  1879. X    if (l >= 0) gotoxy(c, l);
  1880. X    return 0;
  1881. X    }
  1882. X    
  1883. X    so_active++;
  1884. X    so_c = c;
  1885. X    so_l = l;
  1886. X    so_b = blank;
  1887. X    so_p = so_buf;
  1888. X    *so_p = NUL;
  1889. X
  1890. X    return 1;    /* not really true if not standout & c < 0 */
  1891. X}
  1892. X
  1893. X/*VARARGS*/
  1894. Xso_printf(va_alist)
  1895. Xva_dcl
  1896. X{
  1897. X    va_list ap;
  1898. X    
  1899. X    va_start(ap);
  1900. X    so_vprintf(va_args1toN);
  1901. X    va_end(ap);
  1902. X}
  1903. X
  1904. Xso_vprintf(va_tail)
  1905. Xva_tdcl
  1906. X{
  1907. X    char *fmt;
  1908. X    
  1909. X    fmt = va_arg1(char *);
  1910. X
  1911. X    if (!so_active) {
  1912. X    vprintf(fmt, va_args2toN);
  1913. X    return;
  1914. X    }
  1915. X    
  1916. X    vsprintf(so_p, fmt, va_args2toN);
  1917. X    while (*so_p) so_p++;
  1918. X}
  1919. X
  1920. Xso_end()
  1921. X{
  1922. X    int len;
  1923. X
  1924. X    if (!so_active) return;
  1925. X
  1926. X    if (so_l >= 0) {
  1927. X    
  1928. X    len = so_p - so_buf + two_cookies; 
  1929. X
  1930. X    if (so_c < 0)
  1931. X        so_c = Columns - len - 2;
  1932. X    if (so_c < 0) so_c = 0;
  1933. X
  1934. X    if (len + so_c >= Columns) {
  1935. X        len = Columns - so_c - two_cookies;
  1936. X        so_buf[len] = NUL;
  1937. X    }
  1938. X        
  1939. X    if (cookie_size) {
  1940. X        gotoxy(so_c + len - cookie_size, so_l);
  1941. X        putp(exit_standout_mode);
  1942. X    }    
  1943. X    
  1944. X    gotoxy(so_c, so_l);
  1945. X
  1946. X    }
  1947. X    
  1948. X    if ((so_b & 1) && (!STANDOUT || !cookie_size)) putchar(SP);
  1949. X
  1950. X    if (STANDOUT) putp(enter_standout_mode);
  1951. X    
  1952. X    fputs(so_buf, stdout);
  1953. X    
  1954. X    if (STANDOUT) putp(exit_standout_mode);
  1955. X    
  1956. X    if ((so_b & 2) && (!STANDOUT || !cookie_size)) putchar(SP);
  1957. X
  1958. X    so_active = 0;
  1959. X}
  1960. X
  1961. X
  1962. X/*VARARGS*/
  1963. Xso_printxy(va_alist)
  1964. Xva_dcl
  1965. X{
  1966. X    va_list ap;
  1967. X    int k, l;
  1968. X
  1969. X    va_start(ap);
  1970. X    
  1971. X    k = va_arg1(int);
  1972. X    l = va_arg2(int);
  1973. X    
  1974. X    so_gotoxy(k, l, 0);
  1975. X    so_vprintf(va_args3toN);
  1976. X    so_end();
  1977. X
  1978. X    va_end(ap);
  1979. X}
  1980. X
  1981. Xunderline(on)
  1982. X{
  1983. X    if (cookie_size) return 0;
  1984. X    if (! HAS_CAP(enter_underline_mode)) return 0;
  1985. X    putp(on ? enter_underline_mode : exit_underline_mode);
  1986. X    return 1;
  1987. X}
  1988. X
  1989. Xhighlight(on)
  1990. X{
  1991. X    if (cookie_size) return 0;
  1992. X    if (! HAS_CAP(enter_standout_mode)) return 0;
  1993. X    putp(on ? enter_standout_mode : exit_standout_mode);
  1994. X    return 1;
  1995. X}
  1996. X
  1997. Xstatic int is_raw = 0;
  1998. X
  1999. Xraw()
  2000. X{
  2001. X    if (is_raw) return;
  2002. X
  2003. X#ifdef HAVE_TERMIO
  2004. X    ioctl(0, TCSETAF, &raw_tty);
  2005. X#else
  2006. X    ioctl(0, TIOCSETP, &raw_tty);
  2007. X#endif
  2008. X    is_raw++;
  2009. X}
  2010. X
  2011. Xno_raw()
  2012. X{
  2013. X    if (!is_raw) return 0;
  2014. X
  2015. X#ifdef HAVE_TERMIO
  2016. X    ioctl(0, TCSETAF, &norm_tty);
  2017. X#else
  2018. X    ioctl(0, TIOCSETP, &norm_tty);
  2019. X#endif
  2020. X    is_raw = 0;
  2021. X
  2022. X    return 1;
  2023. X}
  2024. X
  2025. Xflush_input()
  2026. X{
  2027. X#ifdef HAVE_TERMIO
  2028. X    ioctl(0, TCFLSH, 0);
  2029. X#else
  2030. X    ioctl(0, TIOCFLUSH, 0);
  2031. X#endif
  2032. X}
  2033. X    
  2034. Xint enable_stop = 1;
  2035. X
  2036. X#ifndef KEY_BURST
  2037. X
  2038. Xstatic int alarm_on = 0;
  2039. X
  2040. Xstatic mk_timeout()
  2041. X{
  2042. X    alarm_on = 0;
  2043. X}
  2044. X
  2045. X#endif
  2046. X
  2047. Xstatic int do_macro_processing = 1;
  2048. X
  2049. Xget_c()
  2050. X{
  2051. X    unsigned char c;
  2052. X    int any_multi, key_cnt, mc;
  2053. X    register struct multi_key *mk;
  2054. X    register int i;
  2055. X#ifdef KEY_BURST
  2056. X    static char cbuf[KEY_BURST], *cp;
  2057. X    static int n = 0;
  2058. X#else
  2059. X    int n;
  2060. X    unsigned char first_key;
  2061. X#endif
  2062. X
  2063. X next_key:
  2064. X    if (s_hangup)
  2065. X    return K_interrupt;
  2066. X
  2067. X#ifdef RESIZING
  2068. X    if (s_resized) {
  2069. X    s_resized = 0;
  2070. X    return GETC_COMMAND | K_REDRAW;
  2071. X    }
  2072. X#endif
  2073. X    
  2074. X    if (do_macro_processing)
  2075. X    switch (m_getc(&mc)) {
  2076. X     case 0:
  2077. X        break;
  2078. X     case 1:
  2079. X        return mc;
  2080. X     case 2:
  2081. X        return K_interrupt;
  2082. X    }
  2083. X    
  2084. X    for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++)
  2085. X    mk->cur_key = mk->keys;
  2086. X    key_cnt = 0;
  2087. X
  2088. X#ifdef KEY_BURST
  2089. X    if (n <= 0) {
  2090. X    n = read(0, cbuf, KEY_BURST);
  2091. X    if (n < 0 && errno != EINTR) s_hangup++;
  2092. X    if (n <= 0) return K_interrupt;
  2093. X    cp = cbuf;
  2094. X    }
  2095. X    
  2096. X    while (--n >= 0) {
  2097. X    c = *cp++;
  2098. X#else    
  2099. X
  2100. X    while ((n = read(0, &c, 1)) > 0) {
  2101. X    c &= 0177;    /* done by ISTRIP on USG systems */
  2102. X#endif
  2103. X    
  2104. X    if (c == CTRL('Q') || c == CTRL('S'))
  2105. X        continue;
  2106. X    
  2107. X    any_multi = 0;
  2108. X    for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++)
  2109. X        if (mk->cur_key) {
  2110. X        if (*(mk->cur_key)++ == c) {
  2111. X            if (*(mk->cur_key) == NUL) {
  2112. X            c = mk->code;
  2113. X            goto got_char;
  2114. X            }
  2115. X            any_multi++;
  2116. X        } else
  2117. X            mk->cur_key = NULL;
  2118. X        }
  2119. X
  2120. X    if (any_multi) {
  2121. X#ifndef KEY_BURST
  2122. X        if (key_cnt == 0) {
  2123. X        first_key = c;
  2124. X        alarm_on = 1;
  2125. X        signal(SIGALRM, mk_timeout);
  2126. X        MICRO_ALARM();
  2127. X        }
  2128. X#endif
  2129. X        key_cnt++;
  2130. X        continue;
  2131. X    }
  2132. X    if (key_cnt == 0) 
  2133. X        goto got_char;
  2134. X    
  2135. X    ding();
  2136. X    flush_input();
  2137. X    goto next_key;
  2138. X    }
  2139. X
  2140. X#ifndef KEY_BURST
  2141. X    if (n < 0) {
  2142. X    if (errno != EINTR) s_hangup++;
  2143. X    return K_interrupt;
  2144. X    }
  2145. X#endif
  2146. X    
  2147. X#ifdef RESIZING
  2148. X    if (s_resized) {
  2149. X    s_resized = 0;
  2150. X    return GETC_COMMAND | K_REDRAW;
  2151. X    }
  2152. X#endif
  2153. X
  2154. X#ifndef KEY_BURST    
  2155. X    if (n < 0 && key_cnt)
  2156. X    c = first_key;
  2157. X#endif
  2158. X
  2159. Xgot_char:
  2160. X
  2161. X#ifndef KEY_BURST
  2162. X    if (alarm_on) {
  2163. X    alarm(0);
  2164. X    alarm_on = 0;
  2165. X    }
  2166. X#endif
  2167. X    
  2168. X    c = global_key_map[c];
  2169. X    
  2170. X    if (c == SuspC) {
  2171. X    if (!enable_stop) goto next_key;
  2172. X    if (suspend_nn())
  2173. X        return GETC_COMMAND | K_REDRAW;
  2174. X    else
  2175. X        goto next_key;
  2176. X    }
  2177. X
  2178. X    if (c == IntrC) c = K_interrupt;
  2179. X    
  2180. X    return c;
  2181. X}
  2182. X
  2183. X
  2184. X/*
  2185. X * read string with completion, pre-filling, and break on first char
  2186. X *
  2187. X *    dflt        is a string that will be use as default value if the
  2188. X *            space bar is hit as the first character.
  2189. X *
  2190. X *    prefill        pre-fill the buffer with .... and print it
  2191. X *
  2192. X *    break_chars    return immediately if one of these characters
  2193. X *            is entered as the first character.
  2194. X *
  2195. X *    completion     is a function that will fill the buffer with a value
  2196. X *            see the group_completion and file_completion routines 
  2197. X *            for examples.
  2198. X */
  2199. X
  2200. Xchar *get_s(dflt, prefill, break_chars, completion)
  2201. Xchar *dflt, *prefill, *break_chars;
  2202. Xint (*completion)();
  2203. X{
  2204. X    static char buf[GET_S_BUFFER];
  2205. X    register char *cp;
  2206. X    register int i, c, lastc;
  2207. X    char *ret_val = buf;
  2208. X    int comp_used, comp_len;
  2209. X    int ostop, max, did_help;
  2210. X    int hit_count;
  2211. X    
  2212. X    switch (m_gets(buf)) {
  2213. X     case 0:
  2214. X    break;
  2215. X     case 1:
  2216. X    return buf;
  2217. X     case 2:
  2218. X    return NULL;
  2219. X    }
  2220. X    
  2221. X    ostop = enable_stop;
  2222. X    enable_stop = 0;
  2223. X    do_macro_processing = 0;
  2224. X    hit_count = 0;
  2225. X    
  2226. X    max = Columns - prompt_length;
  2227. X    
  2228. X    if (max >= FILENAME) max = FILENAME-1;
  2229. X
  2230. X    i = comp_len = comp_used = did_help = 0;
  2231. X
  2232. X    if (prefill && prefill[0]) {
  2233. X    while (c = *prefill++) {
  2234. X        if (i == max) break;
  2235. X        
  2236. X        putchar(c);
  2237. X        buf[i] = c;
  2238. X        i++;
  2239. X    }
  2240. X    fl;
  2241. X    }        
  2242. X
  2243. X    if (dflt && *dflt == NUL)
  2244. X    dflt = NULL;
  2245. X
  2246. X    if (break_chars && *break_chars == NUL)
  2247. X    break_chars = NULL;
  2248. X
  2249. X    c = NUL;
  2250. X    for(;;) {
  2251. X    lastc = c;
  2252. X    c = get_c();
  2253. X    if (c & (0200 | GETC_COMMAND)) continue;
  2254. X
  2255. X     kill_prefill_hack:
  2256. X
  2257. X    hit_count++;
  2258. X
  2259. X    if (i == 0) {
  2260. X        if (c == comp1_key && dflt) {
  2261. X        while ((c = *dflt++) != NUL && i < max) {
  2262. X            putchar(c);
  2263. X            buf[i] = c;
  2264. X            i++;
  2265. X        }
  2266. X        fl;
  2267. X        dflt = NULL;
  2268. X        continue;
  2269. X        }
  2270. X        if (cp = break_chars) {
  2271. X        while (*cp)
  2272. X            if (*cp++ == c) {
  2273. X            buf[0] = c;
  2274. X            buf[1] = NUL;
  2275. X            goto out;
  2276. X            }
  2277. X        }
  2278. X    }
  2279. X
  2280. X    if (completion != NO_COMPLETION) {
  2281. X        if (comp_used && c == erase_key) {
  2282. X        (*completion)(buf, -1);
  2283. X        if (did_help) { clrmsg(i); did_help = 0; }
  2284. X        if (comp_len) {
  2285. X            i -= comp_len;
  2286. X            while (--comp_len >= 0) putchar(BS);
  2287. X            clrline();
  2288. X        }
  2289. X        comp_len = comp_used = 0;
  2290. X        if (lastc == help_key) goto no_completion;
  2291. X        continue;
  2292. X        }
  2293. X
  2294. X        if (c == comp1_key || c == comp2_key || c == help_key) {
  2295. X        if (!comp_used || c == comp2_key || 
  2296. X            (c == help_key && lastc != c)) {
  2297. X            buf[i] = NUL;
  2298. NO_NEWS_IS_GOOD_NEWS
  2299. echo "End of part 14"
  2300. echo "File term.c is continued in part 15"
  2301. echo "15" > s2_seq_.tmp
  2302. exit 0
  2303. ---
  2304. Kim F. Storm        storm@texas.dk        Tel +45 429 174 00
  2305. Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark
  2306.       No news is good news, but nn is better!
  2307.  
  2308.