1
#if !defined(lint) && !defined(DOS)
2
static char rcsid[] = "$Id: init.c 155 2006-09-29 23:28:46Z hubert@u.washington.edu $";
6
* ========================================================================
7
* Copyright 2006 University of Washington
9
* Licensed under the Apache License, Version 2.0 (the "License");
10
* you may not use this file except in compliance with the License.
11
* You may obtain a copy of the License at
13
* http://www.apache.org/licenses/LICENSE-2.0
15
* ========================================================================
18
/*======================================================================
20
Routines for pine start up and initialization
24
#include "../pith/headers.h"
25
#include "../pith/init.h"
26
#include "../pith/conf.h"
27
#include "../pith/status.h"
28
#include "../pith/folder.h"
34
int compare_sm_files(const qsort_t *, const qsort_t *);
38
/*----------------------------------------------------------------------
39
Sets login, full_username and home_dir
41
Args: ps -- The Pine structure to put the user name, etc in
43
Result: sets the fullname, login and home_dir field of the pine structure
44
returns 0 on success, -1 if not.
47
init_username(struct pine *ps)
54
#if defined(DOS) || defined(OS2)
56
expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
59
if(!expanded && ps->vars[V_USER_ID].post_user_val.p)
60
expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
61
ps->vars[V_USER_ID].post_user_val.p, 0);
63
if(!expanded && ps->vars[V_USER_ID].main_user_val.p)
64
expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
65
ps->vars[V_USER_ID].main_user_val.p, 0);
68
ps->blank_user_id = 1;
70
ps->VAR_USER_ID = cpystr(expanded ? expanded : "");
72
ps->VAR_USER_ID = cpystr(ps->ui.login);
73
if(!ps->VAR_USER_ID[0]){
74
fprintf(stderr, "Who are you? (Unable to look up login name)\n");
80
if(ps->vars[V_PERSONAL_NAME].is_fixed){
81
if(ps->FIX_PERSONAL_NAME){
82
expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
83
ps->FIX_PERSONAL_NAME, 0);
85
if(ps->vars[V_PERSONAL_NAME].main_user_val.p ||
86
ps->vars[V_PERSONAL_NAME].post_user_val.p){
87
ps_global->give_fixed_warning = 1;
88
ps_global->fix_fixed_warning = 1;
90
else if(ps->COM_PERSONAL_NAME)
91
ps_global->give_fixed_warning = 1;
94
if(ps->COM_PERSONAL_NAME)
95
expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
96
ps->COM_PERSONAL_NAME, 0);
98
if(!expanded && ps->vars[V_PERSONAL_NAME].post_user_val.p)
99
expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
100
ps->vars[V_PERSONAL_NAME].post_user_val.p, 0);
102
if(!expanded && ps->vars[V_PERSONAL_NAME].main_user_val.p)
103
expanded = expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
104
ps->vars[V_PERSONAL_NAME].main_user_val.p, 0);
108
expanded = ps->ui.fullname;
109
#if defined(DOS) || defined(OS2)
110
ps->blank_personal_name = 1;
114
ps->VAR_PERSONAL_NAME = cpystr(expanded ? expanded : "");
116
dprint((1, "Userid: %s\nFullname: \"%s\"\n",
117
ps->VAR_USER_ID, ps->VAR_PERSONAL_NAME));
122
/*----------------------------------------------------------------------
125
Args: ps -- The Pine structure to put the user name, etc in
127
Result: sets the home_dir field of the pine structure
128
returns 0 on success, -1 if not.
131
init_userdir(struct pine *ps)
133
char fld_dir[MAXPATH+1];
135
if(strlen(ps->home_dir) + strlen(ps->VAR_MAIL_DIRECTORY)+2 > MAXPATH){
136
printf(_("Folders directory name is longer than %d\n"), MAXPATH);
137
printf(_("Directory name: \"%s/%s\"\n"),ps->home_dir,
138
ps->VAR_MAIL_DIRECTORY);
141
#if defined(DOS) || defined(OS2)
142
if(ps->VAR_MAIL_DIRECTORY[1] == ':'){
143
strncpy(fld_dir, ps->VAR_MAIL_DIRECTORY, sizeof(fld_dir)-1);
144
fld_dir[sizeof(fld_dir)-1] = '\0';
148
build_path(fld_dir, ps->home_dir, ps->VAR_MAIL_DIRECTORY, sizeof(fld_dir));
149
ps->folders_dir = cpystr(fld_dir);
155
/*----------------------------------------------------------------------
156
Fetch the hostname of the current system and put it in pine struct
158
Args: ps -- The pine structure to put the hostname, etc in
160
Result: hostname, localdomain, userdomain and maildomain are set
163
** Pine uses the following set of names:
164
hostname - The fully-qualified hostname. Obtained with
165
gethostbyname() which reads /etc/hosts or does a DNS
166
lookup. This may be blank.
167
localdomain - The domain name without the host. Obtained from the
168
above hostname if it has a "." in it. Removes first
169
segment. If hostname has no "." in it then the hostname
170
is used. This may be blank.
171
userdomain - Explicitly configured domainname. This is read out of the
172
global pine.conf or user's .pinerc. The user's entry in the
175
** Pine has the following uses for such names:
177
1. On outgoing messages in the From: line
178
Uses userdomain if there is one. If not uses, uses
179
hostname unless Pine has been configured to use localdomain.
181
2. When expanding/fully-qualifying unqualified addresses during
185
3. When expanding/fully-qualifying unqualified addresses during
186
composition when a local entry in the password file exists for
188
If no userdomain is given, then this lookup is always done
189
and the hostname is used unless Pine's been configured to
190
use the localdomain. If userdomain is defined, it is used,
191
but no local lookup is done. We can't assume users on the
192
local host are valid in the given domain (and, for simplicity,
193
have chosen to ignore the cases userdomain matches localdomain
194
or localhost). Setting user-lookup-even-if-domain-mismatch
195
feature will tell pine to override this behavior and perform
196
the local lookup anyway. The problem of a global "even-if"
197
set and a .pinerc-defined user-domain of something odd causing
198
the local lookup, but this will only effect the personal name,
199
and is not judged to be a significant problem.
201
4. In determining if an address is that of the current pine user for
202
formatting index and filtering addresses when replying
203
If a userdomain is specified the address must match the
204
userdomain exactly. If a userdomain is not specified or the
205
userdomain is the same as the hostname or domainname, then
206
an address will be considered the users if it matches either
207
the domainname or the hostname. Of course, the userid must
211
The fully-qualified hostname is always users here.
214
** Setting the domain names
215
To set the domain name for all Pine users on the system to be
216
different from what Pine figures out from DNS, set the domain name in
217
the "user-domain" variable in pine.conf. To set the domain name for an
218
individual user, set the "user-domain" variable in his .pinerc.
219
The .pinerc setting overrides any other setting.
221
init_hostname(struct pine *ps)
223
char hostname[MAX_ADDRESS+1], domainname[MAX_ADDRESS+1];
225
getdomainnames(hostname, sizeof(hostname)-1,
226
domainname, sizeof(domainname)-1);
229
fs_give((void **)&ps->hostname);
231
ps->hostname = cpystr(hostname);
234
fs_give((void **)&ps->localdomain);
236
ps->localdomain = cpystr(domainname);
237
ps->userdomain = NULL;
239
if(ps->VAR_USER_DOMAIN && ps->VAR_USER_DOMAIN[0]){
240
ps->maildomain = ps->userdomain = ps->VAR_USER_DOMAIN;
242
#if defined(DOS) || defined(OS2)
243
if(ps->VAR_USER_DOMAIN)
244
ps->blank_user_domain = 1; /* user domain set to null string! */
246
ps->maildomain = ps->localdomain[0] ? ps->localdomain : ps->hostname;
248
ps->maildomain = strucmp(ps->VAR_USE_ONLY_DOMAIN_NAME, "yes")
249
? ps->hostname : ps->localdomain;
254
* Tell c-client what domain to use when completing unqualified
255
* addresses it finds in local mailboxes. Remember, it won't
256
* affect what's to the right of '@' for unqualified addresses in
259
mail_parameters(NULL, SET_LOCALHOST, (void *) ps->maildomain);
260
if(F_OFF(F_QUELL_MAILDOMAIN_WARNING, ps) && !strchr(ps->maildomain, '.')){
261
snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Incomplete maildomain \"%s\"."),
263
init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
265
_("Return address in mail you send may be incorrect."), SIZEOF_20KBUF);
266
tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
267
init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
270
dprint((1,"User domain name being used \"%s\"\n",
271
ps->userdomain == NULL ? "" : ps->userdomain));
272
dprint((1,"Local Domain name being used \"%s\"\n",
273
ps->localdomain ? ps->localdomain : "?"));
274
dprint((1,"Host name being used \"%s\"\n",
275
ps->hostname ? ps->hostname : "?"));
277
"Mail Domain name being used (by c-client too) \"%s\"\n",
278
ps->maildomain ? ps->maildomain : "?"));
280
if(!ps->maildomain || !ps->maildomain[0]){
281
#if defined(DOS) || defined(OS2)
282
if(ps->blank_user_domain)
283
return(0); /* prompt for this in send.c:dos_valid_from */
285
fprintf(stderr, _("No host name or domain name set\n"));
293
/*----------------------------------------------------------------------
294
Make sure the default save folders exist in the default
298
init_save_defaults(void)
300
CONTEXT_S *save_cntxt;
302
if(!ps_global->VAR_DEFAULT_FCC ||
303
!*ps_global->VAR_DEFAULT_FCC ||
304
!ps_global->VAR_DEFAULT_SAVE_FOLDER ||
305
!*ps_global->VAR_DEFAULT_SAVE_FOLDER)
308
if(!(save_cntxt = default_save_context(ps_global->context_list)))
309
save_cntxt = ps_global->context_list;
311
if(!(folder_exists(save_cntxt, ps_global->VAR_DEFAULT_FCC) & FEX_ISFILE))
312
context_create(save_cntxt, NULL, ps_global->VAR_DEFAULT_FCC);
314
if(!(folder_exists(save_cntxt, ps_global->VAR_DEFAULT_SAVE_FOLDER) &
316
context_create(save_cntxt, NULL, ps_global->VAR_DEFAULT_SAVE_FOLDER);
318
free_folder_list(save_cntxt);
322
/*----------------------------------------------------------------------
323
Put sent-mail files in date order
325
Args: a, b -- The names of two files. Expects names to be sent-mail-mmm-yy
326
Other names will sort in order and come before those
330
compare_sm_files(const qsort_t *aa, const qsort_t *bb)
332
struct sm_folder *a = (struct sm_folder *)aa,
333
*b = (struct sm_folder *)bb;
335
if(a->month_num == -1 && b->month_num == -1)
336
return(strucmp(a->name, b->name));
337
if(a->month_num == -1) return(-1);
338
if(b->month_num == -1) return(1);
340
return(a->month_num - b->month_num);
345
/*----------------------------------------------------------------------
346
Create an ordered list of sent-mail folders and their month numbers
348
Args: dir -- The directory to find the list of files in
350
Result: Pointer to list of files is returned.
352
This list includes all files that start with "sent-mail", but not "sent-mail"
356
get_mail_list(CONTEXT_S *list_cntxt, char *folder_base)
358
#define MAX_FILES (150)
359
register struct sm_folder *sm = NULL;
360
struct sm_folder *sml = NULL;
362
int i, folder_base_len;
363
char searchname[MAXPATH+1];
365
sml = sm = (struct sm_folder *)fs_get(sizeof(struct sm_folder)*MAX_FILES);
366
memset((void *)sml, 0, sizeof(struct sm_folder) * MAX_FILES);
367
if((folder_base_len = strlen(folder_base)) == 0 || !list_cntxt){
368
sml->name = cpystr("");
373
if(*list_cntxt->context != '{'){ /* NOT an IMAP collection! */
374
snprintf(searchname, sizeof(searchname), "%4.4s*", folder_base);
375
folder_base_len = strlen(searchname) - 1;
379
snprintf(searchname, sizeof(searchname), "%.*s*", sizeof(searchname)-2, folder_base);
381
build_folder_list(NULL, list_cntxt, searchname, NULL, BFL_FLDRONLY);
382
for(i = 0; i < folder_total(FOLDERS(list_cntxt)); i++){
383
filename = folder_entry(i, FOLDERS(list_cntxt))->name;
385
if(struncmp(filename, folder_base, folder_base_len) == 0
386
&& strucmp(filename, folder_base)){
388
if(*list_cntxt->context != '{'){
390
for(j = 0; j < 4; j++)
391
if(!isdigit((unsigned char)filename[folder_base_len + j]))
394
if(j < 4) /* not proper date format! */
395
continue; /* keep trying */
399
if(strnicmp(filename, folder_base, folder_base_len) == 0
400
&& stricmp(filename, folder_base)){
402
if(strncmp(filename, folder_base, folder_base_len) == 0
403
&& strcmp(filename, folder_base)){
406
sm->name = cpystr(filename);
408
if(*list_cntxt->context != '{'){ /* NOT an IMAP collection! */
409
sm->month_num = (sm->name[folder_base_len] - '0') * 10;
410
sm->month_num += sm->name[folder_base_len + 1] - '0';
414
sm->month_num = month_num(sm->name + (size_t)folder_base_len + 1);
416
if(sm >= &sml[MAX_FILES - 1])
417
break; /* Too many files, ignore the rest ; shouldn't occur */
421
sm->name = cpystr("");
423
/* anything to sort?? */
424
if(sml->name && *(sml->name) && (sml+1)->name && *((sml+1)->name)){
427
sizeof(struct sm_folder),
437
check_prune_time(time_t *now, struct tm **tm_now)
441
*now = time((time_t *) 0);
442
*tm_now = localtime(now);
445
* If the last time we did this is blank (as if pine's run for
446
* first time), don't go thru list asking, but just note it for
449
if(ps_global->VAR_LAST_TIME_PRUNE_QUESTION == NULL){
450
ps_global->last_expire_year = (*tm_now)->tm_year;
451
ps_global->last_expire_month = (*tm_now)->tm_mon;
452
snprintf(tmp, sizeof(tmp), "%d.%d", ps_global->last_expire_year,
453
ps_global->last_expire_month + 1);
454
set_variable(V_LAST_TIME_PRUNE_QUESTION, tmp, 1, 1, Main);
458
if(ps_global->last_expire_year != -1 &&
459
((*tm_now)->tm_year < ps_global->last_expire_year ||
460
((*tm_now)->tm_year == ps_global->last_expire_year &&
461
(*tm_now)->tm_mon <= ps_global->last_expire_month)))
469
first_run_of_month(void)
474
now = time((time_t *) 0);
475
tm_now = localtime(&now);
477
if(ps_global->last_expire_year == -1 ||
478
(tm_now->tm_year < ps_global->last_expire_year ||
479
(tm_now->tm_year == ps_global->last_expire_year &&
480
tm_now->tm_mon <= ps_global->last_expire_month)))
488
first_run_of_year(void)
493
now = time((time_t *) 0);
494
tm_now = localtime(&now);
496
if(ps_global->last_expire_year == -1 ||
497
(tm_now->tm_year <= ps_global->last_expire_year))
504
/*----------------------------------------------------------------------
505
Check pruned-folders for validity, making sure they are in the
506
same context as sent-mail.
510
prune_folders_ok(void)
514
for(p = ps_global->VAR_PRUNED_FOLDERS; p && *p && **p; p++)
515
if(!context_isambig(*p))
523
* prune_move_folder - rename folder in context and delete old copy
524
* Returns -1 if unsuccessful.
527
prune_move_folder(char *oldpath, char *newpath, CONTEXT_S *prune_cntxt)
529
MAILSTREAM *prune_stream = NULL;
530
char spath[MAXPATH+1];
532
strncpy(spath, oldpath, sizeof(spath)-1);
533
spath[sizeof(spath)-1] = '\0';
535
/*--- User says OK to rename ---*/
536
dprint((5, "rename \"%.100s\" to \"%.100s\"\n",
537
spath ? spath : "?", newpath ? newpath : "?"));
538
q_status_message1(SM_ORDER, 1, 3,
539
/* TRANSLATORS: arg is a filename */
540
_("Renaming \"%.200s\" at start of month"),
541
pretty_fn(spath ? spath : "?"));
543
if(!context_rename(prune_cntxt, NULL, spath, newpath)){
544
q_status_message2(SM_ORDER | SM_DING, 3, 4,
545
/* TRANSLATORS: 1st arg is filename, 2nd is error message */
546
_("Error renaming \"%.200s\": %.200s"),
547
pretty_fn(spath ? spath : "?"),
548
error_description(errno));
549
dprint((1, "Error renaming %.100s to %.100s: %.100s\n",
550
spath ? spath : "?", newpath ? newpath : "?",
551
error_description(errno)));
552
display_message('x');
556
context_create(prune_cntxt, NULL, spath);