home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / MSGDP206.SZH / MSGED.C < prev    next >
Text File  |  1991-01-07  |  25KB  |  1,069 lines

  1. /*
  2.  
  3. Title:  MsgEd
  4.  
  5. File:   Msged.c
  6.  
  7. Author: Jim Nutt
  8.  
  9. Copr:   released into the PUBLIC DOMAIN 30 jul 1990 by jim nutt
  10.  
  11. Description:
  12.  
  13.     Small, fast fido message editor.
  14.  
  15. Support Files:
  16.  
  17.     msged.h
  18.  
  19. */
  20.  
  21. #define MAIN
  22.  
  23. #include "msged.h"
  24. #include "maincmds.h"
  25. #include "bmg.h"
  26.  
  27. #include <process.h>
  28.  
  29. #if defined(__TURBOC__)
  30. #include <dir.h>
  31. #else
  32. #include <direct.h>
  33. #endif
  34.  
  35. #ifdef __ZTC__
  36. #include <dos.h>
  37. static int brk;
  38. #endif
  39.  
  40. unsigned int _vcm_maxres = 0;
  41.  
  42. void    _pascal r_assignkey(unsigned int key, char *label);
  43. char *  _pascal r_getbind(unsigned int key);
  44. char *  _pascal r_getlabels(int i);
  45.  
  46. int     _pascal setcwd(char *path);
  47. static  void _near _pascal set_area(int area);
  48. static  void _near _pascal empty(void);
  49. static  void _near _pascal highest(void);
  50. static  int _near _pascal start(char *, char *);
  51.  
  52. int     direction = RIGHT;
  53.  
  54. static  int     lastfound = 0;
  55. static  int     command;
  56. static  int     root = 0;       /* root message of a thread */
  57. static  int     back = 0;
  58.  
  59. char * _pascal show_address(ADDRESS a)
  60.  
  61. {
  62.     static char s[80];
  63.     char field[20];
  64.  
  65.     memset(s,0,sizeof s);
  66.     memset(field,0,sizeof field);
  67.  
  68.     if (a.notfound) {
  69.         strcpy(s,"unknown address");
  70.         return(s);
  71.     }
  72.  
  73.     if (a.fidonet) {
  74.         if (a.zone) {
  75.             strcat(s,itoa(a.zone,field,10));
  76.             strcat(s,":");
  77.         }
  78.         strcat(s,itoa(a.net,field,10));
  79.         strcat(s,"/");
  80.         strcat(s,itoa(a.node,field,10));
  81.         if (a.point) {
  82.             strcat(s,".");
  83.             strcat(s,itoa(a.point,field,10));
  84.         }
  85.  
  86.         if (a.domain != NULL) {
  87.             strcat(s,"@");
  88.             strcat(s,strlwr(a.domain));
  89.         }
  90.     }
  91.  
  92.     if (a.internet) {
  93.         strncpy(s,a.domain,60);
  94.     }
  95.  
  96.     if (a.bangpath) {
  97.         char *t,*t1;
  98.  
  99.         t1 = strrchr(a.domain,'!');
  100.         if (t1 == NULL)
  101.             strcpy(s,a.domain);
  102.         else {
  103.             *t1 = '\0';
  104.             t = strrchr(a.domain,'!');
  105.             if (!t)
  106.                 t = a.domain;
  107.             *t1 = '!';
  108.             strcat(strcpy(s,"..."),t);
  109.         }
  110.  
  111.     }
  112.  
  113.     return(s);
  114. }
  115.  
  116. static void _near _pascal delete()
  117.  
  118. {
  119.     deletemsg();
  120. }
  121.  
  122. static void _near _pascal doreply()
  123.  
  124. {
  125.     reply();
  126. }
  127.  
  128. static void _near _pascal doquote()
  129.  
  130. {
  131.     quote();
  132. }
  133.  
  134. static void _near _pascal move()
  135.  
  136. {
  137.     movemsg();
  138. }
  139.  
  140. static void _near _pascal outtxt()
  141.  
  142. {
  143.     writetxt();
  144. }
  145.  
  146. static void _near _pascal set()
  147.  
  148. {
  149.     settings();
  150. }
  151.  
  152. static void _near _pascal new()
  153.  
  154. {
  155.     newmsg();
  156. }
  157.  
  158. static void _near _pascal dochange()
  159.  
  160. {
  161.     change();
  162. }
  163.  
  164. char *  _pascal r_getbind(unsigned int key)
  165.  
  166. {
  167.     unsigned int i = 0;
  168.     void (_near _pascal *action)();
  169.  
  170.     if (key & 0xff)
  171.         action = mainckeys[key & 0xff];
  172.     else
  173.         action = mainakeys[(key >> 8) & 0xff];
  174.  
  175.     while ((maincmds[i].label != NULL) &&
  176.            (action != maincmds[i].action))
  177.         i++;
  178.  
  179.     return(maincmds[i].label);
  180.  
  181. }
  182.  
  183. char *  _pascal r_getlabels(int i)
  184.  
  185. {
  186.     return(maincmds[i].label);
  187. }
  188.  
  189. void    _pascal r_assignkey(unsigned int key, char *label)
  190.  
  191. {
  192.     unsigned int i = 0;
  193.  
  194.     while ((maincmds[i].label != NULL) &&
  195.            (strncmp(maincmds[i].label,label,strlen(maincmds[i].label)) != 0))
  196.         i++;
  197.  
  198.     if (maincmds[i].label != NULL)
  199.         if (key & 0xff)
  200.             mainckeys[key & 0xff] = maincmds[i].action;
  201.         else
  202.             mainakeys[(key >> 8) & 0xff] = maincmds[i].action;
  203. }
  204.  
  205. ADDRESS _pascal parsenode(char *t)
  206.  
  207. {
  208.     ADDRESS tmp;
  209.     char *t1 = t;
  210.     int  n = 0;
  211.     int point = 0;
  212.  
  213.     tmp = thisnode; /* msc doesn't allow auto struct initializers */
  214.     tmp.point = tmp.notfound = 0;
  215.     tmp.fidonet = 1;
  216.     tmp.internet = 0;
  217.     tmp.bangpath = 0;
  218.     if (thisnode.domain != NULL)
  219.         tmp.domain = strdup(thisnode.domain);
  220.  
  221.     if (t == NULL) {
  222.         tmp.notfound = 1;
  223.         return(tmp);
  224.     }
  225.  
  226.     while (isspace(*t)) t++;
  227.     if (!isdigit(*t)) {
  228.         tmp.notfound = 1;
  229.         tmp.fidonet = 0;
  230.         tmp.internet = 0;
  231.         tmp.bangpath = 0;
  232.         return(tmp);
  233.     }
  234.  
  235.     while (t1) {
  236.         n = (int) strtol(t1,&t1,10);
  237.         if (t1 == NULL) {
  238.             if (point) tmp.point = n;
  239.             else tmp.node = n;
  240.             if (tmp.zone == 0) tmp.zone = thisnode.zone;
  241.             return(tmp);
  242.         }
  243.         switch (*t1) {
  244.  
  245.             case ')' :
  246.             case ' ' :
  247.             case '\0':
  248.                 if (point) tmp.point = n;
  249.                 else tmp.node = n;
  250.                 if (tmp.zone == 0) tmp.zone = thisnode.zone;
  251.                 return(tmp);
  252.  
  253.             case ':' :
  254.                 tmp.zone = n;
  255.                 break;
  256.  
  257.             case '/' :
  258.                 tmp.net = n;
  259.                 break;
  260.  
  261.             case '.' :
  262.                 tmp.node = n;
  263.                 point = 1;
  264.                 break;
  265.  
  266.             case '@' :
  267.                 if (point) tmp.point = n;
  268.                 else tmp.node = n;
  269.                 if (tmp.domain != NULL) free(tmp.domain);
  270.                 tmp.domain = strdup(t1+1);
  271.                 if (strchr(tmp.domain,' ')) *strchr(tmp.domain,' ') = '\0';
  272.                 if (tmp.zone == 0) tmp.zone = thisnode.zone;
  273.                 return(tmp);
  274.         }
  275.         t1++;
  276.     }
  277.  
  278.     if (tmp.zone == 0) tmp.zone = thisnode.zone;
  279.     return(tmp);
  280. }
  281.  
  282. void _pascal dispose(MSG *message)
  283.  
  284. {
  285.     if (message == NULL)
  286.         return;
  287.  
  288.     if (message->text != NULL)
  289.         message->text = clearbuffer(message->text);
  290.     release(message->isto);
  291.     release(message->isfrom);
  292.     release(message->reply);
  293.     release(message->subj);
  294.     release(message->to.domain);
  295.     release(message->from.domain);
  296.     release(message);
  297. }
  298.  
  299. static void _near _pascal quit()
  300.  
  301. {
  302.     cleanup();
  303. }
  304.  
  305. void _pascal cleanup()
  306. {
  307. #ifdef _OS2_
  308.     int errorlevel = 0;
  309. #else
  310.     unsigned char errorlevel = 0;
  311. #endif
  312.     FILE   *fp;
  313.     AREA *a;
  314.  
  315.     highest();
  316.     msg_last(arealist[area]);
  317.  
  318.     setcwd(home);
  319. #ifdef __ZTC__
  320.     dos_set_ctrl_break(brk);
  321. #endif
  322.  
  323.     cls();
  324.  
  325.     video_end();
  326.  
  327.     if (*confmail == '+')
  328.         fp = fopen(confmail+1,"at");
  329.     else
  330.         fp = fopen(confmail, "wt");
  331.  
  332.     for (a = &(arealist[area = 0]); area < areas; a = &(arealist[++area])) {
  333.         errorlevel |= (a->netmail && a->new)? 0x01:0;
  334.         errorlevel |= (a->echomail && a->new)?0x02:0;
  335.         errorlevel |= (a->uucp && a->new)?    0x04:0;
  336.         errorlevel |= (a->news && a->new)?    0x08:0;
  337.         errorlevel |= (a->local && a->new)?   0x10:0;
  338.  
  339.         if (a->echomail && a->new)
  340.             fprintf(fp, "%s\n", a->tag);
  341.     }
  342.  
  343.     printf("\nexiting with errorlevel %d\n",errorlevel);
  344.  
  345.     if (messages)
  346.         free(messages);
  347.  
  348.     if (arealist)
  349.         handle_free(arealist);
  350.  
  351. #ifdef _OS2_
  352.     fclose(fp);
  353. #else
  354.     fcloseall();
  355. #endif
  356.  
  357.     exit(errorlevel);
  358. }
  359.  
  360. void _pascal outamemory()
  361. {
  362.     fprintf(stderr, "\ni've run out of memory!  aborting....\n");
  363.     cleanup();
  364. }
  365.  
  366. static void _near _pascal empty()
  367.  
  368. {
  369.     arealist[area].last = arealist[area].current = arealist[area].first = 0;
  370.     cls();
  371.     gotoxy(3, maxy / 2);
  372.     set_color(co_hilite);
  373.     bprintf("%s is empty!",arealist[area].description);
  374.     set_color(co_normal);
  375. }
  376.  
  377. static void _near _pascal search()
  378.  
  379. {
  380.     char   *t = NULL;
  381.     int     tmp = 0;
  382.     MSG    *m;
  383.  
  384.     static  bmgARG pattern;
  385.     static  char prompt[bmgMAXPAT];
  386.     static  char patstr[bmgMAXPAT];
  387.  
  388.     gotoxy(9, 1);
  389.     clreol();
  390.     set_color(co_info);
  391.     bputs("Find: ");
  392.     set_color(co_normal);
  393.     bgets(prompt,sizeof(prompt)-1,sizeof(prompt)-1);
  394.  
  395.     if (strlen(prompt) == 0)
  396.         return;
  397.  
  398.     if (strcmpl(prompt,patstr) == 0)
  399.         tmp = lastfound + 1;
  400.     else {
  401.         tmp = arealist[area].current;
  402.         lastfound = 0;
  403.         memset(patstr,0,sizeof(patstr));
  404.         memset(&pattern,0,sizeof(bmgARG));
  405.         strncpy(patstr,prompt,sizeof(prompt));
  406.         bmgCompile(patstr,&pattern,TRUE);
  407.     }
  408.  
  409.     gotoxy(9,1);
  410.     clreol();
  411.     set_color(co_info);
  412.     for (;tmp < arealist[area].messages; tmp++) {
  413.         if (keyhit() && (getkey() == ABORT)) {
  414.             msg_readtext(-1);
  415.             return;
  416.         }
  417.  
  418.         if ((m = msg_readheader(msgnum(tmp))) != NULL) {
  419.             gotoxy(9,1);
  420.             bprintf("Looking at #%d for \"%s\"",msgnum(tmp),prompt);
  421.             if (bmgSearch(m->isto,strlen(m->isto),&pattern) != NULL) {
  422.                 lastfound = tmp;
  423.                 set_color(co_normal);
  424.                 arealist[area].current = tmp;
  425.                 msg_readtext(-1);
  426.                 return;
  427.             }
  428.  
  429.             if (bmgSearch(m->isfrom,strlen(m->isfrom),&pattern) != NULL) {
  430.                 lastfound = tmp;
  431.                 set_color(co_normal);
  432.                 arealist[area].current = tmp;
  433.                 msg_readtext(-1);
  434.                 return;
  435.             }
  436.  
  437.             if (bmgSearch(m->subj,strlen(m->subj),&pattern) != NULL) {
  438.                 lastfound = tmp;
  439.                 set_color(co_normal);
  440.                 arealist[area].current = tmp;
  441.                 msg_readtext(-1);
  442.                 return;
  443.             }
  444.  
  445.             while ((t = msg_readtext(msgnum(tmp))) != NULL) {
  446.                 if (bmgSearch(t,strlen(t),&pattern) != NULL) {
  447.                     lastfound = tmp;
  448.                     set_color(co_normal);
  449.                     if (t) free(t);
  450.                     arealist[area].current = tmp;
  451.                     msg_readtext(-1);
  452.                     return;
  453.                 }
  454.                 if (t) free(t);
  455.                 t = NULL;
  456.             }
  457.         }
  458.     }
  459.     msg_readtext(-1);
  460.     set_color(co_normal);
  461. }
  462.  
  463. int _pascal confirm()
  464.  
  465. {
  466.     int ch;
  467.  
  468.     if (!(confirmations))                                  /*WRA*/
  469.         return(TRUE);
  470.  
  471.     gotoxy(9,1);
  472.     clreol();
  473.     set_color(co_warn);
  474.     bputs("*warning* ");
  475.     bputs("do you really want to do this? (y/n) ");
  476.     video_update();
  477.  
  478.     do {
  479.         ch = getkey() & 0x7f;
  480.         ch = tolower(ch);
  481.  
  482.     } while ((ch != 'y') && (ch != 'n'));
  483.  
  484.     bputc((char) ch);
  485.     set_color(co_normal);
  486.     return(ch == 'y');
  487. }
  488.  
  489. static void _near _pascal rundos()
  490.  
  491. {
  492.     char tmp[PATHLEN];
  493.     char cmd[64];
  494.  
  495.     getcwd(tmp,PATHLEN);
  496.     memset(cmd,0,sizeof cmd);
  497.     gotoxy(9,1);
  498.     clreol();
  499.     set_color(co_info);
  500.     bputs("DOS command: ");
  501.     bgets(cmd,63,63);
  502. #ifdef __ZTC__
  503.     if (swapping) swap_on();
  504.     else swap_off();
  505. #endif
  506.     cls();
  507.     system(cmd);
  508. #ifdef __ZTC__
  509.     if (!swapping) swap_on();
  510.     else swap_off();
  511. #endif
  512.     maxx = maxy = 0;
  513.     video_init();
  514.     if (rm > maxx)
  515.         rm = maxx;
  516.     puts("\nPress any key to return to msged.");
  517.     getkey();
  518.     setcwd(tmp);
  519. }
  520.  
  521. static  void _near _pascal set_area(int area)
  522.  
  523. {
  524.     lastfound = 1;
  525.     arealist[area].messages = msg_scan((&(arealist[area])));
  526.     direction = RIGHT;
  527.     back = root = 0;
  528.     back = root = arealist[area].current;
  529.     dispose(message);
  530.     message = NULL;
  531. }
  532.  
  533. void _pascal areascan()
  534.  
  535. {
  536.     scan_areas();
  537. }
  538.  
  539. static void _near _pascal scan_areas()
  540.  
  541. {
  542.     int a = 0;
  543.  
  544.     highest();
  545.     msg_last(arealist[area]);
  546.     set_color(co_warn);
  547.     for (;a < areas; a++) {
  548.         gotoxy(9,1);
  549.         clreol();
  550.         video_update();
  551.         bprintf("scanning %s for new mail (<esc> to interrupt)",arealist[a].description);
  552.         if (keyhit() && (getkey() == ABORT))
  553.             break;
  554.         else
  555.             arealist[a].messages = msg_scan((&arealist[a]));
  556.     }
  557.  
  558.     set_color(co_normal);
  559.     scanned = 1;
  560.     arealist[area].messages = msg_scan((&arealist[area]));
  561. }
  562.  
  563. static void _near _pascal next_area()
  564.  
  565. {
  566.     int oarea = area;
  567.  
  568.     override = FALSE;
  569.     if (areas < 2)
  570.         return;
  571.     highest();
  572.     msg_last(arealist[area]);
  573.     if (scanned) {
  574.         area = (area + 1) % areas;
  575.         while ((arealist[area].messages - arealist[area].lastread - 1) <= 0) {
  576.             area = (area + 1) % areas;
  577.             if (area == oarea) {
  578.                 area = (area + 1) % areas;
  579.                 break;
  580.             }
  581.         }
  582.     }
  583.     else
  584.         area = (area + 1) % areas;
  585.     set_area(area);
  586. }
  587.  
  588. static void _near _pascal prev_area()
  589.  
  590. {
  591.     int oarea = area;
  592.  
  593.     override = FALSE;
  594.     if (areas < 2)
  595.         return;
  596.     highest();
  597.     msg_last(arealist[area]);
  598.     if (scanned) {
  599.         area--;
  600.         area = (area < 0)?areas-1:area;
  601.         while ((arealist[area].messages - arealist[area].lastread - 1) <= 0) {
  602.             area--;
  603.             area = (area < 0)?areas-1:area;
  604.             if (area == oarea) {
  605.                 area--;
  606.                 area = (area < 0)?areas-1:area;
  607.                 break;
  608.             }
  609.         }
  610.     }
  611.     else {
  612.         area--;
  613.         area = (area < 0)?areas-1:area;
  614.     }
  615.     set_area(area);
  616. }
  617.  
  618. static void _near _pascal highest()
  619.  
  620. {
  621.     arealist[area].lastread = min(max(arealist[area].lastread,arealist[area].current),arealist[area].messages-1);
  622.     root = arealist[area].current;
  623. }
  624.  
  625.  
  626. static void _near _pascal left()
  627.  
  628. {
  629.     back = arealist[area].current;
  630.     direction = LEFT;
  631.  
  632.     if (arealist[area].current > 0)
  633.         arealist[area].current--;
  634.  
  635.     root = arealist[area].current;
  636. }
  637.  
  638. static void _near _pascal right()
  639.  
  640. {
  641.     back = arealist[area].current;
  642.     direction = RIGHT;
  643.  
  644.     if (arealist[area].current < (arealist[area].messages-1))
  645.         arealist[area].current++;
  646.  
  647.     highest();
  648. }
  649.  
  650. static void _near _pascal gotomsg(int i)
  651.  
  652. {
  653.     gotoxy(9, 1);
  654.     clreol();
  655.     set_color(co_info);
  656.     bputs("Goto Message #? ");
  657.     set_color(co_normal);
  658.     back = arealist[area].current;
  659.     i = getnum(0, arealist[area].messages, i);
  660.     if (i == 0)
  661.         return;
  662.     arealist[area].current = i-1;
  663.     highest();
  664. }
  665.  
  666.  
  667. static void _near _pascal newarea()
  668.  
  669. {
  670.     override = FALSE;
  671.     if (areas < 2)
  672.         return;
  673.     highest();
  674.     msg_last(arealist[area]);
  675.     area = selectarea();
  676.     set_area(area);
  677. }
  678.  
  679. static int _near _pascal start(char *cfg, char *afn)
  680.  
  681. {
  682.     opening(cfg,afn);
  683.  
  684.     area = 0;
  685.  
  686.     arealist[area].messages = msg_scan(&(arealist[area]));
  687.  
  688.     gotoxy(6, maxy);
  689.     bputs("Press any key to continue....");
  690.     getkey();
  691.  
  692.     if (arealist[area].messages > 0) {
  693.         if ((message = readmsg(msgnum(arealist[area].current))) != NULL)
  694.             return showmsg(message);
  695.     }
  696.     else
  697.         return 0x1e00;
  698.  
  699.     return 0x1e00;
  700. }
  701.  
  702. static void _near _pascal go_last()
  703.  
  704. {
  705.     arealist[area].current = min(arealist[area].lastread, arealist[area].messages-1);
  706.     root = arealist[area].current;
  707. }
  708.  
  709. static void _near _pascal link_from()
  710.  
  711. {
  712.     int t;
  713.     if (!message->replyto)
  714.         return;
  715.  
  716.     back = arealist[area].current;
  717.     for (t = arealist[area].current; (t > -1) && ((unsigned) msgnum(t) != message->replyto); t--)
  718.         /* null statement */ ;
  719.     if (t > -1)
  720.         arealist[area].current = t;
  721. }
  722.  
  723. static void _near _pascal view()
  724.  
  725. {
  726.     shownotes = !shownotes;
  727.     seenbys = shownotes;
  728. }
  729.  
  730. static void _near _pascal link_to()
  731.  
  732. {
  733.     int t;
  734.     if (!message->replyfrom)
  735.         return;
  736.     back = arealist[area].current;
  737.     for (t = arealist[area].messages - 1; (t > arealist[area].current) && ((unsigned) msgnum(t) != message->replyfrom); t--)
  738.         /* null statement */;
  739.     if (t > arealist[area].current)
  740.         arealist[area].current = t;
  741.  
  742.     arealist[area].lastread = max(arealist[area].lastread,arealist[area].current);
  743. }
  744.  
  745. static void _near _pascal go_root()
  746.  
  747. {
  748.     back = arealist[area].current;
  749.     arealist[area].current = root;
  750.     highest();
  751. }
  752.  
  753. static void _near _pascal rotate()
  754.  
  755. {
  756.     rot13 = (rot13 + 1) % 3;
  757. }
  758.  
  759. static void _near _pascal go_dos()
  760.  
  761. {
  762.     char tmp[PATHLEN];
  763.  
  764.     getcwd(tmp,PATHLEN);
  765.     setcwd(home);
  766.     cls();
  767.     fputs("\nType EXIT to return to msged.\n",stderr);
  768. #ifdef __ZTC__
  769.     if (!swapping) swap_off();
  770.     else swap_on();
  771. #endif
  772.     spawnl(0,comspec,comspec,NULL);
  773. #ifdef __ZTC__
  774.     if (swapping) swap_off();
  775.     else swap_on();
  776. #endif
  777.     maxx = maxy = 0;
  778.     video_init();
  779.     if (rm > maxx)
  780.         rm = maxx;
  781.     setcwd(tmp);
  782. }
  783.  
  784. static void _near _pascal nada()
  785.  
  786. {
  787. }
  788.  
  789. typedef struct _mlhead {
  790.     int n;
  791.     char to_name[37];
  792.     int  to_net;
  793.     int  to_node;
  794.     char fr_name[37];
  795.     int  fr_net;
  796.     int  fr_node;
  797.     char subj[73];
  798. } MLHEAD;
  799.  
  800. static void _near _pascal update(MLHEAD *headers, int n,int y);
  801. static void _near _pascal showit(MLHEAD *h);
  802. static void _near _pascal getheader(int n, MLHEAD *h);
  803.  
  804. static  char    tmp[16];
  805. static  int     f = 1;
  806.  
  807. void _near _pascal list()
  808.  
  809. {
  810.     MLHEAD *headers = NULL;
  811.     int i = 0, y = 0, ch = 0, a = 0;
  812.     char   *s = NULL;
  813.     static int inlist = 0;
  814.  
  815.     if (inlist) return;
  816.     else inlist = 1;
  817.  
  818.     cls();
  819.     sprintf(tmp,"%%-%d.%ds",maxx,maxx);
  820.     i = a = arealist[area].current;
  821.     highest();
  822.     headers = (MLHEAD *) calloc((maxy+1),sizeof(MLHEAD));
  823.     if (headers == NULL) outamemory();
  824.  
  825.     y = 1;
  826.  
  827.     update(headers,i,y);
  828.  
  829.     ch = 0;
  830.     y = 1;
  831.  
  832.     while ((ch != ENTER) && (ch != ABORT) && arealist[area].messages) {
  833.         gotoxy(1, y);
  834.         clreol();
  835.         set_color(co_hilite);
  836.         showit(&headers[y-1]);
  837.         set_color(co_normal);
  838.  
  839.         switch (ch = getkey()) {
  840.  
  841.             case 0x1e00 :
  842.                 f = !f;
  843.                 y = 1;
  844.                 update(headers,a,y);
  845.                 break;
  846.  
  847.             case PGDN:
  848.                 i = maxy;
  849.                 while ((i > 1) && (a < (arealist[area].messages-1))) {
  850.                     i--;
  851.                     a++;
  852.                 }
  853.                 y = 1;
  854.                 update(headers,a,y);
  855.                 break;
  856.  
  857.                 case PGUP:
  858.                     i = maxy;
  859.                     while ((i > 1) && (a > 0)) {
  860.                         i--;
  861.                         a--;
  862.                     }
  863.                     y = 1;
  864.                     update(headers,a,y);
  865.                     break;
  866.  
  867.             case UP:
  868.                 if (a > 0) {
  869.                     gotoxy(1, y);
  870.                     clreol();
  871.                     if (strcmpl(headers[y-1].to_name,username) == 0)
  872.                         set_color(co_info);
  873.                     else
  874.                         set_color(co_normal);
  875.  
  876.                     showit(&headers[y-1]);
  877.                     a--;
  878.                     y--;
  879.  
  880.                     if (y < 1) {
  881.                         y = 1;
  882.                         scrolldown(1, 1, maxx, maxy, 1);
  883.                         memmove((headers + 1),headers,(sizeof(MLHEAD) * maxy));
  884.                         getheader(msgnum(a), &headers[0]);
  885.                         s = strchr(headers[0].fr_name,'\n');
  886.                         if (s != NULL)
  887.                             *s = '\0';
  888.                         s = strchr(headers[0].to_name,'\n');
  889.                         if (s != NULL)
  890.                             *s = '\0';
  891.                     }
  892.                 }
  893.                 break;
  894.  
  895.             case DOWN:
  896.                 if (a < (arealist[area].messages-1)) {
  897.                     gotoxy(1, y);
  898.                     clreol();
  899.                     if (strcmpl(headers[y-1].to_name,username) == 0)
  900.                         set_color(co_info);
  901.                     else
  902.                         set_color(co_normal);
  903.  
  904.                     showit(&headers[y-1]);
  905.                     a++;
  906.                     y++;
  907.  
  908.                 if (y > maxy) {
  909.                     y = maxy;
  910.                     scrollup(1, 1, maxx, maxy, 1);
  911.                     memmove(headers,(headers + 1),sizeof(MLHEAD) * (maxy+1));
  912.                     getheader(msgnum(a), &headers[maxy-1]);
  913.                     s = strchr(headers[maxy - 1].fr_name,'\n');
  914.                     if (s != NULL)
  915.                         *s = '\0';
  916.                     s = strchr(headers[maxy - 1].to_name,'\n');
  917.                     if (s != NULL)
  918.                         *s = '\0';
  919.                     }
  920.                 }
  921.                 break;
  922.  
  923.                 case ENTER:
  924.                     arealist[area].current = a;
  925.                     dispose(message);
  926.                     message = readmsg(messages[a]);
  927.                     free(headers);
  928.                     inlist = 0;
  929.                     return;
  930.  
  931.                 case ABORT:
  932.                     free(headers);
  933.                     inlist = 0;
  934.                     return;
  935.  
  936.                    default:
  937.                     arealist[area].current = a;
  938.                     if (ch & 0xff) {
  939.                         if (isdigit(ch))
  940.                             gotomsg(ch - 0x30);
  941.                         else if (mainckeys[ch])
  942.                             mainckeys[ch & 0xff]();
  943.                     }
  944.                     else if (mainakeys[ch >> 8])
  945.                         mainakeys[ch >> 8]();
  946.  
  947.                     i = a = arealist[area].current;
  948.                     update(headers,i,y=1);
  949.         }
  950.     }
  951. }
  952.  
  953. static void _near _pascal update(MLHEAD *headers, int i,int y)
  954.  
  955. {
  956.     char *s = NULL;
  957.  
  958.         clrwnd(1,y,maxx,maxy);
  959.         while ((i <= (arealist[area].messages-1)) && (y <= maxy)) {
  960.                 gotoxy(1,y);
  961.         getheader(msgnum(i), &headers[y-1]);
  962.         s = strchr(headers[y - 1].fr_name,'\n');
  963.         if (s != NULL)
  964.             *s = '\0';
  965.         s = strchr(headers[y - 1].to_name,'\n');
  966.         if (s != NULL)
  967.             *s = '\0';
  968.  
  969.         if (strcmpl(headers[y-1].to_name,username) == 0)
  970.             set_color(co_info);
  971.         else
  972.             set_color(co_normal);
  973.  
  974.         showit(&headers[y-1]);
  975.                 i++;
  976.                 y++;
  977.     }
  978.  
  979. }
  980.  
  981. static void _near _pascal showit(MLHEAD *h)
  982.  
  983. {
  984.     char    line[256];
  985.  
  986.     if (f && arealist[area].netmail)
  987.         sprintf(line,"%4d: %-15.15s@%5d/%-5d to %-15.15s@%5d/%-5d RE: %-70s",
  988.             h->n, h->fr_name,h->fr_net,h->fr_node,
  989.             h->to_name,h->to_net,h->to_node, h->subj);
  990.     else
  991.         sprintf(line,"%4d: %-15.15s to %-15.15s RE: %-70s",
  992.             h->n,h->fr_name,h->to_name,h->subj);
  993.     bprintf(tmp,line);
  994. }
  995.  
  996. static void _near _pascal getheader(int n, MLHEAD *h)
  997.  
  998. {
  999.     MSG *i = NULL;
  1000.  
  1001.     i = msg_readheader(n);
  1002.     memset(h,0,sizeof(MLHEAD));
  1003.     if (i == NULL) return;
  1004.  
  1005.     h->n = i->msgnum;
  1006.     h->to_net = i->to.net;
  1007.     h->to_node = i->to.node;
  1008.     h->fr_net = i->from.net;
  1009.     h->fr_node = i->from.node;
  1010.     strncpy(h->subj,i->subj,72);
  1011.     strncpy(h->to_name,i->isto,36);
  1012.     strncpy(h->fr_name,i->isfrom,36);
  1013.     dispose(i);
  1014. }
  1015.  
  1016.  
  1017. void _cdecl main(int argc, char *argv[])
  1018.  
  1019. {
  1020.     messages = NULL;
  1021.     arealist = NULL;
  1022.  
  1023. #ifdef __ZTC__
  1024.     brk = dos_get_ctrl_break();
  1025.     dos_set_ctrl_break(0);
  1026. #endif
  1027.  
  1028.     if ((argc > 1) && (argc < 3))
  1029.         command = start(argv[1],NULL);
  1030.     else if (argc > 1)
  1031.         command = start(argv[1],argv[2]);
  1032.     else
  1033.         command = start(NULL,NULL);
  1034.  
  1035.     for (;;) {          /* endless loop... exit is through cleanup */
  1036.  
  1037.         if (command & 0xff) {
  1038.             if (isdigit(command))
  1039.                 gotomsg(command - 0x30);
  1040.             else if (mainckeys[command])
  1041.                 mainckeys[command & 0xff]();
  1042.         }
  1043.         else if (mainakeys[command >> 8])
  1044.             mainakeys[command >> 8]();
  1045.  
  1046.         if (arealist[area].messages < 1) {
  1047.             empty();
  1048.             command = getkey();
  1049.         }
  1050.         else {
  1051.             dispose(message);
  1052.             message = NULL;
  1053.  
  1054.             while ((message = readmsg(msgnum(arealist[area].current))) == NULL)
  1055.                 if ((direction == RIGHT) && (arealist[area].current > 0))
  1056.                     arealist[area].current--;
  1057.                 else if (arealist[area].current < arealist[area].last)
  1058.                     arealist[area].current++;
  1059.                 else {
  1060.                     empty();
  1061.                     command = getkey();
  1062.                     continue;
  1063.                 }
  1064.  
  1065.             command = showmsg(message);
  1066.         }
  1067.     }
  1068. }
  1069.