1 /*
2 ** Copyright 1998 - 2008 Double Precision, Inc.  See COPYING for
3 ** distribution information.
4 */
5 
6 
7 /*
8 */
9 #include	"pref.h"
10 #include	"config.h"
11 #include	"auth.h"
12 #include	"sqwebmail.h"
13 #include	"sqconfig.h"
14 #include	"mailinglist.h"
15 #include	"cgi/cgi.h"
16 #include	"pcp/pcp.h"
17 #include	<stdio.h>
18 #include	<string.h>
19 #include	<stdlib.h>
20 #include	<sys/stat.h>
21 #include	<unistd.h>
22 
23 #define	OLDEST1ST	"OLDEST1ST"
24 #define	FULLHEADERS	"FULLHEADERS"
25 #define	SORTORDER	"SORT"
26 #define	PAGESIZE	"PAGESIZE"
27 #define	AUTOPURGE_V	"AUTOPURGE"
28 #define	NOHTML		"NOHTML"
29 #define	FROM		"FROM"
30 #define	LDAP		"LDAP"
31 #define FLOWEDTEXT	"NOFLOWEDTEXT"
32 #define NOARCHIVE	"NOARCHIVE"
33 #define NOAUTORENAMESENT	"NOAUTORENAMESENT"
34 #define STARTOFWEEK	"STARTOFWEEK"
35 #define WIKITEXT		"WIKITEXT"
36 
37 #define	OLDEST1ST_PREF	"oldest1st"
38 #define	FULLHEADERS_PREF "fullheaders"
39 #define	HTML_PREF "doshowhtml"
40 #define FLOWEDTEXT_PREF "noflowedtext"
41 #define NOARCHIVE_PREF "noarchive"
42 #define NOAUTORENAMESENT_PREF "noautorenamesent"
43 
44 #define DEFAULTKEY	"DEFAULTKEY"
45 
46 int pref_flagisoldest1st, pref_flagfullheaders;
47 int pref_showhtml;
48 int pref_flagsortorder;
49 int pref_flagpagesize;
50 int pref_autopurge;
51 int pref_noflowedtext;
52 int pref_noarchive;
53 int pref_noautorenamesent;
54 int pref_startofweek;
55 int pref_wikifmt;
56 
57 char *pref_from=0;
58 char *pref_ldap=0;
59 extern const char *sqwebmail_content_charset;
60 
61 #if ENABLE_WEBPASS
62 extern int check_sqwebpass(const char *);
63 extern void set_sqwebpass(const char *);
64 #endif
65 extern void output_attrencoded_oknl(const char *);
66 extern const char *sqwebmail_mailboxid;
67 extern void rename_sent_folder(int really);
68 
69 static const char hex[]="0123456789ABCDEF";
70 
nybble(char c)71 static int nybble(char c)
72 {
73 char	*p=strchr(hex, c);
74 
75 	if (p)	return (p-hex);
76 	return (0);
77 }
78 
decode(char * t)79 static void decode(char *t)
80 {
81 char *s;
82 
83 	for (s=t; *s; s++)
84 	{
85 		if (*s != '+')
86 		{
87 			*t++ = *s;
88 			continue;
89 		}
90 		if (s[1] == 0 || s[2] == 0)
91 			continue;
92 		*t++ = nybble(s[1]) * 16 + nybble(s[2]);
93 		s += 2;
94 	}
95 	*t=0;
96 }
97 
pref_init()98 void pref_init()
99 {
100 const	char *p;
101 char	*q, *r;
102 
103 	p=read_sqconfig(".", CONFIGFILE, 0);
104 	pref_flagisoldest1st=0;
105 	pref_flagfullheaders=0;
106 	pref_flagsortorder=0;
107 	pref_flagpagesize=10;
108 	pref_noarchive=0;
109 
110 	{
111 		const char *autorenamesent=AUTORENAMESENT;
112 
113 		const char *p=getenv("SQWEBMAIL_AUTORENAMESENT");
114 		if (p && *p)
115 			autorenamesent = p;
116 
117 		pref_noautorenamesent=strncmp(autorenamesent, "no", 2) == 0;
118 	}
119 
120 	pref_startofweek=0;
121 	pref_autopurge=AUTOPURGE;
122 	pref_showhtml=1;
123 	pref_wikifmt=0;
124 
125 	if(pref_from) {
126 		free(pref_from);
127 		pref_from=0;
128 		}
129 
130 	if(pref_ldap) {
131 		free(pref_ldap);
132 		pref_ldap=0;
133 		}
134 
135 
136 	if (p)
137 	{
138 		q=strdup(p);
139 		if (!q)	enomem();
140 
141 		for (r=q; (r=strtok(r, " ")) != 0; r=0)
142 		{
143 			if (strcmp(r, OLDEST1ST) == 0)
144 				pref_flagisoldest1st=1;
145 			if (strcmp(r, FULLHEADERS) == 0)
146 				pref_flagfullheaders=1;
147 			if (strcmp(r, NOHTML) == 0)
148 				pref_showhtml=0;
149 			if (strcmp(r, WIKITEXT) == 0)
150 				pref_wikifmt=1;
151 
152 			if (strncmp(r, SORTORDER, sizeof(SORTORDER)-1) == 0
153 				&& r[sizeof(SORTORDER)-1] == '=')
154 				pref_flagsortorder=r[sizeof(SORTORDER)];
155 			if (strncmp(r, PAGESIZE, sizeof(PAGESIZE)-1) == 0
156 				&& r[sizeof(PAGESIZE)-1] == '=')
157 				pref_flagpagesize=atoi(r+sizeof(PAGESIZE));
158 			if (strncmp(r, AUTOPURGE_V, sizeof(AUTOPURGE_V)-1) == 0
159 				&& r[sizeof(AUTOPURGE_V)-1] == '=')
160 				pref_autopurge=atoi(r+sizeof(AUTOPURGE_V));
161 			if (strncmp(r, FLOWEDTEXT, sizeof(FLOWEDTEXT)-1) == 0
162 				&& r[sizeof(FLOWEDTEXT)-1] == '=')
163 				pref_noflowedtext=atoi(r+sizeof(FLOWEDTEXT));
164 			if (strncmp(r, NOARCHIVE, sizeof(NOARCHIVE)-1) == 0
165 				&& r[sizeof(NOARCHIVE)-1] == '=')
166 				pref_noarchive=atoi(r+sizeof(NOARCHIVE));
167 			if (strncmp(r, NOAUTORENAMESENT, sizeof(NOAUTORENAMESENT)-1) == 0
168 				&& r[sizeof(NOAUTORENAMESENT)-1] == '=')
169 				pref_noautorenamesent=atoi(r+sizeof(NOAUTORENAMESENT));
170 			if (strncmp(r, FROM, sizeof(FROM)-1) == 0
171 				&& r[sizeof(FROM)-1] == '=')
172 			{
173 				if (pref_from)	free(pref_from);
174 				if ((pref_from=strdup(r+sizeof(FROM))) == 0)
175 					enomem();
176 
177 				decode(pref_from);
178 			}
179 			if (strncmp(r, LDAP, sizeof(LDAP)-1) == 0
180 				&& r[sizeof(LDAP)-1] == '=')
181 			{
182 				if (pref_ldap)	free(pref_ldap);
183 				if ((pref_ldap=strdup(r+sizeof(LDAP))) == 0)
184 					enomem();
185 
186 				decode(pref_ldap);
187 			}
188 			if (strncmp(r, STARTOFWEEK, sizeof(STARTOFWEEK)-1) == 0
189 				&& r[sizeof(STARTOFWEEK)-1] == '=')
190 			{
191 				int n=atoi(r+sizeof(STARTOFWEEK));
192 
193 				if (n >= 0 && n < 7)
194 					pref_startofweek=n;
195 			}
196 
197 		}
198 		free(q);
199 	}
200 	switch (pref_flagpagesize)	{
201 	case 20:
202 	case 50:
203 	case 100:
204 	case 250:
205 		break;
206 	default:
207 		pref_flagpagesize=10;
208 		break;
209 	}
210 
211 	if (pref_autopurge < 0)	pref_autopurge=0;
212 	if (pref_autopurge > MAXPURGE)	pref_autopurge=MAXPURGE;
213 
214 	switch (pref_flagsortorder)	{
215 	case 'F':
216 	case 'S':
217 		break;
218 	default:
219 		pref_flagsortorder='D';
220 		break;
221 	}
222 }
223 
224 #if 0
225 #if ENABLE_WEBPASS
226 static int goodpass(const char *p)
227 {
228 	for ( ; *p; p++)
229 		if (*p < ' ')	return (0);
230 	return (1);
231 }
232 #endif
233 #endif
234 
append_str(const char * prefs,const char * label,const char * value)235 static char *append_str(const char *prefs, const char *label,
236 	const char *value)
237 {
238 int	l=strlen(prefs) + sizeof(" =") +
239 	strlen(label)+ (value ? strlen(value):0);
240 int	i;
241 char	*p;
242 const char *q;
243 
244 	for (i=0; value && value[i]; i++)
245 		if (value[i] <= ' ' || value[i] >= 127
246 			|| value[i] == '+')
247 			l += 2;
248 
249 	p=malloc(l);
250 	if (!p)	enomem();
251 	strcpy(p, prefs);
252 	if (!value || !*value)	return (p);
253 
254 	strcat(strcat(strcat(p, " "), label), "=");
255 	i=strlen(p);
256 	for (q=value; *q; q++)
257 	{
258 		if (*q <= ' ' || *q >= 127 || *q == '+')
259 		{
260 			sprintf(p+i, "+%02X", (int)(unsigned char)*q);
261 			i += 3;
262 			continue;
263 		}
264 		p[i++]= *q;
265 	}
266 	p[i]=0;
267 	return (p);
268 }
269 
pref_update()270 void pref_update()
271 {
272 char	buf[1000];
273 char	*p;
274 char	*q;
275 
276 	sprintf(buf, SORTORDER "=%c " PAGESIZE "=%d " AUTOPURGE_V "=%d "
277 		FLOWEDTEXT "=%d " NOARCHIVE "=%d " NOAUTORENAMESENT "=%d "
278 		STARTOFWEEK "=%d",
279 		pref_flagsortorder, pref_flagpagesize, pref_autopurge,
280 		pref_noflowedtext, pref_noarchive, pref_noautorenamesent,
281 		pref_startofweek);
282 
283 	if (pref_flagisoldest1st)
284 		strcat(buf, " " OLDEST1ST);
285 
286 	if (pref_flagfullheaders)
287 		strcat(buf, " " FULLHEADERS);
288 
289 	if (!pref_showhtml)
290 		strcat(buf, " " NOHTML);
291 
292 	if (pref_wikifmt)
293 		strcat(buf, " " WIKITEXT);
294 
295 	p=append_str(buf, FROM, pref_from);
296 	q=append_str(p, LDAP, pref_ldap);
297 	write_sqconfig(".", CONFIGFILE, q);
298 	free(q);
299 	free(p);
300 }
301 
pref_setfrom(const char * p)302 void pref_setfrom(const char *p)
303 {
304 	if (pref_from)	free(pref_from);
305 	pref_from=strdup(p);
306 	if (!pref_from)	enomem();
307 	pref_update();
308 }
309 
pref_setldap(const char * p)310 void pref_setldap(const char *p)
311 {
312 	if (pref_ldap && strcmp(p, pref_ldap) == 0)
313 		return;
314 
315 	if (pref_ldap)	free(pref_ldap);
316 	pref_ldap=strdup(p);
317 	if (!pref_ldap)	enomem();
318 	pref_update();
319 }
320 
pref_setprefs()321 void pref_setprefs()
322 {
323 	if (*cgi("do.changeprefs"))
324 	{
325 	char	buf[1000];
326 	FILE	*fp;
327 	char	*p;
328 	char	*q;
329 
330 		sprintf(buf, SORTORDER "=%c " PAGESIZE "=%s " AUTOPURGE_V "=%s "
331 			FLOWEDTEXT "=%s "
332 			NOARCHIVE "=%s "
333 			NOAUTORENAMESENT "=%s "
334 			STARTOFWEEK "=%d",
335 			*cgi("sortorder"), cgi("pagesize"), cgi("autopurge"),
336 			*cgi(FLOWEDTEXT_PREF) ? "1":"0",
337 			*cgi(NOARCHIVE_PREF) ? "1":"0",
338 			*cgi(NOAUTORENAMESENT_PREF) ? "1":"0",
339 			(int)((unsigned)atoi(cgi(STARTOFWEEK)) % 7)
340 			);
341 
342 		if (*cgi(OLDEST1ST_PREF))
343 			strcat(buf, " " OLDEST1ST);
344 		if (*cgi(FULLHEADERS_PREF))
345 			strcat(buf, " " FULLHEADERS);
346 		if (!*cgi(HTML_PREF))
347 			strcat(buf, " " NOHTML);
348 
349 		p=append_str(buf, FROM, pref_from);
350 		q=append_str(p, LDAP, pref_ldap);
351 		write_sqconfig(".", CONFIGFILE, q);
352 		free(p);
353 		free(q);
354 		pref_init();
355 		if ((fp=fopen(SIGNATURE, "w")) != NULL)
356 		{
357 			char *sig_utf8=
358 				unicode_convert_toutf8(cgi("signature"),
359 							 sqwebmail_content_charset,
360 							 NULL);
361 
362 			if (sig_utf8)
363 			{
364 				fprintf(fp, "%s", sig_utf8);
365 				free(sig_utf8);
366 			}
367 			fclose(fp);
368 		}
369 
370 		savemailinglists(cgi("mailinglists"));
371 
372 		printf("%s\n", getarg("PREFSOK"));
373 
374 		rename_sent_folder(0);
375 	}
376 
377 	if (*cgi("do.changepwd"))
378 	{
379 		int status=1;
380 		const	char *p=cgi("newpass");
381 		int has_syspwd=0;
382 
383 		if ( *p && strcmp(p, cgi("newpass2")) == 0
384 			&& strlen(p) >= MINPASSLEN)
385 		{
386 			has_syspwd=
387 				login_changepwd(sqwebmail_mailboxid,
388 						cgi("oldpass"), p,
389 						&status);
390 		}
391 
392 		if (has_syspwd || status)
393 		{
394 			printf("%s\n", getarg("PWDERR"));
395 		}
396 		else
397 		{
398 			printf("%s\n", getarg("PWDOK"));
399 		}
400 	}
401 
402 #if 0
403 	if (*cgi("do.changepwd"))
404 	{
405 #if ENABLE_WEBPASS
406 
407 	const	char *p;
408 
409 		if (check_sqwebpass(cgi("oldpass")) == 0 &&
410 			*(p=cgi("newpass")) &&
411 			goodpass(p) &&
412 			strcmp(p, cgi("newpass2")) == 0)
413 		{
414 			set_sqwebpass(p);
415 		}
416 		else
417 		{
418 			printf("%s\n", getarg("PWDERR"));
419 		}
420 #else
421 		printf("%s\n", getarg("PWDERR"));
422 #endif
423 	}
424 #endif
425 }
426 
pref_isoldest1st()427 void pref_isoldest1st()
428 {
429 	printf("<input type=\"checkbox\" name=\"%s\" id=\"%s\"%s />",
430 		OLDEST1ST_PREF, OLDEST1ST_PREF, pref_flagisoldest1st ? " checked=\"checked\"":"");
431 }
432 
pref_isdisplayfullmsg()433 void pref_isdisplayfullmsg()
434 {
435 	printf("<input type=\"checkbox\" name=\"%s\" id=\"%s\"%s />",
436 		FULLHEADERS_PREF, FULLHEADERS_PREF, pref_flagfullheaders ? " checked=\"checked\"":"");
437 }
438 
pref_displayhtml()439 void pref_displayhtml()
440 {
441 	printf("<input type=\"checkbox\" name=\"%s\" id=\"%s\"%s />",
442 		HTML_PREF, HTML_PREF, pref_showhtml ? " checked=\"checked\"":"");
443 }
444 
pref_displayflowedtext()445 void pref_displayflowedtext()
446 {
447 	printf("<input type=\"checkbox\" name=\"%s\" id=\"%s\"%s />",
448 		FLOWEDTEXT_PREF, FLOWEDTEXT_PREF, pref_noflowedtext ? " checked=\"checked\"":"");
449 }
450 
pref_displayweekstart()451 void pref_displayweekstart()
452 {
453 	int i, j;
454 	static const int d[3]={6,0,1};
455 
456 	printf("<select name=\"" STARTOFWEEK "\">");
457 
458 	for (j=0; j<3; j++)
459 	{
460 		i=d[j];
461 		printf("<option value=\"%d\"%s>", i,
462 		       i == pref_startofweek ? " selected='selected'":"");
463 
464 		output_attrencoded_oknl( pcp_wdayname_long(i));
465 		printf("</option>");
466 	}
467 	printf("</select>");
468 }
469 
pref_displaynoarchive()470 void pref_displaynoarchive()
471 {
472 	printf("<input type=\"checkbox\" name=\"%s\" id=\"%s\"%s />",
473 		NOARCHIVE_PREF, NOARCHIVE_PREF, pref_noarchive ? " checked=\"checked\"":"");
474 }
475 
pref_displaynoautorenamesent()476 void pref_displaynoautorenamesent()
477 {
478 	printf("<input type=\"checkbox\" name=\"%s\" id=\"%s\"%s />",
479 		NOAUTORENAMESENT_PREF, NOAUTORENAMESENT_PREF, pref_noautorenamesent ? " checked=\"checked\"":"");
480 }
481 
pref_displayautopurge()482 void pref_displayautopurge()
483 {
484 	printf("<input type=\"text\" name=\"autopurge\" value=\"%d\" size=\"2\" maxlength=\"2\" />",
485 		pref_autopurge);
486 }
487 
pref_sortorder()488 void pref_sortorder()
489 {
490 static const char selected[]=" selected='selected'";
491 
492 	printf("<select name=\"sortorder\">");
493 	printf("<option value=\"DATE\"%s>%s</option>\n",
494 		pref_flagsortorder == 'D' ? selected:"",
495 	       getarg("DATE"));
496 
497 	printf("<option value=\"FROM\"%s>%s</option>\n",
498 		pref_flagsortorder == 'F' ? selected:"",
499 	       getarg("SENDER"));
500 	printf("<option value=\"SUBJECT\"%s>%s</option>\n",
501 		pref_flagsortorder == 'S' ? selected:"",
502 	       getarg("SUBJECT"));
503 	printf("</select>\n");
504 }
505 
pref_pagesize()506 void pref_pagesize()
507 {
508 static const char selected[]=" selected='selected'";
509 
510 	printf("<select name=\"pagesize\">");
511 	printf("<option value=\"10\"%s>10</option>\n",
512 		pref_flagpagesize == 10 ? selected:"");
513 	printf("<option value=\"20\"%s>20</option>\n",
514 		pref_flagpagesize == 20 ? selected:"");
515 	printf("<option value=\"50\"%s>50</option>\n",
516 		pref_flagpagesize == 50 ? selected:"");
517 	printf("<option value=\"100\"%s>100</option>\n",
518 		pref_flagpagesize == 100 ? selected:"");
519 	printf("<option value=\"250\"%s>250</option>\n",
520 		pref_flagpagesize == 250 ? selected:"");
521 	printf("</select>\n");
522 }
523 
pref_getsig()524 char *pref_getsig()
525 {
526 	return pref_getfile(fopen(SIGNATURE, "r"));
527 }
528 
pref_getfile(FILE * fp)529 char *pref_getfile(FILE *fp)
530 {
531 	struct stat st;
532 	char *utf8_buf;
533 	char *sig_buf;
534 
535 	if (fp == NULL)
536 		return NULL;
537 
538 	if (fstat(fileno(fp), &st) < 0)
539 	{
540 		fclose(fp);
541 		return NULL;
542 	}
543 
544 	utf8_buf=malloc(st.st_size+1);
545 
546 	if (!utf8_buf)
547 	{
548 		fclose(fp);
549 		return NULL;
550 	}
551 
552 	if (fread(utf8_buf, 1, st.st_size, fp) != st.st_size)
553 	{
554 		fclose(fp);
555 		return NULL;
556 	}
557 	utf8_buf[st.st_size]=0;
558 	fclose(fp);
559 
560 	sig_buf=unicode_convert_fromutf8(utf8_buf,
561 					   sqwebmail_content_charset,
562 					   NULL);
563 	free(utf8_buf);
564 
565 	return sig_buf;
566 }
567 
pref_signature()568 void pref_signature()
569 {
570 	char *p=pref_getsig();
571 
572 	if (p)
573 	{
574 		output_attrencoded_oknl(p);
575 		free(p);
576 	}
577 }
578 /*
579 ** Get a setting from GPGCONFIGFILE
580 **
581 ** GPGCONFIGFILE consists of space-separated settings.
582 */
583 
getgpgconfig(const char * name)584 static char *getgpgconfig(const char *name)
585 {
586 	const char *p;
587 	char	*q, *r;
588 
589 	int name_l=strlen(name);
590 
591 	p=read_sqconfig(".", GPGCONFIGFILE, 0);
592 
593 	if (p)
594 	{
595 		q=strdup(p);
596 		if (!q)
597 			enomem();
598 
599 		for (r=q; (r=strtok(r, " ")) != NULL; r=NULL)
600 			if (strncmp(r, name, name_l) == 0 &&
601 			    r[name_l] == '=')
602 			{
603 				r=strdup(r+name_l+1);
604 				free(q);
605 				if (!r)
606 					enomem();
607 				return (r);
608 			}
609 		free(q);
610 	}
611 	return (NULL);
612 }
613 
614 /*
615 ** Enter a setting into GPGCONFIGFILE
616 */
617 
setgpgconfig(const char * name,const char * value)618 static void setgpgconfig(const char *name, const char *value)
619 {
620 	const	char *p;
621 	char *q, *r, *s;
622 	int name_l=strlen(name);
623 
624 	/* Get the existing settings */
625 
626 	p=read_sqconfig(".", GPGCONFIGFILE, 0);
627 
628 	if (!p)
629 		p="";
630 
631 	q=strdup(p);
632 	if (!q)
633 		enomem();
634 
635 	s=malloc(strlen(q)+strlen(name)+strlen(value)+4);
636 	if (!s)
637 		enomem();
638 	*s=0;
639 
640 	/*
641 	** Copy existing settings into a new buffer, deleting any old
642 	** setting.
643 	*/
644 
645 	for (r=q; (r=strtok(r, " ")) != NULL; r=NULL)
646 	{
647 		if (strncmp(r, name, name_l) == 0 &&
648 		    r[name_l] == '=')
649 		{
650 			continue;
651 		}
652 
653 		if (*s)
654 			strcat(s, " ");
655 		strcat(s, r);
656 	}
657 
658 	/* Append the new setting */
659 
660 	if (*s)
661 		strcat(s, " ");
662 	strcat(strcat(strcat(s, name), "="), value);
663 	free(q);
664 	write_sqconfig(".", GPGCONFIGFILE, s);
665 	free(s);
666 }
667 
pref_getdefaultgpgkey()668 char *pref_getdefaultgpgkey()
669 {
670 	return (getgpgconfig(DEFAULTKEY));
671 }
672 
pref_setdefaultgpgkey(const char * v)673 void pref_setdefaultgpgkey(const char *v)
674 {
675 	setgpgconfig(DEFAULTKEY, v);
676 }
677