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