* NTLM authentication support with the ntlm library, in Unix systems.
[alpine.git] / pith / init.c
blob46a565fac2a3be828af1f2816265236cc7a2af79
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: init.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2017 Eduardo Chappa
8 * Copyright 2006-2007 University of Washington
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
21 Routines for pine start up and initialization
22 ====*/
25 #include "../pith/headers.h"
26 #include "../pith/init.h"
27 #include "../pith/conf.h"
28 #include "../pith/status.h"
29 #include "../pith/folder.h"
33 * Internal prototypes
35 int compare_sm_files(const qsort_t *, const qsort_t *);
39 /*----------------------------------------------------------------------
40 Sets login, full_username and home_dir
42 Args: ps -- The Pine structure to put the user name, etc in
44 Result: sets the fullname, login and home_dir field of the pine structure
45 returns 0 on success, -1 if not.
46 ----*/
48 int
49 init_username(struct pine *ps)
51 char *expanded;
52 int rv;
54 rv = 0;
55 expanded = NULL;
56 #if defined(DOS) || defined(OS2)
57 if(ps->COM_USER_ID)
58 expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
59 ps->COM_USER_ID, 0);
61 if(!expanded && ps->vars[V_USER_ID].post_user_val.p)
62 expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
63 ps->vars[V_USER_ID].post_user_val.p, 0);
65 if(!expanded && ps->vars[V_USER_ID].main_user_val.p)
66 expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
67 ps->vars[V_USER_ID].main_user_val.p, 0);
69 if(!expanded)
70 ps->blank_user_id = 1;
72 ps->VAR_USER_ID = cpystr(expanded ? expanded : "");
73 #else
74 ps->VAR_USER_ID = cpystr(ps->ui.login);
75 if(!ps->VAR_USER_ID[0]){
76 fprintf(stderr, "Who are you? (Unable to look up login name)\n");
77 rv = -1;
79 #endif
81 expanded = NULL;
82 if(ps->vars[V_PERSONAL_NAME].is_fixed){
83 if(ps->FIX_PERSONAL_NAME){
84 expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
85 ps->FIX_PERSONAL_NAME, 0);
87 if(ps->vars[V_PERSONAL_NAME].main_user_val.p ||
88 ps->vars[V_PERSONAL_NAME].post_user_val.p){
89 ps_global->give_fixed_warning = 1;
90 ps_global->fix_fixed_warning = 1;
92 else if(ps->COM_PERSONAL_NAME)
93 ps_global->give_fixed_warning = 1;
95 else{
96 if(ps->COM_PERSONAL_NAME)
97 expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
98 ps->COM_PERSONAL_NAME, 0);
100 if(!expanded && ps->vars[V_PERSONAL_NAME].post_user_val.p)
101 expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
102 ps->vars[V_PERSONAL_NAME].post_user_val.p, 0);
104 if(!expanded && ps->vars[V_PERSONAL_NAME].main_user_val.p)
105 expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
106 ps->vars[V_PERSONAL_NAME].main_user_val.p, 0);
109 if(!expanded){
110 expanded = ps->ui.fullname;
111 #if defined(DOS) || defined(OS2)
112 ps->blank_personal_name = 1;
113 #endif
116 ps->VAR_PERSONAL_NAME = cpystr(expanded ? expanded : "");
118 dprint((1, "Userid: %s\nFullname: \"%s\"\n",
119 ps->VAR_USER_ID, ps->VAR_PERSONAL_NAME));
120 return(rv);
124 /*----------------------------------------------------------------------
125 Sets home_dir
127 Args: ps -- The Pine structure to put the user name, etc in
129 Result: sets the home_dir field of the pine structure
130 returns 0 on success, -1 if not.
131 ----*/
134 init_userdir(struct pine *ps)
136 char fld_dir[MAXPATH+1];
138 if(strlen(ps->home_dir) + strlen(ps->VAR_MAIL_DIRECTORY)+2 > MAXPATH){
139 printf(_("Folders directory name is longer than %d\n"), MAXPATH);
140 printf(_("Directory name: \"%s/%s\"\n"),ps->home_dir,
141 ps->VAR_MAIL_DIRECTORY);
142 return(-1);
144 #if defined(DOS) || defined(OS2)
145 if(ps->VAR_MAIL_DIRECTORY[1] == ':'){
146 strncpy(fld_dir, ps->VAR_MAIL_DIRECTORY, sizeof(fld_dir)-1);
147 fld_dir[sizeof(fld_dir)-1] = '\0';
149 else
150 #endif
151 build_path(fld_dir, ps->home_dir, ps->VAR_MAIL_DIRECTORY, sizeof(fld_dir));
152 ps->folders_dir = cpystr(fld_dir);
154 return(0);
158 /*----------------------------------------------------------------------
159 Fetch the hostname of the current system and put it in pine struct
161 Args: ps -- The pine structure to put the hostname, etc in
163 Result: hostname, localdomain, userdomain and maildomain are set
166 ** Pine uses the following set of names:
167 hostname - The fully-qualified hostname. Obtained with
168 gethostbyname() which reads /etc/hosts or does a DNS
169 lookup. This may be blank.
170 localdomain - The domain name without the host. Obtained from the
171 above hostname if it has a "." in it. Removes first
172 segment. If hostname has no "." in it then the hostname
173 is used. This may be blank.
174 userdomain - Explicitly configured domainname. This is read out of the
175 global pine.conf or user's .pinerc. The user's entry in the
176 .pinerc overrides.
178 ** Pine has the following uses for such names:
180 1. On outgoing messages in the From: line
181 Uses userdomain if there is one. If not uses, uses
182 hostname unless Pine has been configured to use localdomain.
184 2. When expanding/fully-qualifying unqualified addresses during
185 composition
186 (same as 1)
188 3. When expanding/fully-qualifying unqualified addresses during
189 composition when a local entry in the password file exists for
190 name.
191 If no userdomain is given, then this lookup is always done
192 and the hostname is used unless Pine's been configured to
193 use the localdomain. If userdomain is defined, it is used,
194 but no local lookup is done. We can't assume users on the
195 local host are valid in the given domain (and, for simplicity,
196 have chosen to ignore the cases userdomain matches localdomain
197 or localhost). Setting user-lookup-even-if-domain-mismatch
198 feature will tell pine to override this behavior and perform
199 the local lookup anyway. The problem of a global "even-if"
200 set and a .pinerc-defined user-domain of something odd causing
201 the local lookup, but this will only effect the personal name,
202 and is not judged to be a significant problem.
204 4. In determining if an address is that of the current pine user for
205 formatting index and filtering addresses when replying
206 If a userdomain is specified the address must match the
207 userdomain exactly. If a userdomain is not specified or the
208 userdomain is the same as the hostname or domainname, then
209 an address will be considered the users if it matches either
210 the domainname or the hostname. Of course, the userid must
211 match too.
213 5. In Message ID's
214 The fully-qualified hostname is always users here.
217 ** Setting the domain names
218 To set the domain name for all Pine users on the system to be
219 different from what Pine figures out from DNS, set the domain name in
220 the "user-domain" variable in pine.conf. To set the domain name for an
221 individual user, set the "user-domain" variable in his .pinerc.
222 The .pinerc setting overrides any other setting.
223 ----*/
225 init_hostname(struct pine *ps)
227 char hostname[MAX_ADDRESS+1], domainname[MAX_ADDRESS+1];
229 getdomainnames(hostname, sizeof(hostname)-1,
230 domainname, sizeof(domainname)-1);
232 if(ps->hostname)
233 fs_give((void **)&ps->hostname);
235 ps->hostname = cpystr(hostname);
237 if(ps->localdomain)
238 fs_give((void **)&ps->localdomain);
240 ps->localdomain = cpystr(domainname);
241 ps->userdomain = NULL;
243 if(ps->VAR_USER_DOMAIN && ps->VAR_USER_DOMAIN[0]){
244 ps->maildomain = ps->userdomain = ps->VAR_USER_DOMAIN;
245 }else{
246 #if defined(DOS) || defined(OS2)
247 if(ps->VAR_USER_DOMAIN)
248 ps->blank_user_domain = 1; /* user domain set to null string! */
250 ps->maildomain = ps->localdomain[0] ? ps->localdomain : ps->hostname;
251 #else
252 ps->maildomain = strucmp(ps->VAR_USE_ONLY_DOMAIN_NAME, "yes")
253 ? ps->hostname : ps->localdomain;
254 #endif
258 * Tell c-client what domain to use when completing unqualified
259 * addresses it finds in local mailboxes. Remember, it won't
260 * affect what's to the right of '@' for unqualified addresses in
261 * remote folders...
263 mail_parameters(NULL, SET_LOCALHOST, (void *) ps->maildomain);
264 if(F_OFF(F_QUELL_MAILDOMAIN_WARNING, ps) && !strchr(ps->maildomain, '.')){
265 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Incomplete maildomain \"%s\"."),
266 ps->maildomain);
267 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
268 strncpy(tmp_20k_buf,
269 _("Return address in mail you send may be incorrect."), SIZEOF_20KBUF);
270 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
271 init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
274 dprint((1,"User domain name being used \"%s\"\n",
275 ps->userdomain == NULL ? "" : ps->userdomain));
276 dprint((1,"Local Domain name being used \"%s\"\n",
277 ps->localdomain ? ps->localdomain : "?"));
278 dprint((1,"Host name being used \"%s\"\n",
279 ps->hostname ? ps->hostname : "?"));
280 dprint((1,
281 "Mail Domain name being used (by c-client too) \"%s\"\n",
282 ps->maildomain ? ps->maildomain : "?"));
284 if(!ps->maildomain || !ps->maildomain[0]){
285 #if defined(DOS) || defined(OS2)
286 if(ps->blank_user_domain)
287 return(0); /* prompt for this in send.c:dos_valid_from */
288 #endif
289 fprintf(stderr, _("No host name or domain name set\n"));
290 return(-1);
292 else
293 return(0);
297 /*----------------------------------------------------------------------
298 Make sure the default save folders exist in the default
299 save context.
300 ----*/
301 void
302 init_save_defaults(void)
304 CONTEXT_S *save_cntxt;
306 if(!ps_global->VAR_DEFAULT_FCC ||
307 !*ps_global->VAR_DEFAULT_FCC ||
308 !ps_global->VAR_DEFAULT_SAVE_FOLDER ||
309 !*ps_global->VAR_DEFAULT_SAVE_FOLDER)
310 return;
312 if(!(save_cntxt = default_save_context(ps_global->context_list)))
313 save_cntxt = ps_global->context_list;
315 if(!(folder_exists(save_cntxt, ps_global->VAR_DEFAULT_FCC) & FEX_ISFILE))
316 context_create(save_cntxt, NULL, ps_global->VAR_DEFAULT_FCC);
318 if(!(folder_exists(save_cntxt, ps_global->VAR_DEFAULT_SAVE_FOLDER) &
319 FEX_ISFILE))
320 context_create(save_cntxt, NULL, ps_global->VAR_DEFAULT_SAVE_FOLDER);
322 free_folder_list(save_cntxt);
326 /*----------------------------------------------------------------------
327 Put sent-mail files in date order
329 Args: a, b -- The names of two files. Expects names to be sent-mail-mmm-yy
330 Other names will sort in order and come before those
331 in above format.
332 ----*/
333 int
334 compare_sm_files(const qsort_t *aa, const qsort_t *bb)
336 struct sm_folder *a = (struct sm_folder *)aa,
337 *b = (struct sm_folder *)bb;
339 if(a->month_num == -1 && b->month_num == -1 && a->name && b->name)
340 return(strucmp(a->name, b->name));
341 if(a->month_num == -1) return(-1);
342 if(b->month_num == -1) return(1);
344 return(a->month_num - b->month_num);
349 /*----------------------------------------------------------------------
350 Create an ordered list of sent-mail folders and their month numbers
352 Args: dir -- The directory to find the list of files in
354 Result: Pointer to list of files is returned.
356 This list includes all files that start with "sent-mail", but not "sent-mail"
357 itself.
358 ----*/
359 struct sm_folder *
360 get_mail_list(CONTEXT_S *list_cntxt, char *folder_base)
362 register struct sm_folder *sm = NULL;
363 struct sm_folder *sml = NULL;
364 char *filename;
365 int i, folder_base_len;
366 int max_files;
367 char searchname[MAXPATH+1];
369 if((folder_base_len = strlen(folder_base)) == 0 || !list_cntxt){
370 sml = (struct sm_folder *) fs_get(sizeof(struct sm_folder));
371 memset((void *)sml, 0, sizeof(struct sm_folder));
372 return(sml);
375 #ifdef DOS
376 if(*list_cntxt->context != '{'){ /* NOT an IMAP collection! */
377 snprintf(searchname, sizeof(searchname), "%4.4s*", folder_base);
378 folder_base_len = strlen(searchname) - 1;
380 else
381 #endif /* MAXPATH + 1 = sizeof(searchmane) */
382 snprintf(searchname, sizeof(searchname), "%.*s*", MAXPATH+1-2, folder_base);
384 build_folder_list(NULL, list_cntxt, searchname, NULL, BFL_FLDRONLY);
386 max_files = MIN(MAX(0, folder_total(FOLDERS(list_cntxt))), 5000);
387 sml = sm = (struct sm_folder *) fs_get(sizeof(struct sm_folder)*(max_files+1));
388 memset((void *)sml, 0, sizeof(struct sm_folder) * (max_files+1));
390 for(i = 0; i < folder_total(FOLDERS(list_cntxt)); i++){
391 filename = folder_entry(i, FOLDERS(list_cntxt))->name;
392 #ifdef DOS
393 if(struncmp(filename, folder_base, folder_base_len) == 0
394 && strucmp(filename, folder_base)){
396 if(*list_cntxt->context != '{'){
397 int j;
398 for(j = 0; j < 4; j++)
399 if(!isdigit((unsigned char)filename[folder_base_len + j]))
400 break;
402 if(j < 4) /* not proper date format! */
403 continue; /* keep trying */
405 #else
406 #ifdef OS2
407 if(strnicmp(filename, folder_base, folder_base_len) == 0
408 && stricmp(filename, folder_base)){
409 #else
410 if(strncmp(filename, folder_base, folder_base_len) == 0
411 && strcmp(filename, folder_base)){
412 #endif
413 #endif
414 sm->name = cpystr(filename);
415 #ifdef DOS
416 if(*list_cntxt->context != '{'){ /* NOT an IMAP collection! */
417 sm->month_num = (sm->name[folder_base_len] - '0') * 10;
418 sm->month_num += sm->name[folder_base_len + 1] - '0';
420 else
421 #endif
422 sm->month_num = month_num(sm->name + (size_t)folder_base_len + 1);
423 sm++;
424 if(sm >= &sml[max_files])
425 break; /* Too many files, ignore the rest ; shouldn't occur */
429 /* anything to sort?? */
430 if(sml->name && *(sml->name) && (sml+1)->name && *((sml+1)->name)){
431 qsort(sml,
432 sm - sml,
433 sizeof(struct sm_folder),
434 compare_sm_files);
437 return(sml);
443 check_prune_time(time_t *now, struct tm **tm_now)
445 char tmp[50];
447 *now = time((time_t *) 0);
448 *tm_now = localtime(now);
451 * If the last time we did this is blank (as if pine's run for
452 * first time), don't go thru list asking, but just note it for
453 * the next time...
455 if(ps_global->VAR_LAST_TIME_PRUNE_QUESTION == NULL){
456 ps_global->last_expire_year = (*tm_now)->tm_year;
457 ps_global->last_expire_month = (*tm_now)->tm_mon;
458 snprintf(tmp, sizeof(tmp), "%d.%d", ps_global->last_expire_year,
459 ps_global->last_expire_month + 1);
460 set_variable(V_LAST_TIME_PRUNE_QUESTION, tmp, 1, 1, Main);
461 return(0);
464 if(ps_global->last_expire_year != -1 &&
465 ((*tm_now)->tm_year < ps_global->last_expire_year ||
466 ((*tm_now)->tm_year == ps_global->last_expire_year &&
467 (*tm_now)->tm_mon <= ps_global->last_expire_month)))
468 return(0);
470 return(1);
475 first_run_of_month(void)
477 time_t now;
478 struct tm *tm_now;
480 now = time((time_t *) 0);
481 tm_now = localtime(&now);
483 if(ps_global->last_expire_year == -1 ||
484 (tm_now->tm_year < ps_global->last_expire_year ||
485 (tm_now->tm_year == ps_global->last_expire_year &&
486 tm_now->tm_mon <= ps_global->last_expire_month)))
487 return(0);
489 return(1);
494 first_run_of_year(void)
496 time_t now;
497 struct tm *tm_now;
499 now = time((time_t *) 0);
500 tm_now = localtime(&now);
502 if(ps_global->last_expire_year == -1 ||
503 (tm_now->tm_year <= ps_global->last_expire_year))
504 return(0);
506 return(1);
511 * prune_move_folder - rename folder in context and delete old copy
512 * Returns -1 if unsuccessful.
515 prune_move_folder(char *oldpath, char *newpath, CONTEXT_S *prune_cntxt)
517 char spath[MAXPATH+1];
519 strncpy(spath, oldpath, sizeof(spath)-1);
520 spath[sizeof(spath)-1] = '\0';
522 /*--- User says OK to rename ---*/
523 dprint((5, "rename \"%s\" to \"%s\"\n",
524 spath ? spath : "?", newpath ? newpath : "?"));
525 q_status_message1(SM_ORDER, 1, 3,
526 /* TRANSLATORS: arg is a filename */
527 _("Renaming \"%s\" at start of month"),
528 pretty_fn(spath ? spath : "?"));
530 if(!context_rename(prune_cntxt, NULL, spath, newpath)){
531 q_status_message2(SM_ORDER | SM_DING, 3, 4,
532 /* TRANSLATORS: 1st arg is filename, 2nd is error message */
533 _("Error renaming \"%s\": %s"),
534 pretty_fn(spath ? spath : "?"),
535 error_description(errno));
536 dprint((1, "Error renaming %s to %s: %s\n",
537 spath ? spath : "?", newpath ? newpath : "?",
538 error_description(errno)));
539 display_message('x');
540 return -1;
543 context_create(prune_cntxt, NULL, spath);
545 return 0;