home *** CD-ROM | disk | FTP | other *** search
/ PDA Software Library / pdasoftwarelib.iso / PSION / COMMS / PSIONMAI / PMFULLSO / MAILRDR / MAIL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  47.8 KB  |  1,716 lines

  1. /* start of include files */
  2. #include <plib.h>
  3. #include <wlib.h>
  4. #include <hwif.h>
  5.  
  6. /* end of include files */
  7.  
  8. /* start of structure definitions */
  9.  
  10. /* initial data */
  11. struct mydata {
  12.     TEXT myaddr[50] ;
  13.     TEXT mypath[P_FNAMESIZE] ;
  14.     } ;
  15. /* how large should the header lines be */
  16. #define HDRLEN 100    
  17. /* linked list data definitions */
  18. struct ll {
  19.    TEXT datafile[13] ; /* <name>.<ext>\0 where name is upto 8 chars and ext is 3 chars, total 11 plis the . and the \0 gives 13 */
  20.    TEXT to[HDRLEN] ;
  21.    TEXT from[HDRLEN] ;
  22.    TEXT subject[HDRLEN] ;
  23.    TEXT cc[HDRLEN] ;
  24.    TEXT bcc[HDRLEN] ;
  25.    INT status ;
  26.    INT read ;
  27.    INT no ;
  28.    INT count ;
  29.    struct mydata * mydata ;
  30.    struct ll * next ;
  31.    } ;
  32.  
  33. /* end of struct definitions */
  34.  
  35.  
  36. /* start of defines */
  37.  
  38. /* #define RUNONSUN */
  39.  
  40. /* list printing definitions */
  41. #define PDATAFILE 0x1
  42. #define PTO 0x2
  43. #define PFROM 0x4
  44. #define PSUBJECT 0x8
  45. #define PCC 0x10
  46. #define PBCC 0x20
  47. #define PSTATUS 0x40
  48. #define PREAD 0x80
  49. #define PNO 0x100
  50. #define PCOUNT 0x200
  51. #define PACTIVE 0x400
  52. #define PIGNORE 0x800
  53. #define PDELETED 0x1000
  54. /* general defines */
  55. #define TRUE 1
  56. #define FALSE 0
  57. #define FILEERR -1
  58. #define MEMERR -2
  59. #define IERR -3
  60.  
  61. /* locations of the meta files */
  62. #define METAIN "LOC::M:\\MAILDIR\\IN.MTA"
  63. #define METAOUT "LOC::M:\\MAILDIR\\OUT.MTA"
  64.  
  65. /* location of the word app */
  66. #define MAILRDRCMD "ROM::WORD.APP"
  67. /* the name to match the name on the system screen
  68.    as this is compiled into the alias file it is probabaly not something you
  69.    will change unless you also rename the mailrdr.ma and mailrdr.pic files
  70.    as well as changing the mailrdr.ma file */
  71. #define MAILRDRNAME "Mailrdr"
  72. #define MAILRDREXT ".msg"
  73. /* default name for output files */
  74. #define OUTSKELETON "OUT%d.MSG"
  75.  
  76. /* max line length */
  77. #define MAXLINE 1024
  78. /* ll status values */
  79. #define ACTIVE 0
  80. #define IGNORE -1
  81. #define DELETED -2
  82. /* ll new / read */
  83. #define RD -1
  84. #define NEW -2
  85.  
  86.  
  87. /* max number of outgoing emails */
  88. #define MAXEMAILOUT 100
  89.  
  90. /* stuff relating to the number of lines in the header window */
  91. #define ITEMS_ON_SCREEN 5
  92. #define ITEMS_ON_HALF_SCREEN 2
  93.  
  94. /* how much to increase the y location when printing the headers */
  95. #define HDRINCR 11
  96.  
  97. /* End of defines */
  98.  
  99. /* Start of Global data */
  100.  
  101. /* pointers to the in and out list and the list we are currently working on */
  102. struct ll * inlist ;
  103. struct ll * outlist ;
  104. struct ll * currlist ;
  105.  
  106. /* menu stuff, first define the commands array */
  107. LOCAL_D TEXT *cmds[]= {
  108.     "vView Current", /* these will go under the Current Functions submenu */
  109.     "dDelete Current",
  110.     "uUndelete Current",
  111.     "mModify Header",
  112.     "nNew Email", /* these will go under the Compose submenu */
  113.     "rReply to sender",
  114.     "aReply to all",
  115.     "xExit and save state", /* these will go under the special menu */
  116.     "cExit and lose state",
  117.     "sSwitch between lists",
  118.     NULL };
  119. /* this defines how the commands menu will be presented */
  120. LOCAL_D H_MENU_DATA mdata[] = {
  121.     "Current Email", 4,
  122.     "Compose",3,
  123.     "Special",3,
  124.     NULL };
  125.     
  126. /* pointers to the arrays. DO NOT CHANGE THESE NAMES OR DEFINITIONS as they
  127.    are used by the psion ROM to do menus etc. */
  128. GLDEF_D TEXT ** _cmds=(&cmds[0]) ;
  129. GLDEF_D H_MENU_DATA * _mdata=(&mdata[0]) ;
  130. /* the current mail number */
  131. INT mailno ; 
  132.  
  133. /* the main window */
  134. UINT MainWid ;
  135.  
  136. /* the status window */
  137. W_WINDATA wdstatus ;
  138. UINT gcstatus ;
  139. G_GC gdstatus ;
  140. INT winstatus ;
  141. /* the headers window */
  142. W_WINDATA wdhdr ;
  143. UINT gchdr ;
  144. G_GC gdhdr ;
  145. INT winhdr ;
  146.  
  147. /* used to remove waste from the end of a line */
  148. TEXT * blank = "                                       " ;
  149.  
  150. /* End of Global data */
  151.  
  152. /* Start of function definitions */
  153.  
  154. /* main and top level functions */
  155. VOID main(VOID);
  156. VOID doword(TEXT * fname) ;
  157. VOID initwins(VOID) ;
  158. VOID initmywins(VOID) ;
  159. VOID dogreet(VOID) ;
  160. INT initlist(VOID) ;
  161. INT mainloop(VOID) ;
  162. INT dotidy(VOID) ;
  163. VOID shutwins(VOID) ;
  164. LOCAL_C VOID ManageCommand(INT keycode) ; /* decide what to do with a command */
  165. /* these functions relate to the window stuff */
  166. VOID statusmsg(TEXT * str) ;
  167. VOID redolist(VOID) ;
  168. INT askincl(VOID) ; /* ask if we want to include the current email */
  169. /* the following relate to the commands for modifying the mailbox in view */
  170. VOID readmail(INT mailno, struct ll * llptr) ; /* bring up a viewer */
  171. VOID wrtemail(INT mailno, struct ll * llptr) ; /* wtite / reply */
  172. VOID delmail (INT mailno, struct ll * llptr) ; /* delete the mail from the internal linked lists */
  173. VOID udelmail (INT mailno, struct ll * llptr) ; /* undelete the mail from the internal linked lists */
  174.  
  175. /* stuff for starting / other processes */
  176. INT buildcmd(TEXT cmdbyte, TEXT * appname, TEXT * appext, TEXT * appalias, TEXT * fname, TEXT * cmdline) ;
  177. INT runcmd(TEXT * appname, TEXT * cmdline, INT cmdlen) ;
  178.  
  179. /* the following are commands that work on the mailbox files */
  180. INT delfile(struct ll * llcur, struct ll * llstart) ; /* delete the actual email file */
  181. INT newfile(struct ll * llcur, struct ll * llstart) ; /* create a new empty email file and return the name */
  182. INT cpyfile (struct ll * newll, struct ll * outhead, struct ll * origll, struct ll * inhead) ;/* cpyfile - copy from the file in origll to the file in newll assume the file exists */
  183. INT fileexist(TEXT * fname) ; /* does the file given in fname exist return TRUE or FALSE if any other error than E_FILE_NXIST return FILEERR */
  184.  
  185.  
  186.  
  187. /* the following work on the meta file */
  188. INT readmeta(TEXT * fname, struct ll * itemlist) ; /* read in the data descriptions */
  189. INT wrtmeta(TEXT * fname, struct ll * itemlist) ; /* write the data descriptions out */
  190. INT readhdr(VOID * fd, struct ll * itemlist) ; /* read the from, subject and return path etc from the data file */
  191. INT wrthdr(VOID * fd, struct ll * itemlist) ; /* write a subject and destination etc to the data file */
  192. INT getf(VOID * fd, TEXT * line) ; /* read a line of text from file handle */
  193. INT putf(VOID * fd, TEXT * line) ; /* write a line of text to file handle */
  194.  
  195. /* commands to manipulate the linked list */
  196. struct ll * llnew(VOID) ;
  197. struct ll * llnofind(INT no, struct ll * llstart) ;
  198. VOID llfill(struct ll * llptr, TEXT * datafile, TEXT * to, TEXT * from, TEXT * subject, TEXT * cc, TEXT * bcc, INT status, INT read, INT no) ;
  199. VOID llfree (struct ll * llptr) ;
  200. VOID lladd(struct ll * newll, struct ll * startll) ;
  201. VOID llinit(VOID);
  202. VOID llcopy(struct ll * out, struct ll * in) ; /* copy the strings in an entry */
  203. INT prgemail(struct ll * llptr) ;
  204. VOID llprint(struct ll * startll, INT mask, INT startno, INT endno); /* print the list at start ll, according to the mask, between the numbers startno and end no */
  205. VOID llprinta(struct ll * llptr, INT mask, TEXT * str) ; /* print the ll structure according to the mask */
  206. VOID disphdrs(struct ll * llptr) ; /* display the usual header information */
  207. INT llvalid(INT mailno, struct ll * llptr) ; /* is mailno in the list and marked as ACTIVE ? */
  208. VOID lldump(struct ll * llptr) ; /* print the current ll entry */
  209. VOID lldmpall(struct ll * llptr) ; /* print the entire ll list */
  210.  
  211.  
  212. /* functions for reading headers from the user */
  213. VOID gethdr(struct ll * in) ; /* fill in a data entry with user information */
  214.  
  215. /* functions for creating new emails and replys */
  216. INT newemail(INT mailno, struct ll * startll, INT incl) ; /* newemail, new list entry, fill it in then write the email */
  217. INT repall(INT mailno, struct ll * startll, INT incl) ; /* repall, reply to the sender and all other recievers */
  218. INT repfrom(INT mailno, struct ll * startll, INT incl) ; /* repfrom, reply to the sender only */
  219.  
  220.  
  221. /* End of function definitions */
  222.  
  223. /* start of actual code */
  224.  
  225. /* start of linked list code */
  226.  
  227. /* display the usual header information */
  228. VOID disphdrs(struct ll * llptr) 
  229. {
  230.     INT mask, startno, endno ;
  231.     /* if llptr is inlist include from, otherwise include to */
  232.     if (llptr == inlist)
  233.         mask = PFROM | PREAD ;
  234.     else
  235.         mask = PTO ;
  236.     /* add the other stuff */
  237.     mask = mask | PNO | PSUBJECT | PACTIVE | PDELETED | PSTATUS ;
  238.     /* try to print ITEMS_ON_SCREEN emails we check for sanity of startno and endno later*/
  239.     startno = mailno - ITEMS_ON_HALF_SCREEN ;
  240.     endno = mailno + ITEMS_ON_HALF_SCREEN ;
  241.     /* if we are at the begining print the first ITEMS_ON_SCREEN emails */
  242.     if (mailno <= ITEMS_ON_HALF_SCREEN)
  243.     {
  244.         startno = 1 ;
  245.         endno = ITEMS_ON_SCREEN ;
  246.     }
  247.     if ((mailno + ITEMS_ON_HALF_SCREEN) >= currlist->count) 
  248.     {
  249.         endno = currlist->count ;
  250.         startno = (endno - ITEMS_ON_SCREEN) +1 ;
  251.     }
  252.     /* check for sanity in the start and end numbers */
  253.     if (startno < 1)
  254.         startno = 1;
  255.     if (endno > currlist->count)
  256.         endno = currlist->count ;
  257.     llprint(llptr, mask, startno, endno) ;
  258. }
  259. /* print the list at start ll, according to the mask, between the numbers startno and end no */
  260. VOID llprint(struct ll * startll, INT mask, INT startno, INT endno) 
  261. {
  262.     TEXT tmp[200], tmp1[300] ;
  263.     INT ystart,doprint, prtct ;
  264.     G_GC gc ;
  265.     ystart = HDRINCR ;
  266.     prtct = 0 ;
  267.     while (startll != NULL)
  268.     {
  269.         doprint = FALSE ;
  270.         if ((startll->no >= startno) && (startll->no <= endno))
  271.         {
  272.             /* should we be printing this record ? */
  273.             if ((mask & PACTIVE) && (startll->status == ACTIVE))
  274.             {
  275.                 llprinta(startll, mask, tmp) ;
  276.                 doprint = TRUE ;
  277.             }
  278.             else if ((mask & PIGNORE) && (startll->status == IGNORE))
  279.             {
  280.                 llprinta(startll, mask, tmp) ;
  281.                 doprint = TRUE ;
  282.             }
  283.             else if ((mask & PDELETED) && (startll->status == DELETED))
  284.             {
  285.                 llprinta(startll, mask, tmp) ;
  286.                 doprint = TRUE ;
  287.             }
  288.         }
  289.         if (doprint == TRUE)
  290.         {
  291.             prtct ++ ;
  292.             if (mailno == startll->no) /* this line needs to be in bold */
  293.             {
  294.                 gc.style = G_STY_NORMAL | G_STY_BOLD ;
  295.                 gSetGC(gchdr, G_GC_MASK_STYLE, &gc) ;
  296.             }
  297.             else /* not the current email */
  298.             {
  299.                 gc.style = G_STY_NORMAL ;
  300.                 gSetGC(gchdr, G_GC_MASK_STYLE, &gc) ;
  301.             }
  302.             p_scpym(tmp1, tmp, blank, NULL) ; /* remove any chars at the end of the line */
  303.             gPrintClipText(5, ystart, tmp1, p_slen(tmp1), 230) ;
  304.             ystart += HDRINCR ;
  305.         }
  306.         startll = startll->next ;
  307.     }
  308.     /* empty out the other stuff on the screen */
  309.     if ( prtct < ITEMS_ON_SCREEN)
  310.     {
  311.         p_scpym(tmp1, blank, blank, NULL) ;
  312.         while (prtct < ITEMS_ON_SCREEN)
  313.         {
  314.             gPrintClipText(5, ystart, tmp1, p_slen(tmp1), 230) ;
  315.             ystart += HDRINCR ;
  316.             prtct ++ ;
  317.         }
  318.     }
  319. }
  320.  
  321. /* print the structure according to the mask */
  322. VOID llprinta(struct ll * llptr, INT mask, TEXT * str)
  323. {
  324.     TEXT outline[1024] ;
  325.     TEXT tmp[100] ;
  326.     outline[0] = '\0' ;
  327.     /* print llptr according to the mask */
  328.     if (mask & PNO)
  329.     {
  330.         p_atos(tmp, "%d", llptr->no) ;
  331.         p_scatm(outline, tmp, " ", NULL) ;
  332.     }
  333.     if (mask & PREAD)
  334.     {
  335.         if (llptr->read == RD)
  336.             p_scatm(outline, "R", " ", NULL) ;
  337.         else
  338.             p_scatm(outline, "N", " ", NULL) ;
  339.     }
  340.     if (mask & PSTATUS)
  341.     {
  342.         if (llptr->status == ACTIVE)
  343.             p_scatm(outline, " ", " ", NULL) ;
  344.         else if (llptr->status == IGNORE)
  345.             p_scatm(outline, "I", " ", NULL) ;
  346.         else if (llptr->status == DELETED)
  347.             p_scatm(outline, "D", " ", NULL) ;
  348.     }
  349.     if (mask & PDATAFILE)
  350.         p_scatm(outline, llptr->datafile, " ", NULL) ;
  351.     if (mask & PTO)
  352.         p_scatm(outline, llptr->to, " ", NULL) ;
  353.     if (mask & PFROM)
  354.         p_scatm(outline, llptr->from, " ", NULL) ;
  355.     if (mask & PSUBJECT)
  356.         p_scatm(outline, ": ",llptr->subject, " ", NULL) ;
  357.     if (mask & PCC)
  358.         p_scatm(outline, llptr->cc, " ", NULL) ;
  359.     if(mask & PBCC)
  360.         p_scatm(outline, llptr->bcc, " ", NULL) ;
  361.     if (mask & PCOUNT)
  362.     {
  363.         p_atos(tmp, "%d", llptr->count) ;
  364.         p_scatm(outline, tmp, " ", NULL) ;
  365.     }
  366.     p_scpy(str, outline) ;
  367. }
  368. /* this command scans the linked lists looking for a deleted entry. the associated file is then deleted */
  369. INT prgemail(struct ll * llptr)
  370. {
  371.     struct ll * llstart ;
  372.     INT ret ;
  373.     llstart = llptr ;
  374.     while(llptr != NULL)
  375.     {
  376.         if(llptr->status == DELETED)
  377.         {
  378.             ret = delfile(llptr, llstart) ;
  379.             if (ret == FILEERR)
  380.             {
  381.                 uDisplayText("FILE ERROR: prgemail,","error in deleting message file", llptr->datafile, NULL) ;
  382.                 return(FILEERR) ;
  383.             }
  384.         }
  385.         llptr = llptr->next ;
  386.     }
  387.     return(TRUE) ;
  388. }
  389. /* fill in a ll entry based on the arguments */
  390. VOID llfill(struct ll * llptr, TEXT * datafile, TEXT * to, TEXT * from, TEXT * subject, TEXT * cc, TEXT * bcc, INT status, INT read, INT no)
  391. {
  392.     p_scpy(llptr->datafile, datafile) ;
  393.     p_scpy(llptr->to, to) ;
  394.     p_scpy(llptr->from, from) ;
  395.     p_scpy(llptr->subject, subject) ;
  396.     p_scpy(llptr->cc, cc) ;
  397.     p_scpy(llptr->bcc, bcc) ;
  398.     llptr->status = status ;
  399.     llptr->read = read ;
  400.     llptr->no = no ;
  401. }
  402. /* find a list entry based on the number */
  403. struct ll * llnofind(INT no, struct ll * llstart)
  404. {
  405.     struct ll * llcurrnt ;
  406.     llcurrnt = llstart ;
  407.     while(llcurrnt->no != no)
  408.     {
  409.         if(llcurrnt->next == NULL)
  410.         {
  411.             return(NULL) ;
  412.         }
  413.         llcurrnt = llcurrnt->next ;
  414.  
  415.     }
  416.     /* to have got here we must havea match if we could not find a match we would already havereturned NULL */
  417.     return(llcurrnt) ;
  418. }
  419.         
  420. /* this adds the newll to the end of the list at startll */
  421. VOID lladd(struct ll * newll, struct ll * startll)
  422. {
  423.     struct ll * llcurrnt ;
  424.     llcurrnt = startll ;
  425.     /* scan down the list lokking for NULL) */
  426.     while(llcurrnt->next != NULL)
  427.     {
  428.         llcurrnt = llcurrnt->next ;
  429.     }
  430.     /* we are at the end of the list add the entry */
  431.     llcurrnt->next = newll ;
  432.     /* increment the total in the list counter, held in the first entry in the list only */
  433.     startll->count ++ ;
  434. }
  435. /* this function creates the initial in and out list entries */
  436. VOID llinit(VOID)
  437. {
  438.     inlist = llnew() ;
  439.     outlist = llnew() ;
  440.     inlist->mydata = p_alloc(sizeof(struct mydata)) ;
  441.     outlist->mydata = p_alloc(sizeof(struct mydata)) ;
  442. }
  443.  
  444. /* linked list functions */
  445. /* llnew, create space and fill with defaults */
  446. struct ll * llnew(VOID)
  447. {
  448.     struct ll * llptr;
  449.     llptr = p_alloc(sizeof(struct ll)) ;
  450.     llptr->datafile[0] = '\0' ;
  451.     llptr->to[0] = '\0' ;
  452.     llptr->from[0] = '\0' ;
  453.     llptr->subject[0] = '\0' ;
  454.     llptr->cc[0] = '\0' ;
  455.     llptr->bcc[0] = '\0' ;
  456.     llptr->status = IGNORE ;
  457.     llptr->read = NEW ;
  458.     llptr->next = NULL ;
  459.     llptr->no = 0 ;
  460.     llptr->count = 0 ;
  461.     llptr->mydata = NULL ;
  462.     return(llptr) ;
  463. }
  464. VOID llcopy (struct ll * out, struct ll * in)
  465. {
  466.     /* copy the strings but status etc remains untouched */
  467.     p_scpy(out->datafile, in->datafile) ;
  468.     p_scpy(out->to, in->to) ;
  469.     p_scpy(out->from, in->from) ;
  470.     p_scpy(out->subject, in->subject) ;
  471.     p_scpy(out->cc, in->cc) ;
  472.     p_scpy(out->bcc, in->bcc) ;
  473. }
  474. /* llfree, free llptr and everything it points to */
  475. VOID llfree (struct ll * llptr) 
  476. {
  477.     struct ll * llnext;
  478.     /* free the mydata section only on the first item */
  479.     p_free(llptr->mydata) ;
  480.     llnext = llptr;
  481.     while(llptr != NULL)
  482.     {
  483.         llnext = llptr->next ;
  484.         p_free(llptr) ;
  485.         llptr = llnext ;
  486.     }
  487. }
  488. /* is mailno in the list and marked as ACTIVE ? */
  489. INT llvalid(INT mailno, struct ll * llptr)
  490. {
  491.     TEXT tmp[50] ;
  492.     llptr = llnofind(mailno, llptr) ;
  493.     if (llptr != NULL)
  494.     {
  495.         if (llptr->status != ACTIVE)
  496.         {
  497.             p_atos(tmp, "%d is not an active message", mailno) ;
  498.             uDisplayText(tmp, NULL) ;
  499.             return(FALSE) ;
  500.         }
  501.         else
  502.         {
  503.             return(TRUE) ;
  504.         }
  505.     }
  506.     else
  507.     {
  508.         p_atos(tmp, "%d is not a valid message", mailno) ;
  509.         uDisplayText(tmp, NULL) ;
  510.         return(FALSE) ;
  511.     }
  512. }
  513.  
  514. /* end of linked list code */
  515.  
  516. /* start of top level functions */
  517.  
  518. /* create the graphics context */
  519. VOID CreateGC(VOID)
  520. {
  521.     INT hgc ;
  522.     hgc = gCreateGC0(MainWid) ;
  523.     if (hgc < 0)
  524.         p_exit(hgc) ;
  525. }
  526. /* do the basic window setup */
  527. VOID initwins(VOID)
  528. {
  529.  
  530.     uCommonInit() ; /* connect to the window system etc */
  531.     MainWid=uFindMainWid() ; /* figure out what the main window is */
  532.     CreateGC() ;
  533.     hCrackCommandLine() ; /* do the command line and make 
  534.                                        ourselves available for recieveing 
  535.                                        commands such as exit etc */
  536. }
  537.  
  538. /* setup the windows etc. */
  539. VOID initmywins(VOID)
  540. {
  541.     /* create the windows */
  542.     /* the status window */
  543.     /* geometry information */
  544.     wdstatus.extent.tl.x = 0 ;
  545.     wdstatus.extent.tl.y = 0 ;
  546.     wdstatus.extent.width = 240 ;
  547.     wdstatus.extent.height = 18 ;
  548.     wdstatus.flags = W_WIN_PRIORITY ;
  549.     wdstatus.mouse_icon = 0 ;
  550.     wdstatus.filler = 0 ;
  551.     wdstatus.background = W_WIN_BACK_BITMAP ;
  552.     /* graphics context definitions (how to draw) specification */
  553.     gdstatus.gmode = G_TRMODE_SET ;
  554.     gdstatus.textmode = G_TRMODE_REPL ;
  555.     gdstatus.style = G_STY_NORMAL ;
  556.     gdstatus.filler = 0 ;
  557.     gdstatus.font = WS_FONT_BASE ;
  558.     /* create the window */
  559.     winstatus = wCreateWindow(MainWid, W_WIN_EXTENT | W_WIN_BACKGROUND, &wdstatus,1) ;
  560.     /* make it real in the windows tree */
  561.     wInitialiseWindowTree(winstatus) ;
  562.     /* create the graphics context */
  563.     gcstatus = gCreateGC(winstatus, G_GC_MASK_GMODE | G_GC_MASK_TEXTMODE | G_GC_MASK_STYLE, &gdstatus) ;
  564.     /* make the window visible */
  565.     wMakeVisible(winstatus) ;
  566.     /* make the current context the one we will use */
  567.     gSetGC0(gcstatus) ;
  568.     /* put a border around the current context */
  569.     gBorder(W_BORD_CUSHION|W_BORD_CORNER_4) ;
  570.     
  571.     /* the header window */
  572.     /* geometry information */
  573.     wdhdr.extent.tl.x = 0 ;
  574.     wdhdr.extent.tl.y = 21 ;
  575.     wdhdr.extent.width = 240 ;
  576.     wdhdr.extent.height = 59 ; 
  577.     wdhdr.flags = W_WIN_PRIORITY ;
  578.     wdhdr.mouse_icon = 0 ;
  579.     wdhdr.filler = 0 ;
  580.     wdhdr.background = W_WIN_BACK_BITMAP ;
  581.     /* graphics context definitions (how to draw) specification for normal text */
  582.     gdhdr.gmode = G_TRMODE_SET ;
  583.     gdhdr.textmode = G_TRMODE_REPL ;
  584.     gdhdr.style = G_STY_NORMAL ;
  585.     gdhdr.filler = 0 ;
  586.     gdhdr.font = WS_FONT_BASE ;
  587.     /* create the window */
  588.     winhdr = wCreateWindow(MainWid, W_WIN_EXTENT | W_WIN_BACKGROUND, &wdhdr,1) ;
  589.     /* make it real in the windows tree */
  590.     wInitialiseWindowTree(winhdr) ;
  591.     /* create the graphics context for normal text */
  592.     gchdr = gCreateGC(winhdr, G_GC_MASK_GMODE | G_GC_MASK_TEXTMODE | G_GC_MASK_STYLE, &gdhdr) ;    
  593.     /* make the window visible */
  594.     wMakeVisible(winhdr) ;
  595.     /* make the current context the one we will use */
  596.     gSetGC0(gchdr) ;
  597.     /* put a border around the current context */
  598.     gBorder(W_BORD_CUSHION|W_BORD_CORNER_4) ;
  599.     
  600. }
  601.  
  602.  
  603. /* close down the windows */
  604. VOID shutwins(VOID) 
  605. {
  606.     /* shutdown any windows etc */
  607.     wCloseWindowTree(MainWid) ;
  608. }
  609.  
  610. /* print out who we are and the version number */
  611. VOID dogreet(VOID)
  612. {
  613.     uDisplayText("Psion Offline SMTP Mail Reader", "(C) by Tim Graves,","Sun Microsystems","Version 2.7", "Press Return to continue", NULL) ;
  614. }
  615.  
  616. /* read the incomming meta file and display the list of emails */
  617. INT initlist(VOID)
  618. {
  619.     INT ret ;
  620.     llinit() ;
  621.     statusmsg("Reading mta lists") ;
  622.     /* first read the incomming meta data file */
  623.     ret = readmeta(METAIN, inlist) ;
  624.     if (ret == FILEERR)
  625.     {
  626.         uDisplayText("FILE ERROR: initlist,","error in reading metafile", METAIN, NULL) ;
  627.         return (FILEERR) ;
  628.     }
  629.     if (ret == MEMERR)
  630.     {
  631.         uDisplayText("MEMORY ERROR: initlist,","error in reading metafile", METAIN, NULL) ;
  632.         return(MEMERR) ;
  633.     }
  634.     /* then the outgoing data file */
  635.     ret = readmeta(METAOUT, outlist) ;
  636.     if (ret == FILEERR)
  637.     {
  638.         uDisplayText("FILE ERROR: initlist,","error in reading metafile", METAIN, NULL) ;
  639.         return (FILEERR) ;
  640.     }
  641.     if (ret == MEMERR)
  642.     {
  643.         uDisplayText("MEMORY ERROR: initlist,","error in reading metafile", METAOUT, NULL) ;
  644.         return(MEMERR) ;
  645.     }
  646.     /* start working with the incomming list */
  647.     currlist = inlist ;
  648.     if (currlist->count > 0)
  649.         mailno = 1 ;
  650.     else
  651.         mailno = 0 ;
  652.     /* display the list first*/
  653.     redolist() ;
  654.     return(TRUE) ;
  655. }
  656.  
  657. /* wait for a command then do it this is taken directly from the 
  658.    developers kit demo code */
  659. INT mainloop(VOID)
  660. {
  661.     INT ret ;
  662.     WMSG_KEY key ;
  663.     FOREVER
  664.     {
  665.         uGetKey(&key) ;
  666.         if (key.keycode&W_EVENT_KEY) /* call from the system screen, we are only interested in the shutdown
  667.                          as we done accept new or open functions */
  668.         {
  669.             if (key.keycode==CONS_EVENT_COMMAND) /* exit and save our state */
  670.                 return(TRUE) ;
  671.         }
  672.         else if (key.keycode&W_SPECIAL_KEY) /* psion-? accelerator */
  673.         {
  674.             /* check for x or q (exit and save or crash out) as we handle these here */
  675.             ret = key.keycode&(~W_SPECIAL_KEY) ;
  676.             if (ret == 'x')
  677.                 return (TRUE) ;
  678.             else if (ret == 'c')
  679.                 return(IERR) ;
  680.             else
  681.                 ManageCommand(ret) ;
  682.         }
  683.         else if ((key.keycode == W_KEY_MENU) && !(key.modifiers&W_CTRL_MODIFIER)) /* menu button */
  684.         {
  685.             ret = uPresentMenus() ;
  686.             if (ret > 0)
  687.             {
  688.                 /* check for x or q (exit and save or crash out) as we handle these here */
  689.                 if (ret == 'x')
  690.                     return (TRUE) ;
  691.                 else if (ret == 'c')
  692.                     return(IERR) ;
  693.                 else
  694.                     ManageCommand(ret) ;
  695.             }
  696.         }
  697.         /* we know the keycode is not a system screen function, psion-? key on menu button
  698.            see if it is a movement key (up, down, page up, page down or modified with ctrl */
  699.         else
  700.         {
  701.             switch (key.keycode)
  702.             {
  703.                 case W_KEY_UP:
  704.                     if (key.modifiers&W_CTRL_MODIFIER) /* go to the bottom of the current page */
  705.                         mailno -= ITEMS_ON_HALF_SCREEN ;
  706.                     else
  707.                         mailno -- ;
  708.                     break ;
  709.                 case W_KEY_DOWN:
  710.                     if (key.modifiers&W_CTRL_MODIFIER) /* go to the top of the current page */
  711.                         mailno += ITEMS_ON_HALF_SCREEN  ;
  712.                     else
  713.                         mailno ++ ;
  714.                     break ;
  715.                 case W_KEY_PAGE_UP:
  716.                     if (key.modifiers&W_CTRL_MODIFIER) /* go to the first entry */
  717.                         mailno = 1 ;
  718.                     else
  719.                         mailno -= ITEMS_ON_SCREEN ;
  720.                     break ;
  721.                 case W_KEY_PAGE_DOWN:
  722.                     if (key.modifiers&W_CTRL_MODIFIER) /* go to the last entry */
  723.                         mailno = currlist->count ;
  724.                     else
  725.                         mailno += ITEMS_ON_SCREEN ;
  726.                     break ;
  727.             }
  728.             /* make sure that mail no is within the current email range */
  729.             if (mailno < 1)
  730.                 mailno = 1 ;
  731.             if (mailno > currlist->count)
  732.                 mailno = currlist->count ;
  733.         }
  734.         redolist() ; /* the likley hood is that the list will have changed so redraw it */
  735.     }
  736. }
  737.  
  738. LOCAL_C VOID ManageCommand(INT keycode)
  739. {
  740.     INT  incl;
  741.     struct ll * llptr ;
  742.     switch (keycode)
  743.     {
  744.         /* functions from the current email list */
  745.         case 'v': /* v - view the email */
  746.             readmail(mailno, currlist) ;
  747.             break ;
  748.         case 'd': /* d - delete email */
  749.             delmail(mailno, currlist) ;
  750.             break ;
  751.         case 'u': /* u - undelete email */
  752.             udelmail(mailno, currlist) ;
  753.             break ;
  754.         case 'm': /* modify the current header */
  755.             /* this is pointless unless we are dealing with the outgoing list. So */
  756.             if (currlist == inlist)
  757.             {
  758.                 uDisplayText("You Cannot modify the headers", "In the incomming list", "(Its a pointless exercise)", NULL) ;
  759.                 break ;
  760.             }
  761.             llptr = llnofind(mailno, currlist) ;
  762.             gethdr(llptr) ;
  763.             break ;
  764.         /* functions from the compose email list */
  765.         case 'n': /* new email */
  766.             incl = askincl() ;
  767.             newemail(mailno, currlist, incl) ;
  768.             break ;
  769.         case 'r': /* r - reply to sender */
  770.             incl = askincl() ;
  771.             repfrom(mailno, currlist, incl) ;
  772.             break;
  773.         case 'a': /* a - reply to all */
  774.             incl = askincl() ;
  775.             repall(mailno, currlist, incl) ;
  776.             break ;
  777.         /* functions from the special email list - NOTE x and c are dealt with earlier in the mainloop code */
  778.         case 's': /* s - switch from the inlist to the outlist */
  779.             if (currlist == inlist)
  780.             {
  781.                 uDisplayText("Switching to the outgoing mail file", NULL) ;
  782.                 currlist = outlist ;
  783.             }
  784.             else
  785.             {
  786.                 uDisplayText("Switching to the incomming mail file", NULL) ;
  787.                 currlist = inlist ;
  788.             }
  789.             mailno = 1 ;
  790.             break ;
  791.     }
  792.     return ;            
  793.         
  794. }
  795.  
  796. /* delete any deleted files, write out the updated meta files */
  797. INT dotidy(VOID)
  798. {
  799.     INT ret ;
  800.     /* purge the deleted incomming emails */
  801.     statusmsg("Deleting unwanted message files") ;
  802.     ret = prgemail(inlist) ;
  803.     if (ret == FILEERR)
  804.     {
  805.         return(FILEERR) ;
  806.     }
  807.     /* purge any deleted outgoing emails */
  808.     ret = prgemail(outlist) ;
  809.     if (ret == FILEERR)
  810.     {
  811.         return(FILEERR) ;
  812.     }
  813.     /* write the incomming list back out */
  814.     statusmsg("Saving mta lists") ;
  815.     ret = wrtmeta(METAIN, inlist) ;
  816.     if (ret == FILEERR)
  817.     {
  818.         return(FILEERR) ;
  819.     }
  820.     /* finaly the outgoing list */
  821.     wrtmeta(METAOUT, outlist) ;
  822.     if (ret == FILEERR)
  823.     {
  824.         return(FILEERR) ;
  825.     }
  826.     /* free the data in the list */
  827.     statusmsg("Freeing Memory") ;
  828.     llfree(inlist) ;
  829.     llfree(outlist) ;
  830.     return(TRUE) ;
  831. }
  832.     
  833.     
  834. /* write the meta files out */
  835.  void main(void)
  836. {
  837.     INT ret ;
  838.     /* setup the windows etc*/
  839.     initwins() ;
  840.     /* say Hi */
  841.     dogreet() ;
  842.     /* Load my windows */
  843.     initmywins() ;
  844.     /* read the list of incomming mail */
  845.     ret = initlist() ;
  846.     if (ret == FILEERR)
  847.     {
  848.         uDisplayText("FILE ERROR: main, error","in loading meta lists", NULL) ;
  849.         return ;
  850.     }
  851.     if (ret == MEMERR)
  852.     {
  853.         uDisplayText("MEMORY ERROR: main, error","in loading meta lists", NULL) ;
  854.         return ;
  855.     }
  856.     if (ret != TRUE)
  857.     {
  858.         uDisplayText("UNKNOWN ERROR: main, error","in loading meta lists", NULL) ;
  859.         return ;
  860.     }
  861.     /* main select / chose / do loop */
  862.     ret = mainloop() ;
  863.     if (ret == IERR)
  864.     {
  865.         uDisplayText("INTERNAL ERROR: panic exit","(metafiles not written)", NULL) ;
  866.         return ;
  867.     }
  868.     else if (ret == FILEERR)
  869.     {
  870.         uDisplayText("FILE ERROR: panic exit","(metafiles not written)", NULL) ;
  871.         return ;
  872.     }
  873.     else if (ret == MEMERR)
  874.     {
  875.         uDisplayText("MEMORY ERROR: panic exit","(metafiles not written)", NULL) ;
  876.         return ;
  877.     }
  878.     else if ((ret != TRUE) && (ret != FALSE))
  879.     {
  880.         uDisplayText("UNKNOWN ERROR: panic exit","(metafiles not written)", NULL) ;
  881.         return ;
  882.     }
  883.     /* tidy up after us */
  884.     ret = dotidy() ;
  885.     if (ret == IERR)
  886.     {
  887.         uDisplayText("INTERNAL ERROR: main, error","in writting meta lists", NULL) ;
  888.         return ;
  889.     }
  890.     if (ret == MEMERR)
  891.     {
  892.         uDisplayText("MEMORY ERROR: main, error","in writting meta lists", NULL) ;
  893.         return ;
  894.     }
  895.     if (ret == FILEERR)
  896.     {
  897.         uDisplayText("FILE ERROR: main, error","in writting meta lists", NULL) ;
  898.         return ;
  899.     }
  900.     if (ret != TRUE)
  901.     {
  902.         uDisplayText("UNKNOWN ERROR: main, error","in writting meta lists", NULL) ;
  903.         return ;
  904.     }
  905.     /* close down the windows etc */
  906.     shutwins() ;
  907. }
  908.  
  909. /* end of top level code */
  910.  
  911. /* start of process related code */
  912. /* do the word stuff */
  913. VOID doword(TEXT * fname)
  914. {
  915.     TEXT cmdline[127], tmp[50] ;
  916.     INT cmdlen ;
  917.  
  918.     /* build the command line */
  919.     cmdlen = buildcmd('O',MAILRDRNAME, MAILRDREXT, "Q", fname, cmdline) ;
  920.     p_atos(tmp, "Running %s", MAILRDRNAME ) ;
  921.     statusmsg(tmp) ;
  922.     runcmd(MAILRDRCMD, cmdline, cmdlen) ;
  923.     p_atos(tmp, "Returned from %s", MAILRDRNAME) ;
  924.     statusmsg(tmp) ;
  925. }
  926.  
  927. INT runcmd(TEXT * appname, TEXT * cmdline, INT cmdlen) 
  928. {
  929.     HANDLE pid ;
  930.     WORD stat ;
  931.     /* create the process */
  932.     if ((pid = p_execc(appname, cmdline, cmdlen)) <0)
  933.         return(pid) ;
  934.     
  935.     /* we want to monitor it */
  936.     p_logona(pid, &stat) ;
  937.  
  938.     /* start the process up */
  939.     p_presume(pid) ;
  940.  
  941.     /* wait for it to finish */
  942.     p_waitstat(&stat) ;
  943.  
  944.     return(stat >> 8) ;
  945. }
  946.  
  947. INT buildcmd(TEXT cmdbyte, TEXT * appname, TEXT * appext, TEXT * appalias, TEXT * fname, TEXT * cmdline)
  948. {
  949.     TEXT * cmdptr;
  950.     INT cmdlen ;
  951.  
  952.     /* initialisation */
  953.     cmdlen = 0 ;
  954.     cmdptr = cmdline ;
  955.     /* do the command byte */
  956.         /* insert it */
  957.         * cmdptr = cmdbyte ;
  958.         /* the length has just been increased */
  959.         cmdlen ++ ;
  960.         /* move cmdptr allong one to skip over the command */
  961.         cmdptr ++ ;
  962.     /* insert the appname */
  963.         /* insert it */
  964.         p_scpy(cmdptr, appname) ;
  965.         /* move over it and the \0 */
  966.         cmdptr = cmdptr + p_slen(appname) +1 ;
  967.         /* add the length and the \0 to the total length */
  968.         cmdlen = cmdlen + p_slen(appname) +1 ;
  969.     /* insert the extension and other stuff if appext is non NULL */
  970.     if (appext != NULL)
  971.     {
  972.         /* insert the extension */
  973.         p_scpy(cmdptr, appext) ;
  974.         /* move over it BUT NOT THE NULL (we may have an alias)*/
  975.         cmdptr = cmdptr + p_slen(appext) ;
  976.         /* add the length to the total length */
  977.         cmdlen = cmdlen + p_slen(appext) ;
  978.  
  979.         /* if the alias is non NULL add it */
  980.         if (appalias != NULL) 
  981.         {
  982.             /* insert a space */
  983.             *cmdptr = ' ' ;
  984.             /* move over the space */
  985.             cmdptr ++ ;
  986.             /* add the space to the total length */
  987.             cmdlen ++ ;
  988.             /* insert the appalias */
  989.             p_scpy(cmdptr, appalias) ;
  990.             /* move over the alias BUT NOT THE NULL (then is dealt with below)*/
  991.             cmdptr = cmdptr + p_slen(appalias) ;
  992.             /* increment the total length */
  993.             cmdlen = cmdlen + p_slen(appalias) ;
  994.         }
  995.  
  996.         /* because we have not accounted for the \0 at the end of the appext / appext+appalias
  997.            move over it now */
  998.         cmdptr ++ ;
  999.         cmdlen ++ ;
  1000.  
  1001.         /* if there is a filename add it */
  1002.         if (fname != NULL)
  1003.         {
  1004.             /*insert the filename */
  1005.             p_scpy(cmdptr, fname) ;
  1006.             /* add the length and vFà \0 to the total length */
  1007.             cmdlen = cmdlen + p_slen(fname) + 1 ;
  1008.             /* we done need to move cmdptr as we are at the end of the operatrion */
  1009.         }
  1010.     }
  1011.     /* return with the length of the assembled string */
  1012.     return(cmdlen) ;
  1013. }
  1014.  
  1015. /* end of process related code */
  1016.  
  1017. /* start of writting email code */
  1018. /* repfrom, reply to the sender only */
  1019. INT repfrom(INT mailno, struct ll * startll, INT incl)
  1020. {
  1021.     struct ll * newll, *repmail ;
  1022.     TEXT tmp[100] ;
  1023.     INT ret ;
  1024.     /* create the new list entry */
  1025.     newll = llnew() ;
  1026.     /* locate the origional email */
  1027.     repmail = llnofind(mailno, startll) ;
  1028.     /* copy the data */
  1029.     llcopy(newll, repmail) ;
  1030.     /* add Reto the start of the subject */
  1031.     p_scpym(tmp, "Re: ", newll->subject, NULL) ;
  1032.     p_scpy(newll->subject, tmp) ;
  1033.     /* copy the from into the to list */
  1034.     p_scpy(newll->to, newll->from) ;
  1035.     /* put our name in the from field */
  1036.     p_scpy(newll->from, startll->mydata->myaddr) ;
  1037.     /* empty the cc and bcc fields */
  1038.     newll->cc[0] = '\0' ;
  1039.     newll->bcc[0] = '\0' ;
  1040.     /* create the related file */
  1041.     if ((ret = newfile(newll, outlist)) != TRUE)
  1042.     {
  1043.         p_free(newll) ;
  1044.         if (ret == FILEERR)
  1045.             uDisplayText("FILE ERROR: repfrom,","newfile returned FILEERR", NULL) ;
  1046.         else
  1047.             uDisplayText("INTERNAL ERROR: repfrom,","newfile returned an unexpected error code", NULL) ;
  1048.         return(ret) ;
  1049.     }
  1050.     /* if incl is TRUE copy from the origional to the new data file */
  1051.     if (incl == TRUE)
  1052.     {
  1053.         if ((ret = cpyfile(newll,outlist , repmail, startll)) != TRUE)
  1054.         {
  1055.             p_free(newll) ;
  1056.             if (ret == FILEERR)
  1057.                 uDisplayText("FILE ERROR: repfrom,","cpyfile returned FILEERR", NULL) ;
  1058.             else
  1059.                 uDisplayText("INTERNAL ERROR: repfrom,","cpyfile returned an unexpected error code", NULL) ;
  1060.             return(ret) ;
  1061.         }
  1062.     }
  1063.     /* make the email active */
  1064.     newll->status = ACTIVE ;
  1065.     /* get the header information */
  1066.     gethdr(newll) ;
  1067.     /* get the sequence number */
  1068.     newll->no = outlist->count +1 ;
  1069.     /* add this email to the outgoing list */
  1070.     lladd(newll, outlist) ;
  1071.     /* call the editor do do the work */
  1072.     wrtemail(newll->no, outlist) ;
  1073. }
  1074.  
  1075. /* repall, reply to the sender and all other recievers */
  1076. INT repall(INT mailno, struct ll * startll, INT incl)
  1077. {
  1078.     struct ll * newll, *repmail ;
  1079.     TEXT tmp[100] ;
  1080.     /* create the new list entry */
  1081.     newll = llnew() ;
  1082.     /* locate the origional email */
  1083.     repmail = llnofind(mailno, startll) ;
  1084.     /* copy the data */
  1085.     llcopy(newll, repmail) ;
  1086.     /* add Reto the start of the subject */
  1087.     p_scpym(tmp, "Re: ", newll->subject, NULL) ;
  1088.     p_scpy(newll->subject, tmp) ;
  1089.     /* add the from to the to list */
  1090.     p_scpym(tmp, newll->from, " ", newll->to, NULL) ;
  1091.     p_scpy(newll->to, tmp) ;
  1092.     /* put our name in the from field */
  1093.     p_scpy(newll->from, startll->mydata->myaddr) ;
  1094.     /* create the related file */
  1095.     if (newfile(newll, outlist)== FALSE)
  1096.     {
  1097.         p_free(newll) ;
  1098.         return(FALSE) ;
  1099.     }
  1100.     /* if incl is TRUE copy from the origional to the new data file */
  1101.     if (incl == TRUE)
  1102.         cpyfile(newll, outlist, repmail, startll) ;
  1103.     /* make the email active */
  1104.     newll->status = ACTIVE ;
  1105.     /* get the header information */
  1106.     gethdr(newll) ;
  1107.     /* get the sequence number */
  1108.     newll->no = outlist->count +1 ;
  1109.     /* add this email to the outgoing list */
  1110.     lladd(newll, outlist) ;
  1111.     /* call the editor do do the work */
  1112.     wrtemail(newll->no, outlist) ;
  1113. }
  1114. /* newemail, new list entry, fill it in then write the email */
  1115. INT newemail(INT mailno, struct ll * startll, INT incl)
  1116. {
  1117.     struct ll * newll, * repmail ;
  1118.     INT ret ;
  1119.     newll = llnew() ;
  1120.     /* instal our address into the from field */
  1121.     p_scpy(newll->from, startll->mydata->myaddr) ;
  1122.     /* create the related file */
  1123.     if (newfile(newll, outlist) == FILEERR)
  1124.     {
  1125.         uDisplayText("FILE ERROR: newemail,","error in creating new email file", NULL) ;
  1126.         p_free(newll) ;
  1127.         return(FILEERR) ;
  1128.     }
  1129.     /* if incl is true we need to copy the given email */
  1130.     if (incl == TRUE)
  1131.     {
  1132.         repmail = llnofind(mailno, startll) ;
  1133.         ret = cpyfile(newll, outlist, repmail, startll) ;
  1134.         if (ret == FILEERR)
  1135.         {
  1136.             uDisplayText("FILE ERROR: newemail,","error in creating copy file for include", NULL) ;
  1137.             return(FILEERR) ;
  1138.         }
  1139.     }
  1140.     /* make the email active */
  1141.     newll->status = ACTIVE ;
  1142.     /* get the header information */
  1143.     gethdr(newll) ;
  1144.     /* get the sequence number */
  1145.     newll->no = outlist->count +1 ;
  1146.     /* add this email to the outgoing list */
  1147.     lladd(newll, outlist) ;
  1148.     /* call the editor do do the work */
  1149.     wrtemail(newll->no, outlist) ;
  1150. }
  1151. /* end of email writting code */
  1152.  
  1153. /* start of header from user code */
  1154. /* fill in a data entry with user information */
  1155. VOID gethdr(struct ll * in)
  1156. {
  1157.     TEXT to[HDRLEN+1], subject[HDRLEN+1], cc [HDRLEN+1], bcc[HDRLEN+1] ;
  1158.     H_DI_SEDIT eto, esubject, ecc, ebcc ;
  1159.     /* convert from zero terminated strings (ala C) to byte count srtings (ala OPL) */
  1160.     uZTStoBCS(to, in->to) ;
  1161.     uZTStoBCS(subject, in->subject) ;
  1162.     uZTStoBCS(cc, in->cc) ;
  1163.     uZTStoBCS(bcc, in->bcc) ;
  1164.     /* build the dialog structures */
  1165.     /* the to structure */
  1166.     eto.str = &to[0] ;
  1167.     eto.len = HDRLEN ;
  1168.     eto.width = 30 ;
  1169.     /* subject structure */
  1170.     esubject.str = &subject[0] ;
  1171.     esubject.len = HDRLEN ;
  1172.     esubject.width = 30 ;
  1173.     /* cc structure */
  1174.     ecc.str = &cc[0] ;
  1175.     ecc.len = HDRLEN ;
  1176.     ecc.width = 30 ;
  1177.     /* bcc structure */
  1178.     ebcc.str = &bcc[0] ;
  1179.     ebcc.len = HDRLEN ;
  1180.     ebcc.width = 30 ;
  1181.     
  1182.     /* build the dialog */
  1183.     uOpenDialog("Please enter the header information") ;
  1184.     /* add the initial header information to it */
  1185.     uAddDialogItem(H_DIALOG_SEDIT, "To:", &eto) ;
  1186.     uAddDialogItem(H_DIALOG_SEDIT, "Subject:", &esubject) ;
  1187.     uAddDialogItem(H_DIALOG_SEDIT, "Cc:", &ecc) ;
  1188.     uAddDialogItem(H_DIALOG_SEDIT, "Bcc:", &ebcc) ;
  1189.     /* run the dialog */
  1190.     uRunDialog() ;
  1191.     /* unpack the resulting strings this is realy daft having parts of the dialog ZTS and parts BCS */
  1192.     /* terminate them first */
  1193.     to[((INT)to[0])+1] = '\0' ;
  1194.     subject[((INT) subject[0])+1] = '\0' ;
  1195.     cc[((INT) cc[0])+1] = '\0' ;
  1196.     bcc[((INT) bcc[0]) +1] = '\0' ;
  1197.     /* copy the strings back */
  1198.     p_scpy(in->to, &to[1]) ;
  1199.     p_scpy(in->subject, &subject[1]) ;
  1200.     p_scpy(in->cc, &cc[1]) ;
  1201.     p_scpy(in->bcc, &bcc[1]) ;    
  1202. }
  1203.  
  1204. /* end of header from user code */
  1205.  
  1206. /* start of functions for working the mailbox in view */
  1207. /* bring up a mail reader */
  1208. VOID readmail(INT mailno, struct ll * llstart)
  1209. {
  1210.     struct ll * llentry ;
  1211.     TEXT fname [P_FNAMESIZE] ;
  1212.     if ((llentry = llnofind(mailno, llstart)) == NULL)
  1213.         return ;
  1214.     if (llentry->status != ACTIVE)
  1215.         return ;
  1216.     /* build up the name */
  1217.     p_scpym(fname, llstart->mydata->mypath, llentry->datafile, NULL) ;
  1218.     /* call up the editor */
  1219.     doword(fname) ;
  1220.     /* OK we've read the mail, mark it as read */
  1221.     llentry->read = RD ;
  1222. }
  1223. /* write a mail reply, the corresponding linked list
  1224.    entry exists as does the file, so ensure that
  1225.    it is listed as active after the edit */
  1226. VOID wrtemail(INT mailno, struct ll * llstart)
  1227. {
  1228.     struct ll * llentry ;
  1229.     TEXT fname [P_FNAMESIZE] ;
  1230.     if((llentry = llnofind(mailno, llstart)) == NULL)
  1231.         return ;
  1232.     /* build up the name */
  1233.     p_scpym(fname, llstart->mydata->mypath, llentry->datafile, NULL) ;
  1234.     /* call up the editor */
  1235.     doword(fname) ;
  1236.     /* OK we've got a file ensure it's active */
  1237.     llentry->status = ACTIVE ;
  1238. }
  1239. /* delete a mail from the linked lists */
  1240. VOID delmail (INT mailno, struct ll * llstart)
  1241. {
  1242.     struct ll * llentry ;
  1243.     if ((llentry = llnofind(mailno, llstart)) == NULL)
  1244.         return ;
  1245.     llentry->status = DELETED ;
  1246. }
  1247. /* undelete the mail from the internal linked lists */
  1248. VOID udelmail (INT mailno, struct ll * llptr)
  1249. {
  1250.     struct ll * llentry ;
  1251.     if ((llentry = llnofind(mailno, llptr)) == NULL)
  1252.         return ;
  1253.     llentry->status = ACTIVE ;
  1254. }
  1255. /* end of functions for working the mailbox in view */
  1256.  
  1257. /* start of ancilary data file functions */
  1258. /* delfile - physicaly delete the data file */
  1259. INT delfile(struct ll * llcur, struct ll * llstart)
  1260. {
  1261.     TEXT dfname[P_FNAMESIZE] ;
  1262.     /* build up the filesname */
  1263.     p_scpym(dfname, llstart->mydata->mypath, llcur->datafile, NULL) ;
  1264.     if (p_delete(dfname) == 0)
  1265.         return(TRUE) ;
  1266.     else
  1267.     {
  1268.         uDisplayText("FILE ERROR: delfile,","error in deleting file", dfname, NULL) ;
  1269.         return(FILEERR) ;
  1270.     }
  1271. }
  1272.  
  1273. /* cpyfile - copy from the file in origll to the file in newll 
  1274.    assume the file exists */
  1275. INT cpyfile (struct ll * newll, struct ll * outhead, struct ll * origll, struct ll * inhead)
  1276. {
  1277.     VOID * infd, * outfd ;
  1278.     INT ret ;
  1279.     TEXT infname[P_FNAMESIZE] , outfname[P_FNAMESIZE] ;
  1280.     TEXT buff [P_FMAXRSIZE], tmp[P_FMAXRSIZE+3] ;
  1281.     /* munge the filenames */
  1282.     p_scpym(infname, inhead->mydata->mypath, origll->datafile, NULL) ;
  1283.     p_scpym(outfname, outhead->mydata->mypath, newll->datafile, NULL) ;
  1284.     /* open the files */
  1285.     ret = p_open(&infd, infname, P_FTEXT | P_FSHARE) ;
  1286.     if (ret != 0)
  1287.     {
  1288.         p_errs(buff, ret) ;
  1289.         uDisplayText("FILE ERROR: cpyfile,","error in opening input", infname, buff, NULL) ;    
  1290.         return(FILEERR) ;
  1291.     }
  1292.     ret = p_open(&outfd, outfname, P_FTEXT | P_FUPDATE | P_FREPLACE) ;
  1293.     if (ret != 0)
  1294.     {
  1295.         p_errs(buff, ret) ;
  1296.         uDisplayText("FILE ERROR: cpyfile,","error in opening output", outfname, buff, NULL) ;
  1297.         p_close(infd) ;
  1298.         return(FILEERR) ;
  1299.     }
  1300.     /* copy the files */
  1301.     ret = 1 ;
  1302.     while(ret >= 0)
  1303.     {
  1304.         ret = p_read(infd, buff, P_FMAXRSIZE) ;
  1305.         if (ret < 0)
  1306.         {
  1307.             break ;
  1308.         }
  1309.         /* terminate the string */
  1310.         buff[ret] = '\0' ;
  1311.         p_scpym(tmp, "> ", buff, NULL) ;
  1312.         p_write(outfd, tmp, p_slen(tmp)) ;
  1313.     }
  1314.     /* close the files */
  1315.     p_close(infd) ;
  1316.     p_close(outfd) ;
  1317.     return(TRUE) ;
  1318. }
  1319.     
  1320.     
  1321. /* newfile, determine a safe new filename and create it */
  1322. INT newfile(struct ll * llcur, struct ll * llstart)
  1323. {
  1324.     TEXT mytempl[P_FNAMESIZE+1],  tmppath[P_FNAMESIZE+1];
  1325.     VOID * fd ;
  1326.     INT ret, i ;
  1327.     /* build up the name OUTSKELETON is assumed to contain a %d */
  1328.     p_scpym(mytempl, llstart->mydata->mypath, OUTSKELETON, NULL) ;
  1329.     for (i = 0 ; i < MAXEMAILOUT ; i ++ )
  1330.     {    
  1331.         /* basicaly run around untill we have a number for i
  1332.            that does not corespond to a file name */
  1333.         p_atos(tmppath, mytempl, i) ;
  1334.         ret = fileexist(tmppath) ;
  1335.         if (ret == TRUE)
  1336.         {
  1337.             /* the file exists, continue */
  1338.             continue ;
  1339.         }
  1340.         else if (ret == FALSE)
  1341.         {
  1342.             /* the file does not exist */
  1343.             break ;
  1344.         }
  1345.         else
  1346.         {
  1347.             uDisplayText("FILE ERROR: newemail,","Directory, Device or other error","recieved from fileexists when testing", tmppath, NULL) ;
  1348.             return(FILEERR) ;
  1349.         }
  1350.     }
  1351.     if (i >= MAXEMAILOUT)
  1352.     {
  1353.         uDisplayText("FILE ERROR: newfile,","maximum number outgoing emails exceeded", tmppath, NULL) ;
  1354.         return(FILEERR) ;
  1355.     }
  1356.     if ((ret = p_open(&fd, tmppath, P_FCREATE | P_FTEXT)) >= 0)
  1357.     {
  1358.         p_close(fd) ;
  1359.         p_atos(llcur->datafile, OUTSKELETON, i) ;
  1360.         return(TRUE) ;
  1361.     }
  1362.     else
  1363.     {
  1364.         uDisplayText("FILE ERROR: newfile,","error in creating new file", mytempl, NULL) ;
  1365.         return(FILEERR) ;
  1366.     }
  1367. }
  1368. /* end of ancilary data file functions */
  1369.  
  1370. /* start of meta file operations code */
  1371. /* the meta file consists of line terminated data in the following format */
  1372. /* the full path component, E.g. LOC::M\MAIL\ */
  1373. /* mu current email adress, e.g. tim.graves@uk.sun.com the following repeated */
  1374. /* datafile name, E.g. in1.msg or out1.msg */
  1375. /* to, a list of recieved addresses, e.g. tim.graves@uk.sun.com MUST contain at least one address */
  1376. /* from, the origionator of the email */
  1377. /* subject, obvious */
  1378. /* cc, the cc list */
  1379. /* bcc, the bcc list (empty on reciept */
  1380. /* read, N if the email is unread, R if read */
  1381. /*at the end of the repeats */
  1382. /* END */
  1383. /* No other items */
  1384. /* */
  1385. /* read in the data descriptions */
  1386. INT readmeta(TEXT * fname, struct ll * itemlist)
  1387. {
  1388.     VOID * fd ;
  1389.     INT ret ;
  1390.     ret = p_open(&fd, fname, P_FTEXT | P_FSHARE) ;
  1391.     if (ret < 0)
  1392.     {
  1393.         uDisplayText("FILE ERROR:  readmeta,","error in opening", fname, NULL) ;
  1394.         return (FILEERR) ;
  1395.     }
  1396.     /* load the one off data */
  1397.     ret = getf(fd, itemlist->mydata->mypath) ;
  1398.     if ( ret == FALSE)
  1399.     {
  1400.         uDisplayText("FILE ERROR: readmeta,","error in reading my path from", fname, NULL) ;
  1401.         return(FILEERR) ;
  1402.     }
  1403.     getf(fd, itemlist->mydata->myaddr) ;
  1404.     if (ret == FALSE)
  1405.     {
  1406.         uDisplayText("FILE ERROR: readmeta,","error in reading my address from", fname, NULL) ;
  1407.         return(FILEERR) ;
  1408.     }
  1409.     while((ret = readhdr(fd, itemlist))== TRUE)
  1410.         ;
  1411.     p_close(fd) ;
  1412.     if (ret == FILEERR)
  1413.     {
  1414.         uDisplayText("FILE ERROR: readmeta,","error in reading meta record from", fname, NULL) ;
  1415.         return(FILEERR) ;
  1416.     }
  1417.     return(TRUE) ;
  1418. }
  1419.  
  1420. /* write the data descriptions out */
  1421. INT wrtmeta(TEXT * fname, struct ll * itemlist) 
  1422. {
  1423.     VOID * fd ;
  1424.     INT ret ;
  1425.         
  1426.     ret = p_delete(fname) ; /* delete the origional file */
  1427.     if (ret < 0)
  1428.     {
  1429.         uDisplayText("FILE ERROR: wrtmeta,","error in deleting",fname,"prior to output", NULL) ;
  1430.         return(FILEERR) ;
  1431.     }
  1432.     ret = p_open(&fd, fname, P_FTEXT | P_FUPDATE | P_FREPLACE) ;
  1433.     if (ret < 0)
  1434.     {
  1435.         uDisplayText("FILE ERROR: wrtmeta,","error in opening", fname, "for output", NULL) ;
  1436.         p_close(fd) ;
  1437.         return(FILEERR) ;
  1438.     }
  1439.     /* write the one off data */
  1440.     ret = putf(fd, itemlist->mydata->mypath) ;
  1441.     if (ret == FILEERR)
  1442.     {
  1443.         uDisplayText("FILE ERROR: wrtmeta,","error in writting my path to", fname, NULL) ;
  1444.         p_close(fd) ;
  1445.         return(FILEERR) ;
  1446.     }
  1447.     ret = putf(fd, itemlist->mydata->myaddr) ;
  1448.     if (ret == FILEERR)
  1449.     {
  1450.         uDisplayText("FILE ERROR: wrtmeta,","error in writting my address to", fname, NULL) ;
  1451.         p_close(fd) ;
  1452.         return(FILEERR) ;
  1453.     }
  1454.     while(itemlist != NULL)
  1455.     {
  1456.         ret = wrthdr(fd, itemlist) ;
  1457.         if (ret == FILEERR)
  1458.             break ;
  1459.         itemlist = itemlist->next ;
  1460.     }
  1461.     if (ret == FILEERR)
  1462.     {
  1463.         uDisplayText("FILE ERROR: wrtmeta,","error in writting record to", fname, NULL) ;
  1464.         p_close(fd) ;
  1465.         return(FILEERR) ;
  1466.     }
  1467.     ret = putf(fd, "END") ;
  1468.     if (ret == FILEERR)
  1469.     {
  1470.         uDisplayText("FILE ERROR: wrtmeta,","error in writting terminator (END) to", fname, NULL) ;
  1471.         p_close(fd) ;
  1472.         return(FILEERR) ;
  1473.     }
  1474.     p_close(fd) ;
  1475.     return(TRUE) ;
  1476. }
  1477.  
  1478. /* read the from, subject and return path etc from the data file */
  1479. INT readhdr(VOID * fd, struct ll * itemlist)
  1480. {
  1481.     struct ll * newll ;
  1482.     TEXT datafile[20] ;
  1483.     TEXT to[HDRLEN] ;
  1484.     TEXT from[HDRLEN] ;
  1485.     TEXT subject[HDRLEN];
  1486.     TEXT cc[HDRLEN];
  1487.     TEXT bcc[HDRLEN];
  1488.     TEXT cread[HDRLEN] ;
  1489.     INT read, ret ;
  1490.     /* read in an entry */
  1491.     ret = getf(fd, datafile) ;
  1492.     if (ret == FILEERR)
  1493.     {
  1494.         uDisplayText("FILE ERROR: readhdr,","error in reading datafile", NULL) ;
  1495.         return(FILEERR) ;
  1496.     }
  1497.     if (p_scmp(datafile, "END") == 0)
  1498.         return(FALSE) ;
  1499.     ret = getf(fd, to) ;
  1500.     if (ret == FILEERR)
  1501.     {
  1502.         uDisplayText("FILE ERROR: readhdr,","error in reading to", NULL) ;
  1503.         return(FILEERR) ;
  1504.     }
  1505.     ret = getf(fd, from) ;
  1506.     if (ret == FILEERR)
  1507.     {
  1508.         uDisplayText("FILE ERROR: readhdr,","error in reading from", NULL) ;
  1509.         return(FILEERR) ;
  1510.     }
  1511.     ret = getf(fd, subject) ;
  1512.     if (ret == FILEERR)
  1513.     {
  1514.         uDisplayText("FILE ERROR: readhdr,","error in reading subject", NULL) ;
  1515.         return(FILEERR) ;
  1516.     }
  1517.     ret = getf(fd, cc) ;
  1518.     if (ret == FILEERR)
  1519.     {
  1520.         uDisplayText("FILE ERROR: readhdr,","error in reading cc", NULL) ;
  1521.         return(FILEERR) ;
  1522.     }
  1523.     ret = getf(fd, bcc) ;
  1524.     if (ret == FILEERR)
  1525.     {
  1526.         uDisplayText("FILE ERROR: readhdr,","error in reading bcc", NULL) ;
  1527.         return(FILEERR) ;
  1528.     }
  1529.     ret = getf(fd, cread) ;
  1530.     if (ret == FILEERR)
  1531.     {
  1532.         uDisplayText("FILE ERROR: readhdr,","error in reading read", NULL) ;
  1533.         return(FILEERR) ;
  1534.     }    
  1535.     if (cread[0] == 'R')
  1536.         read = RD ;
  1537.     else
  1538.         read = NEW ;
  1539.     
  1540.     /* get a new ll structure */
  1541.     newll = llnew ();
  1542.     /* fill in the structure */
  1543.     llfill(newll, datafile, to, from, subject, cc, bcc, ACTIVE, read, itemlist->count + 1) ;
  1544.     /* add the new item into the list */
  1545.     lladd(newll, itemlist) ;
  1546.     return(TRUE) ;
  1547. }
  1548. /* write a subject and destination etc to the data file */
  1549. INT wrthdr(VOID * fd, struct ll * item)
  1550. {
  1551.     INT ret ;
  1552.     /* only outut the record if its active */
  1553.     if (item->status != ACTIVE)
  1554.         return(TRUE) ;
  1555.     ret = putf(fd, item->datafile);
  1556.     if ( ret == FILEERR)
  1557.     {
  1558.         uDisplayText("FILE ERROR: wrthdr,","error in writting datafile", item->datafile, NULL) ;
  1559.         return(FILEERR) ;
  1560.     }
  1561.     ret = putf(fd, item->to) ;
  1562.     if ( ret == FILEERR)
  1563.     {
  1564.         uDisplayText("FILE ERROR: wrthdr,","error in writting to", item->to, NULL) ;
  1565.         return(FILEERR) ;
  1566.     }
  1567.     ret = putf(fd, item->from) ;
  1568.     if ( ret == FILEERR)
  1569.     {
  1570.         uDisplayText("FILE ERROR: wrthdr,","error in writting from", item->from, NULL) ;
  1571.         return(FILEERR) ;
  1572.     }
  1573.     ret = putf(fd, item->subject) ;
  1574.     if ( ret == FILEERR)
  1575.     {
  1576.         uDisplayText("FILE ERROR: wrthdr,","error in writting subject", item->subject, NULL) ;
  1577.         return(FILEERR) ;
  1578.     }
  1579.     ret = putf(fd, item->cc) ;
  1580.     if ( ret == FILEERR)
  1581.     {
  1582.         uDisplayText("FILE ERROR: wrthdr,","error in writting cc", item->cc, NULL) ;
  1583.         return(FILEERR) ;
  1584.     }
  1585.     ret = putf(fd, item->bcc) ;
  1586.     if ( ret == FILEERR)
  1587.     {
  1588.         uDisplayText("FILE ERROR: wrthdr,","error in writting bcc", item->bcc, NULL) ;
  1589.         return(FILEERR) ;
  1590.     }
  1591.     if (item->read == RD)
  1592.         ret = putf(fd, "R") ;
  1593.     else
  1594.         ret = putf(fd, "N") ;
  1595.     if ( ret == FILEERR)
  1596.     {
  1597.         uDisplayText("FILE ERROR: wrthdr,","error in writting read", item->read == RD ? "R" : "N", NULL) ;
  1598.         return(FILEERR) ;
  1599.     }
  1600.     return(TRUE) ;
  1601. }
  1602. /* end of meta file operations code */
  1603.  
  1604. /* start of ancillary file and keyboard IO code */
  1605. /* read a line of text from file handle */
  1606. INT getf(VOID * fd, TEXT * line)
  1607. {
  1608.     INT ret ;
  1609.     ret = p_read(fd, (VOID *) line, HDRLEN) ;
  1610.     if (ret < 0)
  1611.         return(FILEERR) ;
  1612.     line[ret] = '\0' ;
  1613.  
  1614.     return(TRUE) ;
  1615. }
  1616. /* write a line of text to file handle */
  1617. INT putf(VOID * fd, TEXT * line)
  1618. {
  1619.     INT ret ;
  1620.     ret = p_write(fd, (VOID *) line, p_slen(line)) ;
  1621.     if (ret < 0)
  1622.         return(FILEERR) ;
  1623.  
  1624.     return(TRUE) ;
  1625. }
  1626.  
  1627. /* end of ancillary file and keyboard IO code */
  1628. /* does the file given in fname exist return TRUE or FALSE
  1629.    if any other error than E_FILE_NXIST return FILEERR */
  1630. INT fileexist(TEXT * fname)
  1631. {
  1632.     P_INFO pinf ;
  1633.     INT ret ;
  1634.     ret = p_finfo(fname, &pinf) ;
  1635.     if (ret == 0)
  1636.     {
  1637.         return(TRUE) ;
  1638.     }
  1639.     else if (ret == E_FILE_NXIST)
  1640.     {
  1641.         return(FALSE) ;
  1642.     }
  1643.     else if ((ret == E_FILE_DEVICE) || (ret == E_FILE_NOTREADY) || (ret == E_FILE_DIR))
  1644.     {
  1645.         /* this is a major problem with the path */
  1646.         uDisplayText("FILE ERROR: fileexist,","Directory or Device does not exist", fname, NULL) ;
  1647.         return(FILEERR) ;
  1648.     }
  1649.     else /* some other unexpected error */
  1650.     {
  1651.         uDisplayText("FILE ERROR: fileexist,","unxepected error code from p_finfo", NULL) ;
  1652.         return(FILEERR) ;
  1653.     }
  1654. }
  1655. /* start of window functions */
  1656. /* Print the output list */
  1657. VOID redolist(VOID)
  1658. {
  1659.     TEXT str[100] ;
  1660.     UINT border ;
  1661.     /* print the headers around the current email */
  1662.     /* disphdrs will arrange for the current item to be bold and ITEMS_IN_LIST 
  1663.        to be printed (if possible ) */
  1664.     disphdrs(currlist) ;
  1665.     /* do the borders, aqquire the current gc */
  1666.     gSetGC0(gchdr) ;
  1667.     /* if mailno is greater then ITEMS_IN_HALF_LIST + 1 then put an up arrow 
  1668.        on the display if there are items on the bottom of the display */
  1669.     border = W_BORD_CUSHION|W_BORD_CORNER_4 ;
  1670.     if (mailno > (ITEMS_ON_HALF_SCREEN +1))
  1671.         border = border | W_BORD_TOP_ON ;
  1672.     else
  1673.         border = border |W_BORD_TOP_OFF ;
  1674.     /* if currlist->count - mailno is greater than ITEMS_ON_HALF_SCREEN + 1 then put a 
  1675.        down arrow on the display */
  1676.     if (mailno < (currlist->count - ITEMS_ON_HALF_SCREEN))
  1677.         border = border |W_BORD_BOT_ON ;
  1678.     else
  1679.         border = border |W_BORD_BOT_OFF ;
  1680.  
  1681.     gBorder(border) ;
  1682.     /* update the status message */
  1683.     p_atos(str, "%s, Mail no %d of %d", currlist == inlist ? "Incomming list" : "Outgoing List", mailno, currlist->count) ;
  1684.     statusmsg(str) ;
  1685. }
  1686.     
  1687.  
  1688. VOID statusmsg(TEXT * str)
  1689. {
  1690.     TEXT tmp[300] ;
  1691.     /* get hold of the current context */
  1692.     gSetGC0(gcstatus) ;
  1693.     /* sometimes the border gets trashed so rederw it */
  1694.     gBorder(W_BORD_CUSHION|W_BORD_CORNER_4) ;
  1695.     p_scpym(tmp, str, blank, NULL) ;
  1696.     gPrintClipText(5,12,tmp, p_slen(tmp), 220) ;
  1697. }
  1698.  
  1699. INT askincl()
  1700. {
  1701.     struct ll * llptr ;
  1702.     INT ret ;
  1703.     
  1704.     /* only include the current email if mailno is valid */
  1705.     llptr = llnofind(mailno, currlist) ;
  1706.     if (llptr == NULL)
  1707.         return(FALSE) ;
  1708.     uOpenDialog("Include Current Email ?") ;
  1709.     uAddButtonList("Yes", 'y', "No", 'n', NULL) ;
  1710.     ret = uRunDialog() ;
  1711.     if (ret == 'y')
  1712.         return(TRUE) ;
  1713.     else
  1714.         return(FALSE) ;
  1715. }
  1716.