* Deactivate some color code from Pico (as standalone editor) until
[alpine.git] / alpine / init.c
blob631685cb14e4d1e5ae6e8d5963a4e6e3b623c54a
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: init.c 101 2006-08-10 22:53:04Z mikes@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2017 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 /*======================================================================
20 init.c
22 Session initiation support routines
24 ====*/
27 #include "headers.h"
29 #include "../pith/init.h"
30 #include "../pith/conf.h"
31 #include "../pith/status.h"
32 #include "../pith/folder.h"
33 #include "../pith/context.h"
35 #include "init.h"
38 /* these are used to report folder directory creation problems */
39 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.";
41 CONF_TXT_T init_md_file[] = "Alpine requires a directory called \"%s\" and usualy 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.";
43 CONF_TXT_T init_md_create[] = "Creating subdirectory \"%s\" where Alpine will store its mail folders.";
47 * Internal prototypes
49 void display_init_err(char *, int);
50 char *context_string(char *);
51 int prune_folders(CONTEXT_S *, char *, int, char *, unsigned);
52 int prune_move_folder(char *, char *, CONTEXT_S *);
53 void delete_old_mail(struct sm_folder *, CONTEXT_S *, char *);
57 /*----------------------------------------------------------------------
58 Make sure the alpine folders directory exists, with proper folders
60 Args: ps -- alpine structure to get mail directory and contexts from
62 Result: returns 0 if it exists or it is created and all is well
63 1 if it is missing and can't be created.
64 ----*/
65 int
66 init_mail_dir(struct pine *ps)
69 /* MAIL_LIST: can we use imap4 CREATE? */
71 * We don't really care if mail_dir exists if it isn't
72 * part of the first folder collection specified. If this
73 * is the case, it must have been created external to us, so
74 * just move one...
76 if(ps->VAR_FOLDER_SPEC && ps->VAR_FOLDER_SPEC[0]){
77 char *p = context_string(ps->VAR_FOLDER_SPEC[0]);
78 int rv = strncmp(p, ps->VAR_MAIL_DIRECTORY,
79 strlen(ps->VAR_MAIL_DIRECTORY));
80 fs_give((void **)&p);
81 if(rv)
82 return(0);
85 switch(is_writable_dir(ps->folders_dir)){
86 case 0:
87 /* --- all is well --- */
88 return(0);
90 case 1:
91 snprintf(tmp_20k_buf, SIZEOF_20KBUF, init_md_exists, ps->folders_dir);
92 display_init_err(tmp_20k_buf, 1);
93 return(-1);
95 case 2:
96 snprintf(tmp_20k_buf, SIZEOF_20KBUF, init_md_file, ps->folders_dir);
97 display_init_err(tmp_20k_buf, 1);
98 return(-1);
100 case 3:
101 snprintf(tmp_20k_buf, SIZEOF_20KBUF, init_md_create, ps->folders_dir);
102 display_init_err(tmp_20k_buf, 0);
103 #ifndef _WINDOWS
104 sleep(4);
105 #endif
106 if(create_mail_dir(ps->folders_dir) < 0){
107 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Error creating subdirectory \"%s\" : %s",
108 ps->folders_dir, error_description(errno));
109 display_init_err(tmp_20k_buf, 1);
110 return(-1);
114 return(0);
118 /*----------------------------------------------------------------------
119 Make sure the default save folders exist in the default
120 save context.
121 ----*/
122 void
123 display_init_err(char *s, int err)
125 #ifdef _WINDOWS
126 mswin_messagebox(s, err);
127 #else
128 int n = 0;
130 if(err)
131 fputc(BELL, stdout);
133 for(; *s; s++)
134 if(++n > 60 && isspace((unsigned char)*s)){
135 n = 0;
136 fputc('\n', stdout);
137 while(*(s+1) && isspace((unsigned char)*(s+1)))
138 s++;
140 else
141 fputc(*s, stdout);
143 fputc('\n', stdout);
144 #endif
149 * Return malloc'd string containing only the context specifier given
150 * a string containing the raw pinerc entry
152 char *
153 context_string(char *s)
155 CONTEXT_S *t = new_context(s, NULL);
156 char *rv = NULL;
158 if(t){
160 * Take what we want from context, then free the rest...
162 rv = t->context;
163 t->context = NULL; /* don't free it! */
164 free_context(&t);
167 return(rv ? rv : cpystr(""));
172 /*----------------------------------------------------------------------
173 Rename the current sent-mail folder to sent-mail for last month
175 open up sent-mail and get date of very first message
176 if date is last month rename and...
177 if files from 3 months ago exist ask if they should be deleted and...
178 if files from previous months and yes ask about them, too.
179 ----------------------------------------------------------------------*/
181 expire_sent_mail(void)
183 int cur_month, ok = 1;
184 time_t now;
185 char tmp[50], **p;
186 struct tm *tm_now;
187 CONTEXT_S *prune_cntxt;
189 dprint((5, "==== expire_mail called ====\n"));
191 if(!check_prune_time(&now, &tm_now))
192 return 0;
194 cur_month = (1900 + tm_now->tm_year) * 12 + tm_now->tm_mon;
195 dprint((5, "Current month %d\n", cur_month));
198 * locate the default save context...
200 if(!(prune_cntxt = default_save_context(ps_global->context_list)))
201 prune_cntxt = ps_global->context_list;
204 * Since fcc's and read-mail can be an IMAP mailbox, be sure to only
205 * try expiring a list if it's an ambiguous name associated with some
206 * collection...
208 * If sentmail set outside a context, then pruning is up to the
209 * user...
211 if(prune_cntxt){
212 if(ps_global->VAR_DEFAULT_FCC && *ps_global->VAR_DEFAULT_FCC
213 && context_isambig(ps_global->VAR_DEFAULT_FCC))
214 ok = prune_folders(prune_cntxt, ps_global->VAR_DEFAULT_FCC,
215 cur_month, " SENT",
216 ps_global->pruning_rule);
218 if(ok && ps_global->VAR_READ_MESSAGE_FOLDER
219 && *ps_global->VAR_READ_MESSAGE_FOLDER
220 && context_isambig(ps_global->VAR_READ_MESSAGE_FOLDER))
221 ok = prune_folders(prune_cntxt, ps_global->VAR_READ_MESSAGE_FOLDER,
222 cur_month, " READ",
223 ps_global->pruning_rule);
227 * Within the default prune context,
228 * prune back the folders with the given name
230 if(ok && prune_cntxt && (p = ps_global->VAR_PRUNED_FOLDERS))
231 for(; ok && *p; p++)
232 if(**p && context_isambig(*p))
233 ok = prune_folders(prune_cntxt, *p, cur_month, "",
234 ps_global->pruning_rule);
237 * Mark that we're done for this month...
239 if(ok){
240 ps_global->last_expire_year = tm_now->tm_year;
241 ps_global->last_expire_month = tm_now->tm_mon;
242 snprintf(tmp, sizeof(tmp), "%d.%d", ps_global->last_expire_year,
243 ps_global->last_expire_month + 1);
244 set_variable(V_LAST_TIME_PRUNE_QUESTION, tmp, 1, 1, Main);
247 return(1);
251 /*----------------------------------------------------------------------
252 Offer to delete old sent-mail folders
254 Args: sml -- The list of sent-mail folders
256 ----*/
258 prune_folders(CONTEXT_S *prune_cntxt, char *folder_base, int cur_month,
259 char *type, unsigned int pr)
261 char path2[MAXPATH+1], prompt[128], tmp[21];
262 int month_to_use, exists;
263 struct sm_folder *mail_list, *sm;
265 mail_list = get_mail_list(prune_cntxt, folder_base);
266 free_folder_list(prune_cntxt);
268 #ifdef DEBUG
269 for(sm = mail_list; sm != NULL && sm->name != NULL; sm++)
270 dprint((5,"Old sent-mail: %5d %s\n", sm->month_num,
271 sm->name[0] ? sm->name : "?"));
272 #endif
274 for(sm = mail_list; sm != NULL && sm->name != NULL; sm++)
275 if(sm->month_num == cur_month - 1)
276 break; /* matched a month */
278 month_to_use = (sm == NULL || sm->name == NULL) ? cur_month - 1 : 0;
280 dprint((5, "Month_to_use : %d\n", month_to_use));
282 if(month_to_use == 0 || pr == PRUNE_NO_AND_ASK || pr == PRUNE_NO_AND_NO)
283 goto delete_old;
285 strncpy(path2, folder_base, sizeof(path2)-1);
286 path2[sizeof(path2)-1] = '\0';
288 if(F_ON(F_PRUNE_USES_ISO,ps_global)){ /* sent-mail-yyyy-mm */
289 snprintf(path2 + strlen(path2), sizeof(path2)-strlen(path2), "-%4.4d-%2.2d", month_to_use/12,
290 month_to_use % 12 + 1);
292 else{
293 strncpy(tmp, month_abbrev((month_to_use % 12)+1), 20);
294 tmp[sizeof(tmp)-1] = '\0';
295 lcase((unsigned char *) tmp);
296 #ifdef DOS
297 if(*prune_cntxt->context != '{'){
298 int i;
300 i = strlen(path2);
301 snprintf(path2 + (size_t)((i > 4) ? 4 : i),
302 sizeof(path2)- ((i > 4) ? 4 : i),
303 "%2.2d%2.2d", (month_to_use % 12) + 1,
304 ((month_to_use / 12) - 1900) % 100);
306 else
307 #endif
308 snprintf(path2 + strlen(path2), sizeof(path2)-strlen(path2), "-%.20s-%d", tmp, month_to_use/12);
311 Writechar(BELL, 0);
312 snprintf(prompt, sizeof(prompt), "Move current \"%.50s\" to \"%.50s\"", folder_base, path2);
313 if((exists = folder_exists(prune_cntxt, folder_base)) == FEX_ERROR){
314 dprint((5, "prune_folders: Error testing existence\n"));
315 return(0);
317 else if(exists == FEX_NOENT){ /* doesn't exist */
318 dprint((5, "prune_folders: nothing to prune <%s %s>\n",
319 prune_cntxt->context ? prune_cntxt->context : "?",
320 folder_base ? folder_base : "?"));
321 goto delete_old;
323 else if(!(exists & FEX_ISFILE)
324 || pr == PRUNE_NO_AND_ASK || pr == PRUNE_NO_AND_NO
325 || ((pr == PRUNE_ASK_AND_ASK || pr == PRUNE_ASK_AND_NO) &&
326 want_to(prompt, 'n', 0, h_wt_expire, WT_FLUSH_IN) == 'n')){
327 dprint((5, "User declines renaming %s\n",
328 ps_global->VAR_DEFAULT_FCC ? ps_global->VAR_DEFAULT_FCC : "?"));
329 goto delete_old;
332 prune_move_folder(folder_base, path2, prune_cntxt);
334 delete_old:
335 if(pr == PRUNE_ASK_AND_ASK || pr == PRUNE_YES_AND_ASK
336 || pr == PRUNE_NO_AND_ASK)
337 delete_old_mail(mail_list, prune_cntxt, type);
339 if((sm = mail_list) != NULL){
340 while(sm->name){
341 fs_give((void **)&(sm->name));
342 sm++;
345 fs_give((void **)&mail_list);
348 return(1);
352 /*----------------------------------------------------------------------
353 Offer to delete old sent-mail folders
355 Args: sml -- The list of sent-mail folders
356 fcc_cntxt -- context to delete list of folders in
357 type -- label indicating type of folders being deleted
359 ----*/
360 void
361 delete_old_mail(struct sm_folder *sml, CONTEXT_S *fcc_cntxt, char *type)
363 char prompt[150];
364 struct sm_folder *sm;
366 for(sm = sml; sm != NULL && sm->name != NULL; sm++){
367 if(sm->name[0] == '\0') /* can't happen */
368 continue;
370 snprintf(prompt, sizeof(prompt),
371 "To save disk space, delete old%.10s mail folder \"%.30s\" ",
372 type, sm->name);
373 if(want_to(prompt, 'n', 0, h_wt_delete_old, WT_FLUSH_IN) == 'y'){
375 if(!context_delete(fcc_cntxt, NULL, sm->name)){
376 q_status_message1(SM_ORDER,
377 3, 3, "Error deleting \"%s\".", sm->name);
378 dprint((1, "Error context_deleting %s in %s\n", sm->name,
379 (fcc_cntxt && fcc_cntxt->context)
380 ? fcc_cntxt->context : "<null>"));
382 else{
383 int index;
385 if((index = folder_index(sm->name, fcc_cntxt, FI_FOLDER)) >= 0)
386 folder_delete(index, FOLDERS(fcc_cntxt));
388 }else{
389 /* break;*/ /* skip out of the whole thing when he says no */
390 /* Decided to keep asking anyway */