/*----------------------------------------------------------------------

            T H E    P I N E    M A I L   S Y S T E M

   Laurence Lundblade and Mike Seibel
   Networks and Distributed Computing
   Computing and Communications
   University of Washington
   Administration Building, AG-44
   Seattle, Washington, 98195, USA
   Internet: lgl@CAC.Washington.EDU
             mikes@CAC.Washington.EDU

   Please address all bugs and comments to "pine-bugs@cac.washington.edu"

   Copyright 1989, 1990, 1991, 1992  University of Washington

    Permission to use, copy, modify, and distribute this software and its
   documentation for any purpose and without fee to the University of
   Washington is hereby granted, provided that the above copyright notice
   appears in all copies and that both the above copyright notice and this
   permission notice appear in supporting documentation, and that the name
   of the University of Washington not be used in advertising or publicity
   pertaining to distribution of the software without specific, written
   prior permission.  This software is made available "as is", and
   THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
   WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
   NO EVENT SHALL THE UNIVERSITY OF WASHINGTON 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, TORT
   (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
   WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  

   Pine is in part based on The Elm Mail System:
    ***********************************************************************
    *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $          *
    *                                                                     *
    * 			Copyright (c) 1986, 1987 Dave Taylor              *
    * 			Copyright (c) 1988, 1989 USENET Community Trust   *
    ***********************************************************************
 

  ----------------------------------------------------------------------*/

/*======================================================================
    imap.c
    The call back routines for the c-client/imap
       - handles error messages and other notification
       - handles prelimirary notification of new mail and expunged mail
       - prompting for imap server login and password 

 ====*/

#include "headers.h"


/*----------------------------------------------------------------------
      Write imap debugging information into log file

   Args: strings -- the string for the debug file

 Result: message written to the debug log file
  ----*/
void mm_dlog(string)
     char *string;
{
    dprint(0, (debugfile, "IMAP DEBUG: %s\n", string));
}



/*----------------------------------------------------------------------
      Queue imap log message for display in the message line

   Args: string -- The message 
         errflg -- flag set to 1 if pertains to an error

 Result: Message queued for display

 The c-client/imap reports most of it's status and errors here
  ---*/
void mm_log(string, errflg)
     char *string;
     long  errflg;
{
    char        message[300];
    char       *occurance;
    int         was_capitalized;
    long        now;
    struct tm  *tm_now;

    now = time(0);
    tm_now = localtime(&now);

    dprint(errflg == ERROR ? 1 : 2, (debugfile,
                                     "IMAP %d:%d %d/%d mm_log %s: %s\n",
                                     tm_now->tm_hour, tm_now->tm_min,
                                     tm_now->tm_mon+1, tm_now->tm_mday,
                                     errflg == ERROR ? "ERROR" :
                                     errflg == WARN  ? "warn"  :
                                     errflg == PARSE ? "parse" : "babble",
                                     string));

    /*---- replace all "mailbox" with "folder" ------*/
    strncpy(message, string, sizeof(message));
    message[sizeof(message) - 1] = '\0';
    occurance = srchstr(message, "mailbox");
    while(occurance != NULL) {
        was_capitalized = isupper(*occurance);
        rplstr(occurance, 7, (errflg == PARSE ? "address" : "folder"));
        if(was_capitalized)
          *occurance = (errflg == PARSE ? 'A' : 'F');
        occurance = srchstr(occurance, "mailbox");
    }

    if(errflg == PARSE || ps_global->noshow_error) 
      strcpy(ps_global->c_client_error, message);

    if(ps_global->noshow_error || (errflg != ERROR && errflg != WARN))
      return; /* Only care about errors; don't print when asked not to */

    /*---- Display the message ------*/
    q_status_message1(1, errflg == ERROR ? 3 : 2, 5, "\007%s", message);
    strcpy(ps_global->last_error, message);
    display_message('x');
    fflush(stdout);
}




/*----------------------------------------------------------------------
         recieve notification from IMAP

  Args: stream  --  Mail stream message is relavant to 
        string  --  The message text
        errflag --  Set if it is a serious error

 Result: message displayed in status line

 The facility is for general notices, such as connection to server;
 server shutting down etc... It is used infrequently.
  ----------------------------------------------------------------------*/
void mm_notify(stream, string, errflag)
     MAILSTREAM *stream;
     char       *string;
     long        errflag;
{
    dprint(1, (debugfile, "IMAP mm_notify %s : %s : %s\n",
               errflag == ERROR ? "error" : "warning" ,
               stream != NULL && stream->mailbox != NULL ? stream->mailbox :
               "-no folder-" ,
               string));
    q_status_message2(1, errflag == ERROR ? 2 : 1, 6,
                      errflag == ERROR ?"\007%s : %s" : "%s : %s",
                      stream != NULL && stream->mailbox != NULL ?
                      stream->mailbox : "-no folder-", string);

    sprintf(ps_global->last_error,
            "%s : %s", stream != NULL&& stream->mailbox != NULL?
            stream->mailbox : "-no folder-",
            string);
}



/*----------------------------------------------------------------------
       receive notification of new mail from imap daemon

   Args: stream -- The stream the message count report is for.
         number -- The number of messages now in folder.
 
  Result: Sets value in pine state indicating new mailbox size

    Called when the number of messages in the mailbox goes up.
  We set new_max_msgno to the new value and let what ever other part of
  Pine check the variable, discover the new messages and do what is
  appropriate. This may also be called as a result of an expunge.
 ----*/

void mm_exists(stream, number_l)
     MAILSTREAM *stream;
     long number_l;
{
    int number = (int)number_l;
    dprint(3, (debugfile, "=== mm_exists(%ld,%s) called ===\n", number,
                                                            stream->mailbox));
    if(stream == ps_global->inbox_stream  &&
                            ps_global->inbox_stream != ps_global->mail_stream){
        ps_global->inbox_changed |= (ps_global->inbox_max_msgno != number);
        if(ps_global->inbox_max_msgno < number)
          ps_global->inbox_new_mail_count += number-ps_global->inbox_max_msgno;
        ps_global->inbox_max_msgno = number;
    } else if(stream == ps_global->mail_stream) {
        ps_global->mail_box_changed |= (ps_global->max_msgno != number);
        if(ps_global->max_msgno < number)
          ps_global->new_mail_count +=  number - ps_global->max_msgno;
        ps_global->max_msgno = number;
    } else {
        /*--- ignore mm_exist for other. These are quick opens --*/
    }
}


/*----------------------------------------------------------------------
    Receive notification from IMAP that a message has been expunged

   Args: stream -- The stream/folder the message is expunged from
         number -- The message number that was expunged

mm_expunged is always called on an expunge. mm_exists() which reports
the current number of messages is sometimes called, depending on the
kind of mail file (Bezerk, imap...). For this reason there are two
expunge counts. tot_expunge_count counts the total messages expunged
since the last new mail check. The new mail check will only see a
change in the number of messages and not know how the change was made
up as a result of adds and deletes unless it has the
total_expunge_count. The secound counter, expunge_count, counts
messages expunged between calls to mm_exists handling the case where
mm_expunged is called without mm_exists() being called. See new_mail()
for more details.
  ----*/
void mm_expunged(stream, number_l)
     MAILSTREAM *stream;
     long        number_l;
{
     dprint(3, (debugfile, "mm_expunged called %s %ld\n",
                                                 stream->mailbox, number_l));
     if(stream == ps_global->inbox_stream &&
            ps_global->inbox_stream != ps_global->mail_stream) {
         ps_global->inbox_expunge_count++;
         ps_global->inbox_changed = 1;
         ps_global->inbox_max_msgno--;
    } else {
         ps_global->expunge_count++;
         ps_global->mail_box_changed = 1;
         ps_global->max_msgno--;
    }
}



/*----------------------------------------------------------------------
      Get login and password from user for IMAP login
  
  Args:  host   -- The host name the user is trying to log in to 
         user   -- Buffer to return the user name in 
         passwd -- Buffer to return the passwd in
         tial   -- The trial number or number of attempts to login

 Result: username and password passed back to imap
  ----*/
void mm_login(host, user, passwd, trial)
     char *host;
     char *user;
     char *passwd;
     long  trial;
{
    static char x_user[80] = {'\0'}, x_passwd[80] = {'\0'},
                junk[] = {'?', '\0'};
    char prompt[80], **help ;
    int  rc, q_line;

    q_line =  -3; /* 3 from bottom */

    if(messages_queued()) {
        display_message(NO_OP_COMMAND);
        sleep(1);
    }

    if(ps_global->nr_mode) {
        /*------ Anonymous login mode --------*/
        if(trial >= 1) {
            user[0]   = '\0';
            passwd[0] = '\0';
        } else {
            strcpy(user, "anonymous");
            sprintf(passwd, "%s@%s", get_system_login(), ps_global->hostname);
        }
        return;
    }

        
    if(x_user[0] == '\0')
      strcpy(x_user, ps_global->VAR_USER_ID);

    /* try our old passwd once */
    if(trial == 0L && strlen(x_user) > 0 && strlen(x_passwd) > 0) {
	strcpy(user, x_user);
	strcpy(passwd, x_passwd);
	return;
    }

    ps_global->mangled_footer = 1;
    help = NULL;
    sprintf(prompt, "HOST: %s  ENTER LOGIN NAME: ", host);
    while(1) {
        rc = optionally_enter(x_user, q_line, 0, sizeof(x_user) - 1, 1, 0,
                              prompt, NULL, help, 0);
        if(rc == 3) {
            help = help == NULL ? h_oe_login : NULL;
            continue;
        }
        if(rc != 4)
          break;
    }

    if(rc == 1) {
        user[0]   = '\0';
        passwd[0] = '\0';
        return;
    }



    help = NULL;
    sprintf(prompt, "HOST: %s  USER: %s  ENTER PASSWORD: ", host, x_user);
    while(1) {
        rc = optionally_enter(x_passwd, q_line, 0, sizeof(x_passwd) - 1, 0,
                               1, prompt, NULL, help, 0);
        if(rc == 3) {
            help = help == NULL ? h_oe_passwd : NULL;
            continue;
        }
        if(rc != 4)
          break;
    }
    if(rc == 1) {
        strcpy(user,junk);
        strcpy(passwd, junk);
        return;
    }

    strcpy(user, x_user);
    strcpy(passwd, x_passwd);
/*    dprint(2, (debugfile, "host:[%s]  name[%s]  passwd[%s]\n", host, user,
	       passwd)); */
}
    



/*---------------------------------------------------------------------- 
        receive notification that search found something           

 Input:  mail stream and message number of located item

 Result: nothing, not used by pine
  ----*/
void mm_searched(stream, msg_no_l)
     MAILSTREAM *stream;
     long        msg_no_l;
{
    char tmp[20];
    int  msg_no = (int)msg_no_l;

    sprintf(tmp,"%ld",msg_no);
    q_status_message2(0, 2,4, "\007 %s searched %s",
		      stream ? stream->mailbox : "<no folder>", tmp);
}


/*----------------------------------------------------------------------
       Receive notification of an error writing to disk
      
  Args: stream  -- The stream the error occured on
        errcode -- The system error code (errno)
        serious -- Flag indicating error is serious (mail may be lost)

Result: If error is non serious, the stream is marked as having an error
        and deletes are disallowed until error clears
        If error is serious this goes modal, allowing the user to retry
        of get a shell escape to fix the condition. When the condition is
        serious it means that mail existing in the mailbox will be lost
        if Pine exists without writing so we try to induce the user to 
        fix the error, go get some one that can fix the error or whatever
        and don't provide an easy way out.
  ----*/

long
mm_diskerror (stream, errcode, serious)
     MAILSTREAM *stream;
     long        errcode;
     long        serious;
{
    int line, ch;
    char q[200];

    dprint(0, (debugfile,
       "\n***** DISK ERROR on stream %s. Error code %ld. Error is %sserious\n",
               stream ? stream->mailbox : "<no mail folder>", errcode,
               serious ? "" : "not "));
    dprint(0, (debugfile, "***** message: \"%s\"\n\n", ps_global->last_error));

    if(!serious) {
/*        q_status_message2(1, 3, 6,"\007Error saving mail folder \"%s\" : %s",
                    pretty_fn(stream ? stream->mailbox : ""),
                          error_description((int)errcode)); */
        if(stream == ps_global->mail_stream) {
            ps_global->io_error_on_stream = 1;
        }
        return (1) ;
    }

    line = ps_global->ttyo->screen_rows - 3;
    MoveCursor(line, 0);
    CleartoEOLN();
    StartInverse();
    Writechar('\007', 0);
    sprintf(q,  "Serious error saving mail folder \"%s\":",
                    pretty_fn(stream ? stream->mailbox : ""));
    PutLine0(line, 0, q);
    ch = strlen(q); /* Use ch temporarily */
    MoveCursor(line, ch);
    while(ch++ < ps_global->ttyo->screen_cols - 1)
      Writechar(' ', 0);
/*    sprintf(q, "%-*.*s", ps_global->ttyo->screen_cols - 1,
            ps_global->ttyo->screen_cols - 1,
            ps_global->last_error);
    d_q_status_message();
    PutLine0(line+1, 0, q); */
    if(ps_global->can_suspend) {
        sprintf(q,  "Press return to retry saving or press ^Z to suspend Pine: ");
    } else {
        sprintf(q,  "Press return to retry saving or press ! to get to system prompt: ");
    }
    PutLine0(line+2, 0, q);
    Writechar('\007', 0);
    ch = strlen(q); /* Use ch temporarily */
    MoveCursor(line+2, ch);
    while(ch++ < ps_global->ttyo->screen_cols - 1)
      Writechar(' ', 0);
    MoveCursor(line+2, strlen(q));
    fflush(stdout); 

    ch = read_char(0);
    while(!(ch == ps_global->can_suspend ? ctrl('Z') : '!' || ch == '\r')) {
        Writechar('\007', 0);
        fflush(stdout);
        ch = read_char(0);
    }
    switch(ch) {
      case '\r':
        Write_to_screen("Retry");
        EndInverse();
        MoveCursor(line -2, 0);
        fflush(stdout);
        return (0L);
       
      case '!':
        EndInverse();
        end_keyboard(ps_global != NULL ? ps_global->use_fkeys : 0);
        end_tty_driver(ps_global);
        printf("\n\nPlease attempt to correct the error preventing the saving of the mail folder.\n");
        printf("For example if the disk is out of space try removing uneeded files.\n");
        printf("You might also contact your system administrator.\n");
        printf("Give the command \"exit\" to get back to Pine and try saving the folder again.\n");

        system("csh");

        init_tty_driver(ps_global);
        init_keyboard(ps_global->use_fkeys);
        MoveCursor(line - 2, 0);
        return (0L); /* go retry it again */
       
      case ctrl('Z'):
        EndInverse();
        do_suspend(ps_global);
        break;
    }
    return(0);
}



/*----------------------------------------------------------------------
      Receive list of folders from c-client/imap.
 
Pine doesn't use this (yet).
 ----*/
   
void mm_mailbox(name)
char *name;
{
    name = name;
}



/*----------------------------------------------------------------------
     Receive list of bulliten boards from c-client/imap

Pine doesn't use this.
 ----*/

void mm_bboard(name)
char *name;
{
   name = name;
}


void
mm_fatal(message)
     char *message;
{
    panic(message);
}
