/*
 * xmail - X window system interface to the mail program
 *
 * Copyright 1990,1991,1992 by National Semiconductor Corporation
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of National Semiconductor Corporation not
 * be used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
 * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS"
 * WITHOUT EXPRESS OR IMPLIED WARRANTY.  NATIONAL SEMICONDUCTOR CORPORATION
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
 * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * The following software modules were created and are Copyrighted by National
 * Semiconductor Corporation:
 *
 * 1. In_System_Folder:
 * 2. icon_handler:
 * 3. index_handler:
 * 4. info_handler: and
 * 5. file_handler.
 *
 * Author:  Michael C. Wagnitz - National Semiconductor Corporation
 *
 */


#include <ctype.h>
#include "global.h"
#include "MailwatchP.h"
#include <X11/Xaw/LabelP.h>

Boolean	In_Bogus_Mail_File = False;	/* TRUE when we go iconic */

/*
** Examine the current value of the titleBar title and return TRUE/FALSE
** to the question "Does it match the system mail folder name?"  The folder
** name in the title bar label should be surrounded by a pair of quote marks.
*/
int
In_System_Folder(void)
{
 int		len, result;
 char		*fq, *lq, *buf;
 Arg		args[1];
 MailwatchWidget mb = (MailwatchWidget) XtNameToWidget(toplevel, "icon.mailbox");
 Widget		tb = XtNameToWidget(toplevel, "topBox.titleBar.title");


 XtSetArg(args[0], XtNlabel, &buf);
 XtGetValues(tb, args, 1);

 if ((lq = strrchr(buf, '"')) == NULL) result = FALSE;
 else {					/* if a current folder name exists */
    if ((fq = strchr(buf, '"')) == NULL) result = FALSE;
    else {
       ++fq;
       len = lq - fq;
       result = (strncmp(mb->mailbox.filename, fq, len) == 0) ? TRUE : FALSE ;
      }
   }
 return(result);
} /* In_System_Folder */


/*
** Process map and unmap events for the icon widget to manage our iconify and
** deiconify actions and switch to/from a bogus mail folder.  This allows users
** to access mail from another process without colliding with an open folder.
** Once the bogus mail folder is accessed, we unlink it, to avoid having to
** explicitly remove it later.
*/
/* ARGSUSED */
void 
icon_handler(Widget w, XtPointer closure , XEvent *event, Boolean *continueToDispatch)
{
 static Boolean	Was_System_Folder = False;	/* TRUE if we had been in */
 FILE	*fp;
 char	*cp, cmd[BUFSIZ];


 if (mailpid) {
    switch (event->type) {
           case MapNotify :
                if (! In_Bogus_Mail_File) {
                   Was_System_Folder = In_System_Folder();
                   (void) sprintf(cmd, "%s+", tmpName);
                   if (fp = fopen(cmd, "w")) {	/* create a bogus mail file */
                      (void) fprintf(fp, "\n");
                      (void) fclose(fp);
                      (void) sprintf(cmd, "file %s+", tmpName);
                      cp = QueryMail(cmd);	/* focus our attention there */
                      *cp = '\0';
		      (void) UpdateTitleBar("No current folder");
    		      writeTo(XtNameToWidget(toplevel, "*indexWindow"), " ", REPLACE);
    		      writeText(" ");
                      (void) sprintf(cmd, "%s+", tmpName);
                      (void) unlink(cmd);	/* toss it now that we're in */
                      In_Bogus_Mail_File = True;
                     }
                  }
                break;
           case UnmapNotify :
                if (In_Bogus_Mail_File) {
                   if (strcmp(Command, "Start") != 0) {	/* if not starting up */
                      if (Was_System_Folder) {		/* go to system file */
                         (void) strcpy(Command, "file %\n");
                        } else {			/* go to prev. file */
                         (void) strcpy(Command, "file #\n");
                        }
                     } else {
                      if (XMail.MFileName) {	/* start in specified folder */
                         (void) sprintf(Command, "file %s\n", XMail.MFileName);
                        } else {		/* or else use system folder */
                         (void) strcpy(Command, "file %\n");
                        }
                     }
                   SetCursor(WATCH);
                   writeMail(Command);		/* let parser do the updating */
                   In_Bogus_Mail_File = False;
                   Was_System_Folder = False;
                  } else if (In_System_Folder())
                            UnsetNewmail(NULL, NULL, NULL);
                break;
           default:
                break;
          } /* end - switch on event type */
   } /* end - if mail is active */
} /* icon_handler */


/*
** @(#)index_handler() - find value of specified or next appropriate message
*/
int
index_handler(int msg_num, int undeleting)
{
 int			j, k;
 XawTextPosition	pos;
 String			c, s, IBuf;
 Widget			iw;
 Arg			args[1];


 Bell("");					/* reset bell worthyness flag */
 Bell(Default_Status_Info);

 k = msg_num;					/* Try to use specified msg. */
 if (k == 0) {					/* But, if not specified... */
    c = QueryMail("=");
    if (*c)
       (void) sscanf(c, "%d", &k);		/* get msg num from mail. */
   }

 iw = XtNameToWidget(toplevel, "topBox.indexWindow");
 IBuf = NULL;
 XtSetArg(args[0], XtNstring, &IBuf);
 XtGetValues(iw, args, 1);

 if (k <= 50) {					/* do short index from front */
    s = IBuf;
    for (j = k - 1; j > 0 && (c = strchr(s, '\n')) != NULL; j--) s = c + 1;
   } else {					/* if index is fairly large */
    for (s = &IBuf[strlen(IBuf) - 2]; s > IBuf && *s != '\n'; s--);
    for (c = s + 1; *c && !isdigit(*c); c++);	/* get number of last entry */
    j = 0;
    if (*c)
       (void) sscanf(c, "%d", &j);		/* look backwards from there */
    for (; j > k; j--) {
        if (s > IBuf) s--;
        for (; s > IBuf && *s != '\n'; s--);
       }
    if (*s == '\n') s++;
   } 

 j = k;
 for (;;) {					/* allow for deleted msgs */
     for (c = s; *c && !isdigit(*c); c++);
     if (! *c || k == 0 ||
	(sscanf(c, "%d", &j) && j <= k))	/* total may be less than us */
        break;

     if (s - 2 >= IBuf)
        for (s -= 2; s > IBuf && *s != '\n'; s--);
     if (*s == '\n') s++;
    }

 if (! undeleting && *(s + 1) == 'D') {		/* If this is a deleted msg */
    j = 0;					/* then num is inappropriate */
    for (;*s && *(s + 1) == 'D';) {		/* try looking above deletes */
        if (! (c = strchr(s,'\n'))) break;	/* don't go past end of buf */
        s = c + 1;
       }
    for (;s > IBuf && *(s + 1) == 'D';) {
        for (s -= 2; s > IBuf && *s != '\n'; s--);
        if (*s == '\n') s++;
       }
    if (*(s + 1) != 'D') {			/* If we found a readable msg */
       for (c = s; *c && !isdigit(*c); c++);
       if (*c)
          (void) sscanf(c, "%d", &j);
      }
   }

 if (j) {					/* if we have a valid msg num */
    pos = s - IBuf;				/* resolve our position */
    XawTextSetInsertionPoint(iw, pos);		/* point at selected line */
    markIndex("> ");				/* flag it as current */
   }

 return(j);					/* return msg actually found */
} /* index_handler */


/*
** @(#)info_handler - use enter/leave_notify events to alter status window info
*/
/*ARGSUSED*/
void
info_handler(Widget w, XtPointer client_data, XEvent *event, Boolean *continueToDispatch)
      	  				/* unused */
       	            
      	       
{
 if      (event->type == LeaveNotify && ! Waiting) Bell(Default_Status_Info);
 else if (event->type == EnterNotify) {
         if (! Waiting) Bell(client_data);
         Waiting = FALSE;
        }
} /* end - info_handler */


/*
** @(#)file_handler() - Handle output of Start and file commands.
**                      If *Show_Last: resource is TRUE show last
**                      message in list, if none are marked as new.
*/
file_handler(void)
{
 int			New_Unread, msg_num = 0;
 char			*c, *p, *headers = NULL;
 char			msgnum_str[10];
 XawTextPosition	pos;
 Widget			iw = XtNameToWidget(toplevel, "topBox.indexWindow");


 c = QueryMail("file");				/* Forces msg to first New/U */
 if (! mailpid) return (msg_num);

 if (! In_Bogus_Mail_File)
    (void) UpdateTitleBar(c);

 c = QueryMail("=");				/* Get current mail msg num. */
 while (! isdigit(*c)) {
    if (! mailpid) return (msg_num);
    c = QueryMail("=");
   }
 (void) sprintf(msgnum_str, c);

 *c = '\0';
 if (! mailpid) return (msg_num);
 
 headers = QueryMail("h");
 if (strncmp(headers, "No applicable messages", 22) == 0) {
    Bell(headers);
    writeTo(iw, " ", REPLACE);
    writeText(" ");
   } else {
    /*
    ** find mail's idea of this folder's current message number
    */
    if (*headers == '>') c = headers;
    else				/* start search from the end of buf */
       if (c = strrchr(headers, '\n')) c++;
       else c = headers;

    while (c > headers) {
          if (*c == '>' && *(c - 1) == '\n')
             break;

          for (c -= 2; c > headers && *c != '\n'; c--);
          if (*c == '\n') c++;
         }
    /*
    ** If the current message is marked new or unread, ensure as many of the new
    ** message headers as possible are displayed in the index window (especially
    ** the current one), else if the Show_Last resource is not false, select the
    ** last message in the header.
    */
    p = c;					/* save position of current */
    New_Unread = (*(c+1) == 'N' || *(c+1) == 'U');
    if (! New_Unread && XMail.Show_Last) {	/* find the last message */
       if (*p == '>') *p = ' ';			/* erase the original marker */
       if (c == headers) {			/* if we would've started @1 */
          if (p = strrchr(headers, '\n')) p++;
          else p = headers;			/* go to last line of buffer */
         }
       for (c = p; *c && !isdigit(*c); c++);
       if (*c)
          (void) sscanf(c, "%d", &msg_num);
       (void) sprintf(msgnum_str, "%d", msg_num);
      }
    /*
    ** mark the current message's index line
    */
    *p = '>'; *(p+1) = ' ';
    /*
    ** Install these headers in the index window
    */
    writeTo(iw, headers, REPLACE);
    /*
    ** Ensure if there are new or unread messages that as many as possible are
    ** displayed in the index window to reduce the amount of scrolling required
    ** when reading(/deleting) them.
    */
    pos = p - headers;
    if (New_Unread)
       XawTextSetInsertionPoint(iw, strlen(headers));
    XawTextSetInsertionPoint(iw, pos);
    /*
    ** Return the current message number.
    */
    msg_num = atoi(msgnum_str);
   }
 *headers = '\0';
 return(msg_num);
} /* file_handler */
