#if !defined(lint) && !defined(DOS)
static char rcsid[] = "$Id: init.c 101 2006-08-10 22:53:04Z mikes@u.washington.edu $";
#endif

/*
 * ========================================================================
 * Copyright 2006-2007 University of Washington
 * Copyright 2013-2020 Eduardo Chappa
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * ========================================================================
 */

/*======================================================================
     init.c

  Session initiation support routines

 ====*/


#include "headers.h"

#include "../pith/init.h"
#include "../pith/conf.h"
#include "../pith/status.h"
#include "../pith/folder.h"
#include "../pith/context.h"

#include "init.h"


/* these are used to report folder directory creation problems */
CONF_TXT_T init_md_exists[] =	"The \"%s\" subdirectory already exists, but it is not writable by Alpine so Alpine cannot run.  Please correct the permissions and restart Alpine.";

CONF_TXT_T init_md_file[] =	"Alpine requires a directory called \"%s\" and usually creates it.  You already have a regular file by that name which means Alpine cannot create the directory.  Please move or remove it and start Alpine again.";

CONF_TXT_T init_md_create[] =	"Creating subdirectory \"%s\" where Alpine will store its mail folders.";


/*
 * Internal prototypes
 */
char	*context_string(char *);
int	 prune_folders(CONTEXT_S *, char *, int, char *, unsigned);
int	 prune_move_folder(char *, char *, CONTEXT_S *);
void	 delete_old_mail(struct sm_folder *, CONTEXT_S *, char *);



/*----------------------------------------------------------------------
    Make sure the alpine folders directory exists, with proper folders

   Args: ps -- alpine structure to get mail directory and contexts from

  Result: returns 0 if it exists or it is created and all is well
                  1 if it is missing and can't be created.
  ----*/
int
init_mail_dir(struct pine *ps)
{

/* MAIL_LIST: can we use imap4 CREATE? */
    /*
     * We don't really care if mail_dir exists if it isn't 
     * part of the first folder collection specified.  If this
     * is the case, it must have been created external to us, so
     * just move one...
     */
    if(ps->VAR_FOLDER_SPEC && ps->VAR_FOLDER_SPEC[0]){
	char *p  = context_string(ps->VAR_FOLDER_SPEC[0]);
	int   rv = strncmp(p, ps->VAR_MAIL_DIRECTORY,
			   strlen(ps->VAR_MAIL_DIRECTORY));
	fs_give((void **)&p);
	if(rv)
	  return(0);
    }

    switch(is_writable_dir(ps->folders_dir)){
      case 0:
        /* --- all is well --- */
	return(0);

      case 1:
	snprintf(tmp_20k_buf, SIZEOF_20KBUF, init_md_exists, ps->folders_dir);
	display_init_err(tmp_20k_buf, 1);
	return(-1);

      case 2:
	snprintf(tmp_20k_buf, SIZEOF_20KBUF, init_md_file, ps->folders_dir);
	display_init_err(tmp_20k_buf, 1);
	return(-1);

      case 3:
	snprintf(tmp_20k_buf, SIZEOF_20KBUF, init_md_create, ps->folders_dir);
	display_init_err(tmp_20k_buf, 0);
#ifndef	_WINDOWS
    	sleep(4);
#endif
        if(create_mail_dir(ps->folders_dir) < 0){
            snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Error creating subdirectory \"%s\" : %s",
		    ps->folders_dir, error_description(errno));
	    display_init_err(tmp_20k_buf, 1);
            return(-1);
        }
    }

    return(0);
}


/*----------------------------------------------------------------------
  Make sure the default save folders exist in the default
  save context.
  ----*/
void
display_init_err(char *s, int err)
{
#ifdef	_WINDOWS
    mswin_messagebox(s, err);
#else
    int n = 0;

    if(err)
      fputc(BELL, stdout);

    for(; *s; s++)
      if(++n > 60 && isspace((unsigned char)*s)){
	  n = 0;
	  fputc('\n', stdout);
	  while(*(s+1) && isspace((unsigned char)*(s+1)))
	    s++;
      }
      else
	fputc(*s, stdout);

    fputc('\n', stdout);
#endif
}


/*
 * Return malloc'd string containing only the context specifier given
 * a string containing the raw pinerc entry
 */
char *
context_string(char *s)
{
    CONTEXT_S *t = new_context(s, NULL);
    char      *rv = NULL;

    if(t){
	/*
	 * Take what we want from context, then free the rest...
	 */
	rv = t->context;
	t->context = NULL;			/* don't free it! */
	free_context(&t);
    }

    return(rv ? rv : cpystr(""));
}



/*----------------------------------------------------------------------
      Rename the current sent-mail folder to sent-mail for last month

   open up sent-mail and get date of very first message
   if date is last month rename and...
       if files from 3 months ago exist ask if they should be deleted and...
           if files from previous months and yes ask about them, too.   
  ----------------------------------------------------------------------*/
int
expire_sent_mail(void)
{
    int		 cur_month, ok = 1;
    time_t	 now;
    char	 tmp[50], **p;
    struct tm	*tm_now;
    CONTEXT_S	*prune_cntxt;

    dprint((5, "==== expire_mail called ====\n"));

    if(!check_prune_time(&now, &tm_now))
      return 0;

    cur_month = (1900 + tm_now->tm_year) * 12 + tm_now->tm_mon;
    dprint((5, "Current month %d\n", cur_month));

    /*
     * locate the default save context...
     */
    if(!(prune_cntxt = default_save_context(ps_global->context_list)))
      prune_cntxt = ps_global->context_list;

    /*
     * Since fcc's and read-mail can be an IMAP mailbox, be sure to only
     * try expiring a list if it's an ambiguous name associated with some
     * collection...
     *
     * If sentmail set outside a context, then pruning is up to the
     * user...
     */
    if(prune_cntxt){
	if(ps_global->VAR_DEFAULT_FCC && *ps_global->VAR_DEFAULT_FCC
	   && context_isambig(ps_global->VAR_DEFAULT_FCC))
	  ok = prune_folders(prune_cntxt, ps_global->VAR_DEFAULT_FCC,
			     cur_month, " SENT",
			     ps_global->pruning_rule);

	if(ok && ps_global->VAR_READ_MESSAGE_FOLDER 
	   && *ps_global->VAR_READ_MESSAGE_FOLDER
	   && context_isambig(ps_global->VAR_READ_MESSAGE_FOLDER))
	  ok = prune_folders(prune_cntxt, ps_global->VAR_READ_MESSAGE_FOLDER,
			     cur_month, " READ",
			     ps_global->pruning_rule);
    }

    /*
     * Within the default prune context,
     * prune back the folders with the given name
     */
    if(ok && prune_cntxt && (p = ps_global->VAR_PRUNED_FOLDERS))
      for(; ok && *p; p++)
	if(**p && context_isambig(*p))
	  ok = prune_folders(prune_cntxt, *p, cur_month, "",
			     ps_global->pruning_rule);

    /*
     * Mark that we're done for this month...
     */
    if(ok){
	ps_global->last_expire_year = tm_now->tm_year;
	ps_global->last_expire_month = tm_now->tm_mon;
	snprintf(tmp, sizeof(tmp), "%d.%d", ps_global->last_expire_year,
		ps_global->last_expire_month + 1);
	set_variable(V_LAST_TIME_PRUNE_QUESTION, tmp, 1, 1, Main);
    }

    return(1);
}


/*----------------------------------------------------------------------
     Offer to delete old sent-mail folders

  Args: sml -- The list of sent-mail folders
 
  ----*/
int
prune_folders(CONTEXT_S *prune_cntxt, char *folder_base, int cur_month,
	      char *type, unsigned int pr)
{
    char         path2[MAXPATH+1],  prompt[128], tmp[21];
    int          month_to_use, exists;
    struct sm_folder *mail_list, *sm;

    mail_list = get_mail_list(prune_cntxt, folder_base);
    free_folder_list(prune_cntxt);

#ifdef	DEBUG
    for(sm = mail_list; sm != NULL && sm->name != NULL; sm++)
      dprint((5,"Old sent-mail: %5d  %s\n", sm->month_num,
	     sm->name[0] ? sm->name : "?"));
#endif

    for(sm = mail_list; sm != NULL && sm->name != NULL; sm++)
      if(sm->month_num == cur_month - 1)
        break;  /* matched a month */
 
    month_to_use = (sm == NULL || sm->name == NULL) ? cur_month - 1 : 0;

    dprint((5, "Month_to_use : %d\n", month_to_use));

    if(month_to_use == 0 || pr == PRUNE_NO_AND_ASK || pr == PRUNE_NO_AND_NO)
      goto delete_old;

    strncpy(path2, folder_base, sizeof(path2)-1);
    path2[sizeof(path2)-1] = '\0';

    if(F_ON(F_PRUNE_USES_ISO,ps_global)){             /* sent-mail-yyyy-mm */
	snprintf(path2 + strlen(path2), sizeof(path2)-strlen(path2), "-%4.4d-%2.2d", month_to_use/12,
		month_to_use % 12 + 1);
    }
    else{
	strncpy(tmp, month_abbrev((month_to_use % 12)+1), 20);
	tmp[sizeof(tmp)-1] = '\0';
	lcase((unsigned char *) tmp);
#ifdef	DOS
	if(*prune_cntxt->context != '{'){
	  int i;

	  i = strlen(path2);
	  snprintf(path2 + (size_t)((i > 4) ? 4 : i),
	           sizeof(path2)- ((i > 4) ? 4 : i),
		  "%2.2d%2.2d", (month_to_use % 12) + 1,
		  ((month_to_use / 12) - 1900) % 100);
	}
	else
#endif
	snprintf(path2 + strlen(path2), sizeof(path2)-strlen(path2), "-%.20s-%d", tmp, month_to_use/12);
    }

    Writechar(BELL, 0);
    snprintf(prompt, sizeof(prompt), "Move current \"%.50s\" to \"%.50s\"", folder_base, path2);
    if((exists = folder_exists(prune_cntxt, folder_base)) == FEX_ERROR){
        dprint((5, "prune_folders: Error testing existence\n"));
        return(0);
    }
    else if(exists == FEX_NOENT){	/* doesn't exist */
        dprint((5, "prune_folders: nothing to prune <%s %s>\n",
		   prune_cntxt->context ? prune_cntxt->context : "?",
		   folder_base ? folder_base : "?"));
        goto delete_old;
    }
    else if(!(exists & FEX_ISFILE)
	    || pr == PRUNE_NO_AND_ASK || pr == PRUNE_NO_AND_NO
	    || ((pr == PRUNE_ASK_AND_ASK || pr == PRUNE_ASK_AND_NO) &&
	        want_to(prompt, 'n', 0, h_wt_expire, WT_FLUSH_IN) == 'n')){
	dprint((5, "User declines renaming %s\n",
	       ps_global->VAR_DEFAULT_FCC ? ps_global->VAR_DEFAULT_FCC : "?"));
	goto delete_old;
    }

    prune_move_folder(folder_base, path2, prune_cntxt);

  delete_old:
    if(pr == PRUNE_ASK_AND_ASK || pr == PRUNE_YES_AND_ASK
       || pr == PRUNE_NO_AND_ASK)
      delete_old_mail(mail_list, prune_cntxt, type);

    if((sm = mail_list) != NULL){
	while(sm->name){
	    fs_give((void **)&(sm->name));
	    sm++;
	}

        fs_give((void **)&mail_list);
    }

    return(1);
}


/*----------------------------------------------------------------------
     Offer to delete old sent-mail folders

  Args: sml       -- The list of sent-mail folders
        fcc_cntxt -- context to delete list of folders in
        type      -- label indicating type of folders being deleted
 
  ----*/
void
delete_old_mail(struct sm_folder *sml, CONTEXT_S *fcc_cntxt, char *type)
{
    char  prompt[150];
    struct sm_folder *sm;

    for(sm = sml; sm != NULL && sm->name != NULL; sm++){
	if(sm->name[0] == '\0')		/* can't happen */
	  continue;

        snprintf(prompt, sizeof(prompt),
	       "To save disk space, delete old%.10s mail folder \"%.30s\" ",
	       type, sm->name);
        if(want_to(prompt, 'n', 0, h_wt_delete_old, WT_FLUSH_IN) == 'y'){

	    if(!context_delete(fcc_cntxt, NULL, sm->name)){
		q_status_message1(SM_ORDER,
				  3, 3, "Error deleting \"%s\".", sm->name);
		dprint((1, "Error context_deleting %s in %s\n", sm->name,
			   (fcc_cntxt && fcc_cntxt->context)
				     ? fcc_cntxt->context : "<null>"));
            }
	    else{
		int index;

		if((index = folder_index(sm->name, fcc_cntxt, FI_FOLDER)) >= 0)
		  folder_delete(index, FOLDERS(fcc_cntxt));
	    }
	}else{
		/* break;*/ /* skip out of the whole thing when he says no */
		/* Decided to keep asking anyway */
        }
    }
}



