1 /*
2 ** Copyright 1998 - 2009 Double Precision, Inc.  See COPYING for
3 ** distribution information.
4 */
5 
6 
7 /*
8 ** $Id: sqwebmail.c,v 1.147 2009/11/08 18:14:47 mrsam Exp $
9 */
10 #include	"sqwebmail.h"
11 #include	"sqconfig.h"
12 #include	"auth.h"
13 #include	"folder.h"
14 #include	"pref.h"
15 #include	"maildir.h"
16 #include	"cgi/cgi.h"
17 #include	"pref.h"
18 #include	"mailinglist.h"
19 #include	"newmsg.h"
20 #include	"pcp.h"
21 #include	"acl.h"
22 #include	"addressbook.h"
23 #include	"autoresponse.h"
24 #include	"http11/http11.h"
25 #include	"random128/random128.h"
26 #include	"maildir/maildirmisc.h"
27 #include	"maildir/maildirinfo.h"
28 #include	"maildir/maildiraclt.h"
29 #include	"liblock/config.h"
30 #include	"liblock/liblock.h"
31 #include	"rfc822/rfc822hdr.h"
32 #include	"courierauth.h"
33 #include	<stdio.h>
34 #include	<errno.h>
35 #include	<stdlib.h>
36 #if	HAVE_UNISTD_H
37 #include	<unistd.h>
38 #endif
39 #include	<string.h>
40 #include	<signal.h>
41 #include	<sys/types.h>
42 #include	<sys/stat.h>
43 #include	<sys/types.h>
44 #include        <sys/socket.h>
45 #if	HAVE_FCNTL_H
46 #include	<fcntl.h>
47 #endif
48 #if	HAVE_LOCALE_H
49 #if	HAVE_SETLOCALE
50 #include	<locale.h>
51 #if	USE_LIBCHARSET
52 #if	HAVE_LOCALCHARSET_H
53 #include	<localcharset.h>
54 #elif	HAVE_LIBCHARSET_H
55 #include	<libcharset.h>
56 #endif	/* HAVE_LOCALCHARSET_H */
57 #elif	HAVE_LANGINFO_CODESET
58 #include	<langinfo.h>
59 #endif	/* USE_LIBCHARSET */
60 #endif	/* HAVE_SETLOCALE */
61 #endif	/* HAVE_LOCALE_H */
62 #include	<ctype.h>
63 #if HAVE_SYS_WAIT_H
64 #include	<sys/wait.h>
65 #endif
66 #if	HAVE_SYS_SELECT_H
67 #include	<sys/select.h>
68 #endif
69 #if	HAVE_SYS_UIO_H
70 #include	<sys/uio.h>
71 #endif
72 #define	MD5_INTERNAL
73 #include	"md5/md5.h"
74 
75 #include	<courierauthdebug.h>
76 #include	"maildir/maildircache.h"
77 #include	"maildir/maildiraclt.h"
78 #include	"maildir/maildirnewshared.h"
79 #include	"mailfilter.h"
80 #include	"numlib/numlib.h"
81 #include	"gpglib/gpglib.h"
82 #include	"gpg.h"
83 #if	HAVE_CRYPT_H
84 #include	<crypt.h>
85 #endif
86 #if     NEED_CRYPT_PROTOTYPE
87 extern char *crypt(const char *, const char *);
88 #endif
89 #include	"htmllibdir.h"
90 
91 #include	"logindomainlist.h"
92 
93 #include	"strftime.h"
94 
95 extern void spell_show();
96 extern void spell_check_continue();
97 extern void print_safe(const char *);
98 extern void ldaplist();
99 extern int ldapsearch();
100 extern void doldapsearch();
101 
102 extern void sent_gpgerrtxt();
103 extern void sent_gpgerrresume();
104 extern const char *redirect_hash(const char *);
105 
106 const char *sqwebmail_mailboxid=0;
107 const char *sqwebmail_folder=0;
108 
109 #define ALL_RIGHTS \
110 	ACL_ADMINISTER \
111 	ACL_CREATE \
112 	ACL_EXPUNGE \
113 	ACL_INSERT \
114 	ACL_LOOKUP \
115 	ACL_READ \
116 	ACL_SEEN \
117 	ACL_DELETEMSGS \
118 	ACL_WRITE \
119 	ACL_DELETEFOLDER
120 char sqwebmail_folder_rights[sizeof(ALL_RIGHTS)];
121 
122 const char *sqwebmail_sessiontoken=0;
123 
124 const char *sqwebmail_content_language=0;
125 const char *sqwebmail_content_locale;
126 const char *sqwebmail_system_charset=0;
127 static char *sys_locale_charset=0;
128 
129 const char *sqwebmail_content_ispelldict;
130 const char *sqwebmail_content_charset;
131 
132 dev_t sqwebmail_homedir_dev;
133 ino_t sqwebmail_homedir_ino;
134 
135 static int noimages=0;
136 
137 time_t	login_time;
138 
139 extern int nochangepass();
140 
141 /* Need to cache the following environment variables */
142 static const char * const authvars[] = { "AUTHADDR", "AUTHFULLNAME",
143 					 "OPTIONS", "AUTHENTICATED", 0 };
144 
145 #ifdef	GZIP
146 static int gzip_save_fd;
147 
148 #endif
149 
150 static const char *sqwebmail_formname;
151 
152 extern void attachments_head(const char *, const char *, const char *);
153 extern void attachments_opts(const char *);
154 extern void doattach(const char *, const char *);
155 
156 static void timezonelist();
157 
158 struct template_stack {
159 	struct template_stack *next;
160 	FILE *fp;
161 } ;
162 
163 static struct template_stack *template_stack=NULL;
164 
165 char *trim_spaces(const char *s);
166 
get_timeoutsoft()167 size_t get_timeoutsoft()
168 {
169 	time_t n=TIMEOUTSOFT;
170 	const char *p;
171 
172 	p=getenv("SQWEBMAIL_TIMEOUTSOFT");
173 
174 	if (p && *p)
175 		n=atoi(p);
176 
177 	return n;
178 }
179 
get_timeouthard()180 size_t get_timeouthard()
181 {
182 	time_t n=TIMEOUTHARD;
183 	const char *p;
184 
185 	p=getenv("SQWEBMAIL_TIMEOUTHARD");
186 
187 	if (p && *p)
188 		n=atoi(p);
189 
190 	return n;
191 }
192 
fake_exit(int n)193 void fake_exit(int n)
194 {
195 	maildir_cache_cancel();
196 	exit(n);
197 }
198 
199 
200 /* Stub to catch aborts from authlib */
201 
authexit(int n)202 void authexit(int n)
203 {
204 	fake_exit(n);
205 }
206 
207 /* enomem() used to be just an out-of-memory handler.  Now, I use it as a
208 ** generic failure type of a deal.
209 */
210 
rfc2045_error(const char * p)211 void rfc2045_error(const char *p)
212 {
213 	error(p);
214 }
215 
print_attrencodedlen(const char * p,size_t len,int oknl,FILE * fp)216 void print_attrencodedlen(const char *p, size_t len, int oknl, FILE *fp)
217 {
218 	for (; len; p++, --len)
219 	{
220 		switch (*p)	{
221 		case '<':
222 			fprintf(fp, "&lt;");
223 			continue;
224 		case '>':
225 			fprintf(fp, "&gt;");
226 			continue;
227 		case '&':
228 			fprintf(fp, "&amp;");
229 			continue;
230 		case '"':
231 			fprintf(fp, "&quot;");
232 			continue;
233 		case '\n':
234 			if (oknl)
235 			{
236 				if (oknl == 2)
237 				{
238 					fprintf(fp, "<br />");
239 					continue;
240 				}
241 				putc('\n', fp);
242 				continue;
243 			}
244 		default:
245 			if (!ISCTRL(*p))
246 			{
247 				putc(*p, fp);
248 				continue;
249 			}
250 		}
251 		fprintf(fp, "&#%d;", (int)(unsigned char)*p);
252 	}
253 }
254 
output_attrencoded_fp(const char * p,FILE * fp)255 void output_attrencoded_fp(const char *p, FILE *fp)
256 {
257 	print_attrencodedlen(p, strlen(p), 0, fp);
258 }
259 
output_attrencoded(const char * p)260 void output_attrencoded(const char *p)
261 {
262 	output_attrencoded_fp(p, stdout);
263 }
264 
output_attrencoded_oknl_fp(const char * p,FILE * fp)265 void output_attrencoded_oknl_fp(const char *p, FILE *fp)
266 {
267 	print_attrencodedlen(p, strlen(p), 1, fp);
268 }
269 
output_attrencoded_oknl(const char * p)270 void output_attrencoded_oknl(const char *p)
271 {
272 	output_attrencoded_oknl_fp(p, stdout);
273 }
274 
output_attrencoded_nltobr(const char * p)275 void output_attrencoded_nltobr(const char *p)
276 {
277 	print_attrencodedlen(p, strlen(p), 2, stdout);
278 }
279 
output_urlencoded(const char * p)280 void output_urlencoded(const char *p)
281 {
282 char	*q=cgiurlencode(p);
283 
284 	printf("%s", q);
285 	free(q);
286 }
287 
output_loginscriptptr()288 void output_loginscriptptr()
289 {
290 #if	USE_HTTPS_LOGIN
291 const	char *p=cgihttpsscriptptr();
292 #elif	USE_RELATIVE_URL
293 const	char *p=cgirelscriptptr();
294 #else
295 const	char *p=cgihttpscriptptr();
296 #endif
297 
298 	printf("%s", p);
299 }
300 
nonloginscriptptr()301 const char *nonloginscriptptr()
302 {
303 #if	USE_HTTPS
304 	return (cgihttpsscriptptr());
305 #elif	USE_RELATIVE_URL
306 	return (cgirelscriptptr());
307 #else
308 	return (cgihttpscriptptr());
309 #endif
310 }
311 
312 
output_scriptptr()313 void output_scriptptr()
314 {
315 const	char *p=nonloginscriptptr();
316 
317 	printf("%s", p);
318 	if (sqwebmail_mailboxid)
319 	{
320 	char	*q=cgiurlencode(sqwebmail_mailboxid);
321 	char	buf[NUMBUFSIZE];
322 
323 		printf("/login/%s/%s/%s", q,
324 			sqwebmail_sessiontoken ?  sqwebmail_sessiontoken:" ",
325 			libmail_str_time_t(login_time, buf));
326 		free(q);
327 	}
328 }
329 
output_loginscriptptr_get()330 void output_loginscriptptr_get()
331 {
332 	output_loginscriptptr();
333 	if (sqwebmail_mailboxid)
334 	{
335 	char	*q=cgiurlencode(sqwebmail_mailboxid);
336 	char	buf[NUMBUFSIZE];
337 
338 		printf("/login/%s/%s/%s", q,
339 			sqwebmail_sessiontoken ?  sqwebmail_sessiontoken:" ",
340 			libmail_str_time_t(login_time, buf));
341 		free(q);
342 	}
343 }
344 
scriptptrget()345 char *scriptptrget()
346 {
347 char	*q=0;
348 size_t	l=0;
349 int	i;
350 char	buf[NUMBUFSIZE];
351 
352 #define	ADD(s) {const char *zz=(s); if (i) strcat(q, zz); l += strlen(zz);}
353 #define ADDE(ue) { char *yy=cgiurlencode(ue); ADD(yy); free(yy); }
354 
355 	for (i=0; i<2; i++)
356 	{
357 		if (i && (q=malloc(l+1)) == 0)	enomem();
358 		if (i)	*q=0;
359 		ADD( nonloginscriptptr() );
360 		if (!sqwebmail_mailboxid)
361 		{
362 			ADD("?");
363 			continue;
364 		}
365 
366 		ADD("/login/");
367 		ADDE(sqwebmail_mailboxid);
368 		ADD("/");
369 		ADD(sqwebmail_sessiontoken ? sqwebmail_sessiontoken:" ");
370 		ADD("/");
371 		ADD(libmail_str_time_t(login_time, buf));
372 
373 		ADD( "?" );
374 		if (sqwebmail_folder)
375 		{
376 			ADD("folder=");
377 			ADDE(sqwebmail_folder);
378 		}
379 	}
380 #undef	ADD
381 #undef	ADDE
382 	return (q);
383 }
384 
output_scriptptrget()385 void output_scriptptrget()
386 {
387 char	*p=scriptptrget();
388 
389 	printf("%s", p);
390 	free(p);
391 	return;
392 }
393 
output_scriptptrpostinfo()394 void output_scriptptrpostinfo()
395 {
396 	if (sqwebmail_folder)
397 	{
398 		printf("<input type=\"hidden\" name=\"folder\" value=\"");
399 		output_attrencoded(sqwebmail_folder);
400 		printf("\" />");
401 	}
402 
403 	if (*cgi("folderdir"))	/* In folders.html */
404 	{
405 		printf("<input type=\"hidden\" name=\"folderdir\" value=\"");
406 		output_attrencoded(cgi("folderdir"));
407 		printf("\" />");
408 	}
409 }
410 
error(const char * errmsg)411 void error(const char *errmsg)
412 {
413 	cginocache();
414 	printf("Content-Type: text/html; charset=us-ascii\n\n"
415 		"<html><head><title>%s</title></head><body><h1>%s</h1></body></html>\n",
416 		errmsg, errmsg);
417 	cleanup();
418 	fake_exit(1);
419 }
420 
error2(const char * file,int line)421 void error2(const char *file, int line)
422 {
423 	cginocache();
424 	printf("Content-Type: text/html; charset=us-ascii\n\n"
425 		"<html><head><title>Internal error</title></head><body>"
426 		"<h1>Internal error (module %s, line %d) - contact system administrator</h1>"
427 		"</body></html>\n",
428 		file, line);
429 	cleanup();
430 	fake_exit(1);
431 }
432 
error3(const char * file,int line,const char * msg1,const char * msg2,int err)433 void error3(const char *file, int line, const char *msg1, const char *msg2, int err)
434 {
435 	cginocache();
436 	if (err == -1) err = errno;
437 	printf("Content-Type: text/html; charset=us-ascii\n\n"
438 		"<html><head><title>Internal error</title></head><body>"
439 		"<h1>Internal error (module %s, line %d) - contact system administrator</h1>"
440 		"<pre>%s\n%s\n%s</pre>"
441 		"</body></html>\n",
442 		file, line, msg1?msg1:"", msg2?msg2:"", err?strerror(err):"");
443 	cleanup();
444 	fake_exit(1);
445 }
446 
447 
get_templatedir()448 char *get_templatedir()
449 {
450 char	*templatedir=getenv("SQWEBMAIL_TEMPLATEDIR");
451 
452 	if (!templatedir || !*templatedir)	templatedir=HTMLLIBDIR;
453 
454 	return templatedir;
455 }
456 
457 
get_imageurl()458 char *get_imageurl()
459 {
460 char	*imageurl=getenv("SQWEBMAIL_IMAGEURL");
461 
462 	if (!imageurl || !*imageurl)	imageurl=IMGPATH;
463 
464 	return imageurl;
465 }
466 
467 
open_langform(const char * lang,const char * formname,int print_header)468 FILE *open_langform(const char *lang, const char *formname,
469 		    int print_header)
470 {
471 char	*formpath;
472 FILE	*f;
473 char	*templatedir=get_templatedir();
474 
475 	/* templatedir/lang/formname */
476 
477 	if (!(formpath=malloc(strlen(templatedir)+3+
478 		strlen(lang)+strlen(formname))))
479 		error("Out of memory.");
480 
481 	strcat(strcat(strcat(strcat(strcpy(formpath, templatedir), "/"),
482 		lang), "/"), formname);
483 
484 	f=fopen(formpath, "r");
485 
486 	free(formpath);
487 
488 	if (f && print_header)
489 		printf("Content-Language: %s\n", lang);
490 	if (f)
491 		fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
492 	return (f);
493 }
494 
ishttps()495 int ishttps()
496 {
497 	const char *p=getenv("HTTPS");
498 
499 	return (p && strcasecmp(p, "on") == 0);
500 }
501 
502 struct var_put_buf {
503 	char argbuf[3072];
504 	char *argp;
505 	size_t argn;
506 } ;
507 
var_put_buf_func(int c,void * p)508 static void var_put_buf_func(int c, void *p)
509 {
510 	struct var_put_buf *pp=(struct var_put_buf *)p;
511 
512 	if (pp->argn)
513 	{
514 		*pp->argp++=c;
515 		--pp->argn;
516 	}
517 }
518 
pass_image_through(int c,void * p)519 static void pass_image_through(int c, void *p)
520 {
521 	putchar(c);
522 }
523 
output_image(FILE * f,void (* output_func)(int,void *),void * void_arg)524 static void output_image( FILE *f,
525 			  void (*output_func)(int, void *), void *void_arg)
526 {
527 	int c;
528 
529 	/*
530 	  Conditional image.  It's formatted as follows:
531 
532 	  @@filename,width=x height=y@text@
533             ^
534             |
535 	    ----- we're at this point now.
536 
537 	  If images are enabled, we replace that with an IMG tag we build from
538 	  filename,width=x, height=y.
539 	  If images are disabled, we replace all of this with text.
540 
541 	*/
542 
543 #define	MKIMG(c)	(*output_func)((c), void_arg)
544 
545 	if (noimages)
546 	{
547 		while ((c=getc(f)) >= 0
548 		       && c != '@')
549 			;
550 		while ((c=getc(f)) >= 0
551 		       && c != '@')
552 			MKIMG(c);
553 	}
554 	else
555 	{
556 		char	*p;
557 
558 		MKIMG('<');
559 		MKIMG('i');
560 		MKIMG('m');
561 		MKIMG('g');
562 		MKIMG(' ');
563 		MKIMG('s');
564 		MKIMG('r');
565 		MKIMG('c');
566 		MKIMG('=');
567 		MKIMG('"');
568 		for (p=get_imageurl(); *p; p++)
569 			MKIMG(*p);
570 
571 		MKIMG('/');
572 		while ((c=getc(f)) >= 0
573 		       && c != '@' && c != ',')
574 			MKIMG(c);
575 		MKIMG('"');
576 		MKIMG(' ');
577 		if (c == ',')
578 			c=getc(f);
579 		while (c >= 0 && c != '@')
580 		{
581 			MKIMG(c);
582 			c=getc(f);
583 		}
584 		while ((c=getc(f)) >= 0 && c != '@')
585 			;
586 		MKIMG(' ');
587 		MKIMG('/');
588 		MKIMG('>');
589 	}
590 }
591 
592 /* ---- time zone list ---- */
593 
timezonefile(int (* callback_func)(const char *,const char *,void *),void * callback_arg)594 static int timezonefile( int (*callback_func)(const char *, const char *,
595 					      void *), void *callback_arg)
596 {
597 	FILE *f=NULL;
598 	char buffer[BUFSIZ];
599 
600 	if (sqwebmail_content_language)
601 		f=open_langform(sqwebmail_content_language, "TIMEZONELIST", 0);
602 
603 	if (!f)	f=open_langform(HTTP11_DEFAULTLANG, "TIMEZONELIST", 0);
604 
605 	if (!f)
606 		return (0);
607 
608 	while (fgets(buffer, sizeof(buffer), f) != NULL)
609 	{
610 		char *p=strchr(buffer, '\n');
611 		char *tz;
612 		int rc;
613 
614 		if (p) *p=0;
615 
616 		p=strchr(buffer, '#');
617 		if (p) *p=0;
618 
619 		for (p=buffer; *p; p++)
620 			if (!isspace((int)(unsigned char)*p))
621 				break;
622 
623 		if (!*p)
624 			continue;
625 
626 		tz=p;
627 		while (*p)
628 		{
629 			if (isspace((int)(unsigned char)*p))
630 				break;
631 			++p;
632 		}
633 		if (*p) *p++=0;
634 		while (*p && isspace((int)(unsigned char)*p))
635 			++p;
636 
637 		if (strcmp(p, "*") == 0)
638 			p="";
639 		if (strcmp(tz, "*") == 0)
640 			tz="";
641 
642 		rc= (*callback_func)(tz, p, callback_arg);
643 
644 		if (rc)
645 		{
646 			fclose(f);
647 			return (rc);
648 		}
649 	}
650 	fclose(f);
651 	return (0);
652 }
653 
654 static int callback_timezonelist(const char *, const char *, void *);
655 
timezonelist()656 static void timezonelist()
657 {
658 	printf("<select name=\"timezonelist\" class=\"timezonelist\">");
659 	timezonefile(callback_timezonelist, NULL);
660 	printf("</select>\n");
661 }
662 
callback_timezonelist(const char * tz,const char * n,void * dummy)663 static int callback_timezonelist(const char *tz, const char *n, void *dummy)
664 {
665 	printf("<option value=\"%s\">", tz);
666 	output_attrencoded(n);
667 	printf("</option>\n");
668 	return (0);
669 }
670 
set_timezone(const char * p)671 static int set_timezone(const char *p)
672 {
673 	static char *s_buffer=0;
674 	char *buffer;
675 
676 	if (!p || !*p || strcmp(p, "*") == 0)
677 		return (0);
678 
679 	buffer=malloc(strlen(p)+10);
680 	if (!buffer)
681 		return (0);
682 	strcat(strcpy(buffer, "TZ="), p);
683 
684 	putenv(buffer);
685 
686 	if (s_buffer)
687 		free(buffer);
688 	s_buffer=buffer;
689 
690 	return (0);
691 }
692 
693 static int callback_get_timezone(const char *, const char *, void *);
694 
695 /* Return TZ selected from login dropdown */
696 
get_timezone()697 static char *get_timezone()
698 {
699 	char *langptr=0;
700 
701 	timezonefile(callback_get_timezone, &langptr);
702 
703 	if (!langptr)
704 	{
705 		langptr=strdup("");
706 		if (!langptr)
707 			enomem();
708 	}
709 
710 	if (*langptr == 0)
711 	{
712 		free(langptr);
713 		langptr=strdup("*");
714 		if (!langptr)
715 			enomem();
716 	}
717 
718 	return(langptr);
719 }
720 
callback_get_timezone(const char * tz,const char * n,void * dummy)721 static int callback_get_timezone(const char *tz, const char *n, void *dummy)
722 {
723 	if (strcmp(tz, cgi("timezonelist")) == 0)
724 	{
725 		char **p=(char **)dummy;
726 
727 		if (*p)
728 			free(*p);
729 
730 		*p=strdup(tz);
731 	}
732 	return (0);
733 }
734 
735 /* ------------------------ */
736 
do_open_form(const char * formname,int flag)737 static FILE *do_open_form(const char *formname, int flag)
738 {
739 	struct template_stack *ts;
740 	FILE	*f=NULL;
741 
742 	if ((ts=(struct template_stack *)malloc(sizeof(struct template_stack)))
743 	    == NULL)
744 		return (NULL);
745 
746 	if (sqwebmail_content_language)
747 		f=open_langform(sqwebmail_content_language, formname, flag);
748 	if (!f)	f=open_langform(HTTP11_DEFAULTLANG, formname, flag);
749 
750 	if (!f)
751 	{
752 		free(ts);
753 		return (NULL);
754 	}
755 
756 	ts->next=template_stack;
757 	template_stack=ts;
758 	ts->fp=f;
759 	return (f);
760 }
761 
do_close_form()762 static void do_close_form()
763 {
764 	struct template_stack *ts=template_stack;
765 
766 	if (!ts)
767 		enomem();
768 
769 	fclose(ts->fp);
770 	template_stack=ts->next;
771 	free(ts);
772 }
773 
774 static void do_output_form_loop(FILE *);
775 
fix_xml_header(FILE * f)776 static void fix_xml_header(FILE *f)
777 {
778 	char linebuf[80];
779 
780 	/*
781 	** Some templates now have an <?xml > header.  Adjust the
782 	** encoding to match the selected default.  Yes, it's a dirty hack,
783 	** and I'm proud of it, since it allows me to continue editing the
784 	** HTML templates in Amaya.
785 	*/
786 
787 	if (fgets(linebuf, sizeof(linebuf), f) == NULL)
788 		return;
789 
790 	if (strncasecmp(linebuf, "<?xml version=", 14) == 0)
791 		sprintf(linebuf, "<?xml version=\"1.0\" encoding=\"%s\"?>\n",
792 			sqwebmail_content_charset);
793 
794 	printf("%s", linebuf);
795 }
796 
output_form(const char * formname)797 void output_form(const char *formname)
798 {
799 	FILE	*f;
800 
801 #ifdef	GZIP
802 	int	dogzip;
803 	int	pipefd[2];
804 	pid_t	pid= -1;
805 #endif
806 
807 	noimages= auth_getoptionenvint("wbnoimages");
808 
809 	f=do_open_form(formname, 1);
810 
811 	sqwebmail_formname=formname;
812 
813 	if (!f)	error("Can't open form template.");
814 
815 	/*
816 	** Except for the dummy frame window (and the tiny empty frame),
817 	** and the window containing the print preview of the message,
818 	** expire everything.
819 	*/
820 
821 	if (strcmp(formname, "index.html") && strcmp(formname, "empty.html") &&
822 		strcmp(formname, "print.html"))
823 		cginocache();
824 
825 #ifdef	GZIP
826 
827 	dogzip=0;
828 	if (strcmp(formname, "readmsg.html") == 0 ||
829 	    strcmp(formname, "folder.html") == 0 ||
830 	    strcmp(formname, "folders.html") == 0 ||
831 	    strcmp(formname, "gpg.html") == 0)
832 	{
833 	const char *p=getenv("HTTP_ACCEPT_ENCODING");
834 
835 		if (p)
836 		{
837 		char	*q=strdup(p), *r;
838 
839 			if (!q)	enomem();
840 			for (r=q; *r; r++)
841 				*r= tolower((int)(unsigned char)*r);
842 			for (r=q; (r=strtok(r, ", ")) != 0; r=0)
843 				if (strcmp(r, "gzip") == 0)
844 				{
845 					dogzip=1;
846 					if (pipe(pipefd))
847 						enomem();
848 				}
849 			free(q);
850 		}
851 	}
852 #endif
853 
854 	/* Do not send a Vary header for attachment downloads */
855 
856 	if (*cgi("download") == 0)
857 		printf("Vary: Accept-Language\n");
858 
859 #ifdef	GZIP
860 	if (dogzip)
861 		printf("Content-Encoding: gzip\n");
862 #endif
863 
864 	printf("Content-Type: text/html");
865 
866 	if (sqwebmail_content_charset)
867 		printf("; charset=%s", sqwebmail_content_charset);
868 
869 	printf("\n\n");
870 
871 #ifdef	GZIP
872 	if (dogzip)
873 	{
874 		fflush(stdout);
875 		while ((pid=fork()) == -1)
876 			sleep(5);
877 		if (pid == 0)
878 		{
879 			dup2(pipefd[0], 0);
880 			close(pipefd[0]);
881 			close(pipefd[1]);
882 			execl(GZIP, "gzip", "-c", (char *)0);
883 			fprintf(stderr,
884 			       "ERR: Cannot execute " GZIP ": %s\n",
885 			       strerror(errno));
886 			exit(1);
887 		}
888 
889 		gzip_save_fd=dup(1);
890 		dup2(pipefd[1], 1);
891 		close(pipefd[1]);
892 		close(pipefd[0]);
893 	}
894 #endif
895 	fix_xml_header(f);
896 	do_output_form_loop(f);
897 	do_close_form();
898 
899 #ifdef	GZIP
900 	if (pid > 0)
901 	{
902 	int	waitstat;
903 	pid_t	p2;
904 
905 		/* Restore original stdout */
906 
907 		fflush(stdout);
908 		dup2(gzip_save_fd, 1);
909 		close(gzip_save_fd);
910 		gzip_save_fd= -1;
911 		while ((p2=wait(&waitstat)) >= 0 && p2 != pid)
912 			;
913 	}
914 #endif
915 }
916 
917 static FILE *openinclude(const char *);
918 
919 
insert_include(const char * inc_name)920 void insert_include(const char *inc_name)
921 {
922 	FILE *ff=openinclude(inc_name);
923 	do_output_form_loop(ff);
924 	do_close_form();
925 }
926 
do_output_form_loop(FILE * f)927 static void do_output_form_loop(FILE *f)
928 {
929 	int	c, c2, c3;
930 
931 	while ((c=getc(f)) >= 0)
932 	{
933 	char	kw[64];
934 
935 		if (c != '[')
936 		{
937 			putchar(c);
938 			continue;
939 		}
940 		c=getc(f);
941 		if (c != '#')
942 		{
943 			putchar('[');
944 			ungetc(c,f);
945 			continue;
946 		}
947 		c=getc(f);
948 		if (c == '?')
949 		{
950 			c=getc(f);
951 			if (c < '0' || c > '9')
952 			{
953 				putchar('[');
954 				putchar('#');
955 				putchar('?');
956 				putchar(c);
957 				continue;
958 			}
959 			if (
960 			    ( c == '0' && nochangepass()) ||
961 			    (c == '1' && strncmp(cgi("folderdir"),
962 						 SHARED ".",
963 						 sizeof(SHARED)) == 0) ||
964 			    (c == '2' && strncmp(cgi("folderdir"),
965 						 SHARED ".",
966 						 sizeof(SHARED))) ||
967 			    (c == '4' && maildir_filter_hasmaildirfilter(".")) ||
968 			    (c == '5' && libmail_gpg_has_gpg(GPGDIR)) ||
969 			    (c == '6' && !ishttps()) ||
970 			    (c == '7' && !sqpcp_has_calendar()) ||
971 			    (c == '8' && !sqpcp_has_groupware())
972 			    )
973 			{
974 				while ((c=getc(f)) != EOF)
975 				{
976 					if (c != '[')	continue;
977 					if ( getc(f) != '#')	continue;
978 					if ( getc(f) != '?')	continue;
979 					if ( getc(f) != '#')	continue;
980 					if ( getc(f) == ']')	break;
981 				}
982 			}
983 			continue;
984 		}
985 
986 		if (c == '$')
987 		{
988 			struct var_put_buf buf;
989 
990 			buf.argp=buf.argbuf;
991 			buf.argn=sizeof(buf.argbuf)-1;
992 
993 			while ((c=getc(f)) >= 0 && c != '\n')
994 			{
995 				if (c == '#')
996 				{
997 					c=getc(f);
998 					if (c == ']')	break;
999 					ungetc(c, f);
1000 					c='#';
1001 				}
1002 
1003 				if (c == '@')
1004 				{
1005 					c=getc(f);
1006 					if (c == '@')
1007 					{
1008 						output_image(f,
1009 							     var_put_buf_func,
1010 							     &buf);
1011 						continue;
1012 					}
1013 					ungetc(c, f);
1014 					c='@';
1015 				}
1016 				var_put_buf_func(c, &buf);
1017 			}
1018 			*buf.argp=0;
1019 			addarg(buf.argbuf);
1020 			continue;
1021 		}
1022 
1023 		if (c == '@')
1024 		{
1025 			output_image(f, pass_image_through, NULL);
1026 			c=getc(f);
1027 			if (c == '#')
1028 			{
1029 				c=getc(f);
1030 				if (c == ']')
1031 					continue;
1032 			}
1033 			if (c != EOF)
1034 				ungetc(c, f);
1035 			continue;
1036 		}
1037 
1038 		if (!isalnum(c) && c != ':')
1039 		{
1040 			putchar('[');
1041 			putchar('#');
1042 			ungetc(c, f);
1043 			continue;
1044 		}
1045 		c2=0;
1046 		while (c != EOF && (isalnum(c) || c == ':' || c == '_'))
1047 		{
1048 			if (c2 < sizeof(kw)-1)
1049 				kw[c2++]=c;
1050 			c=getc(f);
1051 		}
1052 		kw[c2]=0;
1053 		c2=c;
1054 
1055 		if (c2 != '#')
1056 		{
1057 			putchar('[');
1058 			putchar('#');
1059 			printf("%s", kw);
1060 			ungetc(c2, f);
1061 			continue;
1062 		}
1063 
1064 		if ((c3=getc(f)) != ']')
1065 		{
1066 			putchar('[');
1067 			putchar('#');
1068 			printf("%s", kw);
1069 			putchar(c2);
1070 			ungetc(c3, f);
1071 			continue;
1072 		}
1073 
1074 		if (strcmp(kw, "a") == 0)
1075 		{
1076 			addressbook();
1077 		}
1078 		else if (strcmp(kw, "d") == 0)
1079 		{
1080 			const char *f=cgi("folderdir");
1081 			char *origc, *c;
1082 			const char *sep="";
1083 
1084 			origc=c=folder_fromutf7(f);
1085 
1086 			if (*c && strcmp(c, INBOX))
1087 			{
1088 				printf(" - ");
1089 
1090 				if (strcmp(c, NEWSHAREDSP) == 0 ||
1091 				    strncmp(c, NEWSHAREDSP ".",
1092 					    sizeof(NEWSHAREDSP)) == 0)
1093 				{
1094 					printf("%s", getarg("PUBLICFOLDERS"));
1095 					sep=".";
1096 				}
1097 
1098 				c=strchr(c, '.');
1099 				if (c)
1100 				{
1101 					printf(sep);
1102 					print_safe(c+1);
1103 				}
1104 			}
1105 			free(origc);
1106 		}
1107 		else if (strcmp(kw, "D") == 0)
1108 		{
1109 			const char *p=cgi("folder");
1110 			const char *q=strrchr(p, '.');
1111 
1112 				if (q)
1113 				{
1114 				char	*r=malloc(q-p+1);
1115 
1116 					if (!r)	enomem();
1117 					memcpy(r, p, q-p);
1118 					r[q-p]=0;
1119 					output_urlencoded(r);
1120 					free(r);
1121 				}
1122 		}
1123 		else if (strcmp(kw, "G") == 0)
1124 		{
1125 			output_attrencoded(login_returnaddr());
1126 		}
1127 		else if (strcmp(kw, "r") == 0)
1128 		{
1129 			output_attrencoded(cgi("redirect"));
1130 		}
1131 		else if (strcmp(kw, "s") == 0)
1132 		{
1133 			output_scriptptrget();
1134 		}
1135 		else if (strcmp(kw, "S") == 0)
1136 		{
1137 			output_loginscriptptr();
1138 		}
1139 		else if (strcmp(kw, "R") == 0)
1140 		{
1141 			output_loginscriptptr_get();
1142 		}
1143 		else if (strcmp(kw, "p") == 0)
1144 		{
1145 			output_scriptptr();
1146 		}
1147 		else if (strcmp(kw, "P") == 0)
1148 		{
1149 			output_scriptptrpostinfo();
1150 		}
1151 		else if (strcmp(kw, "f") == 0)
1152 		{
1153 			folder_contents_title();
1154 		}
1155 		else if (strcmp(kw, "F") == 0)
1156 		{
1157 			folder_contents(sqwebmail_folder, atol(cgi("pos")));
1158 		}
1159 		else if (strcmp(kw, "n") == 0)
1160 		{
1161 			folder_initnextprev(sqwebmail_folder, atol(cgi("pos")));
1162 		}
1163 		else if (strcmp(kw, "N") == 0)
1164 		{
1165 			folder_nextprev();
1166 		}
1167 		else if (strcmp(kw, "m") == 0)
1168 		{
1169 			folder_msgmove();
1170 		}
1171 		else if (strcmp(kw, "M") == 0)
1172 		{
1173 			folder_showmsg(sqwebmail_folder, atol(cgi("pos")));
1174 		}
1175 		else if (strcmp(kw, "T") == 0)
1176 		{
1177 			folder_showtransfer();
1178 		}
1179 		else if (strcmp(kw, "L") == 0)
1180 		{
1181 			folder_list();
1182 		}
1183 		else if (strcmp(kw, "l") == 0)
1184 		{
1185 			folder_list2();
1186 		}
1187 		else if (strcmp(kw, "E") == 0)
1188 		{
1189 			folder_rename_list();
1190 		}
1191 		else if (strcmp(kw, "W") == 0)
1192 		{
1193 			newmsg_init(sqwebmail_folder, cgi("pos"));
1194 		}
1195 		else if (strcmp(kw, "z") == 0)
1196 		{
1197 			pref_isdisplayfullmsg();
1198 		}
1199 		else if (strcmp(kw, "y") == 0)
1200 		{
1201 			pref_isoldest1st();
1202 		}
1203 		else if (strcmp(kw, "H") == 0)
1204 		{
1205 			pref_displayhtml();
1206 		}
1207 		else if (strcmp(kw, "FLOWEDTEXT") == 0)
1208 		{
1209 			pref_displayflowedtext();
1210 		}
1211 		else if (strcmp(kw, "NOARCHIVE") == 0)
1212 		{
1213 			pref_displaynoarchive();
1214 		}
1215 		else if (strcmp(kw, "NOAUTORENAMESENT") == 0)
1216 		{
1217 			pref_displaynoautorenamesent();
1218 		}
1219 		else if (strcmp(kw, "x") == 0)
1220 		{
1221 			pref_setprefs();
1222 		}
1223 		else if (strcmp(kw, "w") == 0)
1224 		{
1225 			pref_sortorder();
1226 		}
1227 		else if (strcmp(kw, "t") == 0)
1228 		{
1229 			pref_signature();
1230 		}
1231 		else if (strcmp(kw, "u") == 0)
1232 		{
1233 			pref_pagesize();
1234 		}
1235 		else if (strcmp(kw, "v") == 0)
1236 		{
1237 			pref_displayautopurge();
1238 		}
1239 		else if (strcmp(kw, "A") == 0)
1240 		{
1241 			attachments_head(sqwebmail_folder, cgi("pos"),
1242 				cgi("draft"));
1243 		}
1244 		else if (strcmp(kw, "ATTACHOPTS") == 0)
1245 		{
1246 			attachments_opts(cgi("draft"));
1247 		}
1248 		else if (strcmp(kw, "GPGERR") == 0)
1249 		{
1250 			sent_gpgerrtxt();
1251 		}
1252 		else if (strcmp(kw, "GPGERRRESUME") == 0)
1253 		{
1254 			sent_gpgerrresume();
1255 		}
1256 #ifdef	ISPELL
1257 		else if (strcmp(kw, "K") == 0)
1258 		{
1259 			spell_show();
1260 		}
1261 #endif
1262 #ifdef	BANNERPROG
1263 		else if (strcmp(kw, "B") == 0)
1264 		{
1265 			char banargbuf[31];
1266 			int	i=0;
1267 			int	wait_stat;
1268 			pid_t	p, p2;
1269 
1270 				if ((c=getc(f)) != '{')
1271 					ungetc(c, f);
1272 				else	while ((c=getc(f)), isalnum(c))
1273 						if (i < sizeof(banargbuf)-1)
1274 							banargbuf[i++]=c;
1275 				banargbuf[i]=0;
1276 				fflush(stdout);
1277 
1278 				if ( (p=fork()) == 0 )
1279 				{
1280 					execl(BANNERPROG, BANNERPROG,
1281 						sqwebmail_formname,
1282 						banargbuf, (char *)0);
1283 					_exit(0);
1284 				}
1285 				if (p > 0)
1286 				{
1287 					while ((p2=wait(&wait_stat)) > 0 &&
1288 						p2 != p)
1289 						;
1290 				}
1291 		}
1292 #endif
1293 		else if (strcmp(kw, "h") == 0)
1294 		{
1295 			FILE *fp=fopen(LOGINDOMAINLIST, "r");
1296 
1297 			if (fp) {
1298 				/* parse LOGINDOMAINLIST and print proper output */
1299 				print_logindomainlist(fp);
1300 				fclose(fp);
1301 			}
1302 		}
1303 		else if (strcmp(kw, "o") == 0)
1304 		{
1305 			ldaplist();
1306 		}
1307 		else if (strcmp(kw, "O") == 0)
1308 		{
1309 			doldapsearch();
1310 		}
1311 		else if (strcmp(kw, "IMAGEURL") == 0)
1312 		{
1313 			printf("%s", get_imageurl());
1314 		}
1315 		else if (strcmp(kw, "LOADMAILFILTER") == 0)
1316 		{
1317 			mailfilter_init();
1318 		}
1319 		else if (strcmp(kw, "MAILFILTERLIST") == 0)
1320 		{
1321 			mailfilter_list();
1322 		}
1323 		else if (strcmp(kw, "MAILFILTERLISTFOLDERS") == 0)
1324 		{
1325 			mailfilter_listfolders();
1326 		}
1327 		else if (strcmp(kw, "QUOTA") == 0)
1328 		{
1329 			folder_showquota();
1330 		}
1331 		else if (strcmp(kw, "NICKLIST") == 0)
1332 		{
1333 		        ab_listselect();
1334 		}
1335 		else if (strcmp(kw, "LISTPUB") == 0)
1336 		{
1337 			gpglistpub();
1338 		}
1339 		else if (strcmp(kw, "LISTSEC") == 0)
1340 		{
1341 			gpglistsec();
1342 		}
1343 		else if (strcmp(kw, "KEYIMPORT") == 0)
1344 		{
1345 			folder_keyimport(sqwebmail_folder, atol(cgi("pos")));
1346 		}
1347 		else if (strcmp(kw, "GPGCREATE") == 0)
1348 		{
1349 			gpgcreate();
1350 		}
1351 		else if (strcmp(kw, "DOGPG") == 0)
1352 		{
1353 			gpgdo();
1354 		}
1355 		else if (strcmp(kw, "ATTACHPUB") == 0)
1356 		{
1357 			gpgselectpubkey();
1358 		}
1359 		else if (strcmp(kw, "ATTACHSEC") == 0)
1360 		{
1361 			gpgselectprivkey();
1362 		}
1363 		else if (strcmp(kw, "MAILINGLISTS") == 0)
1364 		{
1365 			char *p=getmailinglists();
1366 
1367 			/* <sigh> amaya inserts a bunch of spaces that mess
1368 			** things up in Netscape.
1369 			*/
1370 
1371 			output_attrencoded(p ? p:"");
1372 			if (p)
1373 				free(p);
1374 		}
1375 		else if (strcmp(kw, "AUTORESPONSE") == 0)
1376 		{
1377 			autoresponse();
1378 		}
1379 		else if (strcmp(kw, "AUTORESPONSE_LIST") == 0)
1380 		{
1381 			autoresponselist();
1382 		}
1383 		else if (strcmp(kw, "AUTORESPONSE_PICK") == 0)
1384 		{
1385 			autoresponsepick();
1386 		}
1387 		else if (strcmp(kw, "AUTORESPONSE_DELETE") == 0)
1388 		{
1389 			autoresponsedelete();
1390 		}
1391 		else if (strcmp(kw, "SQWEBMAILCSS") == 0)
1392 		{
1393 			printf("%s/sqwebmail.css", get_imageurl());
1394 		}
1395 		else if (strcmp(kw, "timezonelist") == 0)
1396 		{
1397 			timezonelist();
1398 		}
1399 		else if (strcmp(kw, "PREFWEEK") == 0)
1400 		{
1401 			pref_displayweekstart();
1402 		}
1403 		else if (strcmp(kw, "NEWEVENT") == 0)
1404 		{
1405 			sqpcp_newevent();
1406 		}
1407 		else if (strcmp(kw, "RECURRING") == 0)
1408 		{
1409 			printf("%s", getarg("RECURRING"));
1410 		}
1411 		else if (strcmp(kw, "EVENTSTART") == 0)
1412 		{
1413 			sqpcp_eventstart();
1414 		}
1415 		else if (strcmp(kw, "EVENTEND") == 0)
1416 		{
1417 			sqpcp_eventend();
1418 		}
1419 		else if (strcmp(kw, "EVENTFROM") == 0)
1420 		{
1421 			sqpcp_eventfrom();
1422 		}
1423 		else if (strcmp(kw, "EVENTTIMES") == 0)
1424 		{
1425 			sqpcp_eventtimes();
1426 		}
1427 		else if (strcmp(kw, "EVENTPARTICIPANTS") == 0)
1428 		{
1429 			sqpcp_eventparticipants();
1430 		}
1431 		else if (strcmp(kw, "EVENTTEXT") == 0)
1432 		{
1433 			sqpcp_eventtext();
1434 		}
1435 		else if (strcmp(kw, "EVENTATTACH") == 0)
1436 		{
1437 			sqpcp_eventattach();
1438 		}
1439 		else if (strcmp(kw, "EVENTSUMMARY") == 0)
1440 		{
1441 			sqpcp_summary();
1442 		}
1443 		else if (strcmp(kw, "CALENDARTODAY") == 0)
1444 		{
1445 			sqpcp_todays_date();
1446 		}
1447 		else if (strcmp(kw, "CALENDARWEEKLYLINK") == 0)
1448 		{
1449 			sqpcp_weeklylink();
1450 		}
1451 		else if (strcmp(kw, "CALENDARMONTHLYLINK") == 0)
1452 		{
1453 			sqpcp_monthlylink();
1454 		}
1455 		else if (strcmp(kw, "CALENDARTODAYV") == 0)
1456 		{
1457 			sqpcp_todays_date_verbose();
1458 		}
1459 		else if (strcmp(kw, "CALENDARDAYVIEW") == 0)
1460 		{
1461 			sqpcp_daily_view();
1462 		}
1463 		else if (strcmp(kw, "CALENDARPREVDAY") == 0)
1464 		{
1465 			sqpcp_prevday();
1466 		}
1467 		else if (strcmp(kw, "CALENDARNEXTDAY") == 0)
1468 		{
1469 			sqpcp_nextday();
1470 		}
1471 		else if (strcmp(kw, "CALENDARWEEK") == 0)
1472 		{
1473 			sqpcp_show_cal_week();
1474 		}
1475 		else if (strcmp(kw, "CALENDARNEXTWEEK") == 0)
1476 		{
1477 			sqpcp_show_cal_nextweek();
1478 		}
1479 		else if (strcmp(kw, "CALENDARPREVWEEK") == 0)
1480 		{
1481 			sqpcp_show_cal_prevweek();
1482 		}
1483 		else if (strcmp(kw, "CALENDARWEEKVIEW") == 0)
1484 		{
1485 			sqpcp_displayweek();
1486 		}
1487 		else if (strcmp(kw, "CALENDARMONTH") == 0)
1488 		{
1489 			sqpcp_show_cal_month();
1490 		}
1491 		else if (strcmp(kw, "CALENDARNEXTMONTH") == 0)
1492 		{
1493 			sqpcp_show_cal_nextmonth();
1494 		}
1495 		else if (strcmp(kw, "CALENDARPREVMONTH") == 0)
1496 		{
1497 			sqpcp_show_cal_prevmonth();
1498 		}
1499 		else if (strcmp(kw, "CALENDARMONTHVIEW") == 0)
1500 		{
1501 			sqpcp_displaymonth();
1502 		}
1503 		else if (strcmp(kw, "EVENTDISPLAYINIT") == 0)
1504 		{
1505 			sqpcp_displayeventinit();
1506 		}
1507 		else if (strcmp(kw, "EVENTDELETEINIT") == 0)
1508 		{
1509 			sqpcp_deleteeventinit();
1510 		}
1511 		else if (strcmp(kw, "EVENTDISPLAY") == 0)
1512 		{
1513 			sqpcp_displayevent();
1514 		}
1515 		else if (strcmp(kw, "EVENTBACKLINK") == 0)
1516 		{
1517 			sqpcp_eventbacklink();
1518 		}
1519 		else if (strcmp(kw, "EVENTEDITLINK") == 0)
1520 		{
1521 			sqpcp_eventeditlink();
1522 		}
1523 		else if (strcmp(kw, "EVENTCANCELUNCANCELLINK") == 0)
1524 		{
1525 			sqpcp_eventcanceluncancellink();
1526 		}
1527 		else if (strcmp(kw, "EVENTCANCELUNCANCELLINK") == 0)
1528 		{
1529 			sqpcp_eventcanceluncancellink();
1530 		}
1531 		else if (strcmp(kw, "EVENTCANCELUNCANCELIMAGE") == 0)
1532 		{
1533 			sqpcp_eventcanceluncancelimage();
1534 		}
1535 		else if (strcmp(kw, "EVENTCANCELUNCANCELTEXT") == 0)
1536 		{
1537 			sqpcp_eventcanceluncanceltext();
1538 		}
1539 		else if (strcmp(kw, "EVENTDELETELINK") == 0)
1540 		{
1541 			sqpcp_eventdeletelink();
1542 		}
1543 		else if (strcmp(kw, "EVENTACL") == 0)
1544 		{
1545 			sqpcp_eventacl();
1546 		}
1547 		else if (strcmp(kw, "ABOOKNAMELIST") == 0)
1548 		{
1549 			ab_addrselect();
1550 		}
1551 		else if (strcmp(kw, "LISTRIGHTS") == 0)
1552 			listrights();
1553 		else if (strcmp(kw, "GETACL") == 0)
1554 			getacl();
1555 		else if (strncmp(kw, "radio:", 6) == 0)
1556 		{
1557 		const char *name=strtok(kw+6, ":");
1558 		const char *value=strtok(0, ":");
1559 
1560 			if (name && value)
1561 			{
1562 				printf("<input type=\"radio\" name=\"%s\""
1563 					" value=\"%s\"",
1564 					name, value);
1565 				if ( strcmp(cgi(name), value) == 0)
1566 					printf(" checked=\"checked\"");
1567 				printf(" />");
1568 			}
1569 		}
1570 		else if (strncmp(kw, "checkbox:", 9) == 0)
1571 		{
1572 		const char *name=strtok(kw+9, ":");
1573 		const char *cgivar=strtok(0, ":");
1574 
1575 			if (name && cgivar)
1576 			{
1577 				printf("<input type=\"checkbox\" name=\"%s\""
1578 					"%s />",
1579 					name,
1580 					*cgi(cgivar) ? " checked=\"checked\"":"");
1581 			}
1582 		}
1583 		else if (strncmp(kw, "input:", 6) == 0)
1584 		{
1585 			output_attrencoded(cgi(kw+6));
1586 		}
1587 		else if (strncmp(kw, "select:", 7) == 0)
1588 		{
1589 		const char *name=strtok(kw+7, ":");
1590 		const char *class=strtok(0, ":");
1591 		const char *size=strtok(0, ":");
1592 
1593 			printf("<select name=\"%s\"", name ? name:"");
1594 			if (class)	printf(" class=\"%s\"", class);
1595 			if (size)	printf(" size=\"%s\"", size);
1596 			printf(">");
1597 		}
1598 		else if (strncmp(kw, "option:", 7) == 0)
1599 		{
1600 		const char *name=strtok(kw+7, ":");
1601 		const char *cgivar=strtok(0, ":");
1602 		const char *cgival=strtok(0, ":");
1603 
1604 			printf("<option value=\"%s\"", name ? name:"");
1605 			if (cgivar && cgival &&
1606 				strcmp(cgi(cgivar), cgival) == 0)
1607 				printf(" selected='selected'");
1608 			printf(">");
1609 		}
1610 		else if (strcmp(kw, "endoption") == 0)
1611 			printf("</option>");
1612 		else if (strcmp(kw, "endselect") == 0)
1613 			printf("</select>");
1614 		else if (strncmp(kw, "env:", 4) == 0) {
1615 			const char *val = getenv(kw+4);
1616 			if (val) output_attrencoded(val);
1617 		}
1618 		else if (strncmp(kw, "include:", 8) == 0)
1619 		{
1620 			insert_include(kw+8);
1621 		}
1622 		else if (strcmp(kw, "endinclude") == 0)
1623 		{
1624 			break;
1625 		}
1626 	}
1627 }
1628 
1629 /* Include another template file */
1630 
openinclude(const char * p)1631 static FILE *openinclude(const char *p)
1632 {
1633 	char buffer[BUFSIZ];
1634 	FILE *f;
1635 
1636 	buffer[0]=0;
1637 	strncat(buffer, p, 100);
1638 	strcat(buffer, ".inc.html");
1639 
1640 	f=do_open_form(buffer, 0);
1641 
1642 	if (!f)
1643 		error("Can't open form template.");
1644 
1645 	while (fgets(buffer, sizeof(buffer), f))
1646 	{
1647 		const char *p=strchr(buffer, '[');
1648 
1649 		if (!p)
1650 			continue;
1651 
1652 		if (strncmp(p, "[#begininclude#]", 16) == 0)
1653 		{
1654 			break;
1655 		}
1656 	}
1657 	return (f);
1658 }
1659 
1660 
1661 /* Top level HTTP redirect without referencing a particular mailbox */
1662 
http_redirect_top(const char * app)1663 static void http_redirect_top(const char *app)
1664 {
1665 const	char *p=nonloginscriptptr();
1666 char	*buf=malloc(strlen(p)+strlen(app)+2);
1667 
1668 	if (!buf)	enomem();
1669 	strcat(strcpy(buf, p), app);
1670 	cgiredirect(buf);
1671 	free(buf);
1672 }
1673 
1674 /* HTTP redirects within a given mailbox, various formats */
1675 
http_redirect_argu(const char * fmt,unsigned long un)1676 void http_redirect_argu(const char *fmt, unsigned long un)
1677 {
1678 char	buf[MAXLONGSIZE];
1679 
1680 	sprintf(buf, "%lu", un);
1681 	http_redirect_argss(fmt, buf, "");
1682 }
1683 
http_redirect_argss(const char * fmt,const char * arg1,const char * arg2)1684 void http_redirect_argss(const char *fmt, const char *arg1, const char *arg2)
1685 {
1686 	http_redirect_argsss(fmt, arg1, arg2, "");
1687 }
1688 
http_redirect_argsss(const char * fmt,const char * arg1,const char * arg2,const char * arg3)1689 void http_redirect_argsss(const char *fmt, const char *arg1, const char *arg2,
1690 	const char *arg3)
1691 {
1692 char *base=scriptptrget();
1693 char *arg1s=cgiurlencode(arg1);
1694 char *arg2s=cgiurlencode(arg2);
1695 char *arg3s=cgiurlencode(arg3);
1696 char *q;
1697 
1698 	/* We generate a Location: redirected_url header.  The actual
1699 	** header is generated in cgiredirect, we just build it here */
1700 
1701 	q=malloc(strlen(base)+strlen(fmt)+strlen(arg1s)+strlen(arg2s)+
1702 			strlen(arg3s)+1);
1703 	if (!q)	enomem();
1704 	strcpy(q, base);
1705 	sprintf(q+strlen(q), fmt, arg1s, arg2s, arg3s);
1706 	cgiredirect(q);
1707 	free(q);
1708 	free(arg1s);
1709 	free(arg2s);
1710 	free(arg3s);
1711 	free(base);
1712 }
1713 
output_user_form(const char * formname)1714 void output_user_form(const char *formname)
1715 {
1716 char	*p;
1717 
1718 	if (!*formname || strchr(formname, '.') || strchr(formname, '/'))
1719 		error("Invalid request.");
1720 
1721 	if ((strcmp(formname, "filter") == 0
1722 	     || strcmp(formname, "autoresponse") == 0)
1723 	    && maildir_filter_hasmaildirfilter("."))
1724 		/* Script kiddies... */
1725 		formname="nofilter";
1726 
1727 	if (strcmp(formname, "filter") == 0 && *cgi("do.submitfilter"))
1728 		mailfilter_submit();
1729 
1730 	if (strcmp(formname, "gpg") == 0 && libmail_gpg_has_gpg(GPGDIR))
1731 		error("Invalid request.");
1732 
1733 	if (strcmp(formname, "gpgcreate") == 0 && libmail_gpg_has_gpg(GPGDIR))
1734 		error("Invalid request.");
1735 
1736 	if (*cgi("ldapsearch"))	/* Special voodoo for LDAP address book stuff */
1737 	{
1738 		if (ldapsearch() == 0)
1739 		{
1740 			output_form("ldapsearch.html");
1741 			return;
1742 		}
1743 	}
1744 
1745 	/*
1746 	** In order to hide the session ID in the URL of the message what
1747 	** we do is that the initial URL, that contains setcookie=1, results
1748 	** in us setting a temporary cookie that contains the session ID,
1749 	** then we return a redirect to a url which has /printmsg/ in the
1750 	** PATH_INFO, instead of the session ID.  The code in main()
1751 	** traps /printmsg/ PATH_INFO, fetches the path info from the
1752 	** cookie, and punts after resetting setcookie to 0.
1753 	*/
1754 
1755 	if (strcmp(formname, "print") == 0 && *cgi("setcookie") == '1')
1756 	{
1757 	const char *qs=getenv("QUERY_STRING");
1758 	const char *pi=getenv("PATH_INFO");
1759 	const char *nl;
1760 	char	*buf;
1761 
1762 		if (!pi)	pi="";
1763 		if (!pi)	pi="";
1764 
1765 		nl=nonloginscriptptr();
1766 
1767 		buf=malloc(strlen(nl) + sizeof("/printmsg/print?")+strlen(qs));
1768 		if (!buf)	enomem();
1769 		strcat(strcat(strcpy(buf, nl), "/printmsg/print?"), qs);
1770 		cginocache();
1771 		cgi_setcookie("sqwebmail-pi", pi);
1772 		printf("Refresh: 0; URL=%s\n", buf);
1773 		free(buf);
1774 		output_form("printredirect.html");
1775 		return;
1776 	}
1777 
1778 	if (strcmp(cgi("fromscreen"), "mailfilter") == 0)
1779 		maildir_filter_endmaildirfilter(".");	/* Remove the temp file */
1780 
1781 	if (strcmp(formname, "logout") == 0)
1782 	{
1783 		unlink(IPFILE);
1784 		http_redirect_top("");
1785 		return;
1786 	}
1787 
1788 	if (strcmp(formname, "fetch") == 0)
1789 	{
1790 		folder_download( sqwebmail_folder, atol(cgi("pos")),
1791 			cgi("mimeid") );
1792 		return;
1793 	}
1794 
1795 	if (strcmp(formname, "delmsg") == 0)
1796 	{
1797 		folder_delmsg( atol(cgi("pos")));
1798 		return;
1799 	}
1800 
1801 	if (strcmp(formname, "donewmsg") == 0)
1802 	{
1803 		newmsg_do(sqwebmail_folder);
1804 		return;
1805 	}
1806 
1807 	if (strcmp(formname, "doattach") == 0)
1808 	{
1809 		doattach(sqwebmail_folder, cgi("draft"));
1810 		return;
1811 	}
1812 
1813 	if (strcmp(formname, "folderdel") == 0)
1814 	{
1815 		folder_delmsgs(sqwebmail_folder, atol(cgi("pos")));
1816 		return;
1817 	}
1818 	if (strcmp(formname, "spellchk") == 0)
1819 	{
1820 #ifdef	ISPELL
1821 		spell_check_continue();
1822 #else
1823 		printf("Status: 404");
1824 #endif
1825 		return;
1826 	}
1827 
1828 	if (sqpcp_loggedin())
1829 	{
1830 		if (*cgi("do.neweventpreview"))
1831 		{
1832 			sqpcp_preview();
1833 			return;
1834 		}
1835 
1836 		if (*cgi("do.neweventsave"))
1837 		{
1838 			sqpcp_save();
1839 			return;
1840 		}
1841 
1842 		if (*cgi("do.neweventpostpone"))
1843 		{
1844 			sqpcp_postpone();
1845 			return;
1846 		}
1847 
1848 		if (*cgi("do.neweventdeleteattach"))
1849 		{
1850 			sqpcp_deleteattach();
1851 			return;
1852 		}
1853 
1854 		if (*cgi("do.neweventupload"))
1855 		{
1856 			sqpcp_uploadattach();
1857 			return;
1858 		}
1859 
1860 		if (*cgi("do.neweventuppubkey"))
1861 		{
1862 			sqpcp_attachpubkey();
1863 			return;
1864 		}
1865 
1866 		if (*cgi("do.neweventupprivkey"))
1867 		{
1868 			sqpcp_attachprivkey();
1869 			return;
1870 		}
1871 		if (*cgi("do.eventdelete"))
1872 		{
1873 			sqpcp_dodelete();
1874 			return;
1875 		}
1876 	}
1877 
1878 	if (strcmp(formname, "event-edit") == 0)
1879 	{
1880 		formname="folders";
1881 		if (sqpcp_loggedin())
1882 		{
1883 			formname="eventshow";	/* default */
1884 			if (sqpcp_eventedit() == 0)
1885 				formname="newevent";
1886 		}
1887 	}
1888 
1889 
1890 	if (strcmp(formname, "open-draft") == 0)
1891 	{
1892 		formname="newmsg";
1893 		if (sqpcp_has_calendar())
1894 			/* DRAFTS may contain event files */
1895 		{
1896 			const char *n=cgi("draft");
1897 			char *filename;
1898 			FILE *fp;
1899 
1900 			CHECKFILENAME(n);
1901 
1902 			filename=maildir_find(INBOX "." DRAFTS, n);
1903 
1904 			if (filename)
1905 			{
1906 				if ((fp=fopen(filename, "r")) != NULL)
1907 				{
1908 					struct rfc822hdr h;
1909 
1910 					rfc822hdr_init(&h, 8192);
1911 
1912 					while (rfc822hdr_read(&h, fp, NULL, 0)
1913 					       == 0)
1914 					{
1915 						if (strcasecmp(h.header,
1916 							       "X-Event") == 0)
1917 						{
1918 							formname="newevent";
1919 							cgi_put("draftmessage",
1920 								cgi("draft"));
1921 							break;
1922 						}
1923 					}
1924 					rfc822hdr_free(&h);
1925 					fclose(fp);
1926 				}
1927 				free(filename);
1928 			}
1929 		}
1930 	}
1931 
1932 	if (strcmp(formname, "newevent") == 0 ||
1933 	    strcmp(formname, "eventdaily") == 0 ||
1934 	    strcmp(formname, "eventweekly") == 0 ||
1935 	    strcmp(formname, "eventmonthly") == 0 ||
1936 	    strcmp(formname, "eventshow") == 0 ||
1937 	    strcmp(formname, "eventacl") == 0)
1938 	{
1939 		if (!sqpcp_has_calendar() ||
1940 		    !sqpcp_loggedin())
1941 			formname="folders";	/* Naughty boy */
1942 	}
1943 
1944 	p=malloc(strlen(formname)+6);
1945 	if (!p)	enomem();
1946 
1947 	strcat(strcpy(p, formname),".html");
1948 	output_form(p);
1949 	free(p);
1950 }
1951 
1952 
1953 extern void folder_cleanup();
1954 extern void maildir_cleanup();
1955 extern void mailfilter_cleanup();
1956 
1957 #ifdef	ISPELL
1958 extern void ispell_cleanup();
1959 #endif
1960 
cleanup()1961 void cleanup()
1962 {
1963 	sqwebmail_formname = NULL;
1964 	sqwebmail_mailboxid=0;
1965 	sqwebmail_folder=0;
1966 	sqwebmail_sessiontoken=0;
1967 	sqwebmail_content_language=0;
1968 	sqwebmail_content_locale=0;
1969 	sqwebmail_system_charset=0;
1970 	if (sys_locale_charset)
1971 		free(sys_locale_charset);
1972 	sys_locale_charset=0;
1973 	sqwebmail_content_ispelldict=0;
1974 	folder_cleanup();
1975 	maildir_cleanup();
1976 	mailfilter_cleanup();
1977 #ifdef ISPELL
1978 	ispell_cleanup();
1979 #endif
1980 
1981 #ifdef GZIP
1982 	if (gzip_save_fd >= 0)	/* Restore original stdout */
1983 	{
1984 		dup2(gzip_save_fd, 1);
1985 		close(gzip_save_fd);
1986 		gzip_save_fd= -1;
1987 	}
1988 #endif
1989 
1990 	libmail_gpg_cleanup();
1991 	freeargs();
1992 	sqpcp_close();
1993 }
1994 
1995 
1996 
catch_sig(int n)1997 static RETSIGTYPE catch_sig(int n)
1998 {
1999 	n=n;
2000 	cleanup();
2001 	maildir_cache_cancel();
2002 	exit(0);
2003 }
2004 
setlang()2005 static void setlang()
2006 {
2007 	static char *lang_buf=0;
2008 	char *p;
2009 
2010 	if (sqwebmail_content_locale && *sqwebmail_content_locale
2011 	    && (p=malloc(sizeof("LANG=")+strlen(sqwebmail_content_locale)))!=0)
2012 	{
2013 		strcat(strcpy(p, "LANG="), sqwebmail_content_locale);
2014 		putenv(p);
2015 		if (lang_buf)
2016 			free(lang_buf);
2017 		lang_buf=p;
2018 	}
2019 }
2020 
init_default_locale()2021 static void init_default_locale()
2022 {
2023 char	*templatedir=get_templatedir();
2024 char	*cl=http11_best_content_language(templatedir,
2025 			getenv("HTTP_ACCEPT_LANGUAGE"));
2026 
2027 	sqwebmail_content_language=
2028 				http11_content_language(templatedir, cl);
2029 	sqwebmail_content_locale=
2030 			http11_content_locale(templatedir, cl);
2031 	sqwebmail_content_ispelldict=
2032 			http11_content_ispelldict(templatedir, cl);
2033 	sqwebmail_content_charset=
2034 			http11_content_charset(templatedir, cl);
2035 
2036 	free(cl);
2037 #if	HAVE_LOCALE_H
2038 #if	HAVE_SETLOCALE
2039 	setlocale(LC_ALL, sqwebmail_content_locale);
2040 #if	USE_LIBCHARSET
2041 	setlocale(LC_CTYPE, sqwebmail_content_locale);
2042 	sqwebmail_system_charset = locale_charset();
2043 #elif	HAVE_LANGINFO_CODESET
2044 	setlocale(LC_CTYPE, sqwebmail_content_locale);
2045 	sqwebmail_system_charset = sys_locale_charset=strdup(nl_langinfo(CODESET));
2046 #else
2047 	sqwebmail_system_charset = NULL;
2048 #endif	/* USE_LIBCHARSET */
2049 	setlocale(LC_CTYPE, "C");
2050 	setlang();
2051 #endif
2052 #endif
2053 }
2054 
rename_sent_folder(int really)2055 void rename_sent_folder(int really)
2056 {
2057 	char buf[128];
2058 	char yyyymm[128];
2059 	const char *yyyymmp;
2060 
2061 	time_t t;
2062 	struct tm *tm;
2063 	char *pp;
2064 
2065 	if (really)
2066 		(void)maildir_create(INBOX "." SENT); /* No matter what */
2067 
2068 	time(&t);
2069 	tm=localtime(&t);
2070 	if (!tm)
2071 		return;
2072 
2073 	if (tm->tm_mon == 0)
2074 	{
2075 		tm->tm_mon=11;
2076 		--tm->tm_year;
2077 	}
2078 	else
2079 		--tm->tm_mon;
2080 
2081 	if (strftime (yyyymm, sizeof(yyyymm), "%Y%m", tm) == 0)
2082 		return;
2083 
2084 	if ((yyyymmp=read_sqconfig(".", SENTSTAMP, NULL)) != NULL &&
2085 	    strcmp(yyyymm, yyyymmp) == 0)
2086 		return;
2087 
2088 	if (strftime (buf, sizeof(buf), "." SENT ".%Y.%m-%b", tm) == 0)
2089 		return;
2090 
2091 	pp=folder_toutf7(buf);
2092 
2093 	if (really)
2094 		rename("." SENT, pp);
2095 	free(pp);
2096 	if (really)
2097 		(void)maildir_create(INBOX "." SENT);
2098 
2099 	write_sqconfig(".", SENTSTAMP, yyyymm);
2100 }
2101 
2102 static int valid_redirect();
2103 
redirect(const char * url)2104 static void redirect(const char *url)
2105 {
2106 	if (valid_redirect())
2107 	{
2108 		printf("Refresh: 0; URL=%s\n", url);
2109 		output_form("redirect.html");
2110 		return;
2111 	}
2112 
2113 	printf("Content-Type: text/plain\n\n"
2114 	       "The URL you clicked on is no longer valid.\n");
2115 	return;
2116 }
2117 
valid_redirect()2118 static int valid_redirect()
2119 {
2120 	const char *timestamp=cgi("timestamp"), *p;
2121 	unsigned long timestamp_n;
2122 	time_t timestamp_t;
2123 	time_t now;
2124 
2125 	if (sscanf(timestamp, "%lu", &timestamp_n) != 1)
2126 		return 0;
2127 
2128 	timestamp_t=(time_t)timestamp_n;
2129 	time(&now);
2130 
2131 	if (now < timestamp_t || now > timestamp_t + get_timeouthard())
2132 		return 0;
2133 
2134 	p=redirect_hash(timestamp);
2135 
2136 	if (*p == 0 || strcmp(cgi("md5"), p))
2137 		return 0;
2138 	return 1;
2139 }
2140 
2141 static void main2();
2142 
usage()2143 static void usage()
2144 {
2145 	fprintf(stderr, "sqwebmaild does not accept command arguments.\n"
2146 		"Use sqwebmaild.rc script to start sqwebmaild as a daemon.\n");
2147 	exit(1);
2148 }
2149 
call_main2(void * dummy)2150 static void call_main2(void *dummy)
2151 {
2152 	main2();
2153 	cleanup();
2154 }
2155 
main(int argc,char ** argv)2156 int main(int argc, char **argv)
2157 {
2158 	const char *prefork;
2159 	int n;
2160 
2161 	courier_authdebug_login_init();
2162 
2163 	if (argc > 1)
2164 		usage();
2165 
2166 	prefork=getenv("SQWEBMAIL_PREFORK");
2167 
2168 	n=prefork ? atoi(prefork):5;
2169 
2170 	cgi_daemon(n, SOCKFILENAME, NULL, call_main2, NULL);
2171 
2172 	return (0);
2173 }
2174 
setuidgid(uid_t u,gid_t g,const char * dir,void * dummy)2175 static int setuidgid(uid_t u, gid_t g, const char *dir, void *dummy)
2176 {
2177 	if (setgid(g) || setuid(u))
2178 	{
2179 		fprintf(stderr,
2180 			"CRIT: Cache - can't setuid/setgid to %u/%u\n",
2181 		       (unsigned)u, (unsigned)g);
2182 		return (-1);
2183 	}
2184 
2185 	if (chdir(dir))
2186 	{
2187 		fprintf(stderr,
2188 			"CRIT: Cache - can't chdir to %s: %s\n", dir, strerror(errno));
2189 		return (-1);
2190 	}
2191 	return (0);
2192 }
2193 
main2()2194 static void main2()
2195 {
2196 const char	*u;
2197 const char	*ip_addr;
2198 char	*pi;
2199 char	*pi_malloced;
2200 int	reset_cookie=0;
2201 time_t	timeouthard=get_timeouthard();
2202 
2203 
2204 #ifdef	GZIP
2205 	gzip_save_fd= -1;
2206 #endif
2207 	u=ip_addr=pi=NULL;
2208 
2209 	ip_addr=getenv("REMOTE_ADDR");
2210 
2211 #if 0
2212 	{
2213 		FILE *f;
2214 
2215 		f=fopen("/tmp/pid", "w");
2216 		fprintf(f, "%d\n", (int)getpid());
2217 		fclose(f);
2218 		sleep(10);
2219 	}
2220 #endif
2221 
2222 	/*
2223 	 * Note: if we get a signal during FastCGI processing, this means
2224 	 * means we need to terminate so that the webserver can respawn us.
2225 	 * Exception is SIGPIPE which we just ignore (this is what we get
2226 	 * if we try to write data to a client which goes away before
2227 	 * we finished sending them the reply)
2228 	 */
2229 
2230 	signal(SIGHUP, catch_sig);
2231 	signal(SIGINT, catch_sig);
2232 	signal(SIGPIPE, catch_sig);
2233 	signal(SIGTERM, catch_sig);
2234 
2235 	if (!ip_addr)	ip_addr="127.0.0.1";
2236 
2237 	umask(0077);
2238 
2239 	{
2240 		timeouthard=get_timeouthard();
2241 	}
2242 
2243 	if (maildir_cache_init(timeouthard, CACHEDIR, CACHEOWNER, authvars))
2244 	{
2245 		printf("Content-Type: text/plain\n\nmaildir_cache_init() failed\n");
2246 		fake_exit(0);
2247 	}
2248 
2249 	pi=getenv("PATH_INFO");
2250 
2251 	pi_malloced=0;
2252 	sqpcp_init();
2253 
2254 	if (pi && strncmp(pi, "/printmsg/", 10) == 0)
2255 	{
2256 		/* See comment in output_user_form */
2257 
2258 		pi_malloced=pi=cgi_cookie("sqwebmail-pi");
2259 		if (*pi_malloced == 0)
2260 		{
2261 			free(pi_malloced);
2262 			setgid(getgid());
2263 			setuid(getuid());
2264 			output_form("printnocookie.html");
2265 			return;
2266 		}
2267 		reset_cookie=1;
2268 		cgi_setcookie("sqwebmail-pi", "DELETED");
2269 	}
2270 
2271 	if (pi && strncmp(pi, "/login/", 7) == 0)
2272 	{
2273 	const char	*p;
2274 	time_t	last_time, current_time;
2275 	char	*q;
2276 	time_t	timeoutsoft=get_timeoutsoft();
2277 
2278 		/* Logging into the mailbox */
2279 
2280 		pi=strdup(pi);
2281 		if (pi_malloced)	free(pi_malloced);
2282 
2283 		if (!pi)	enomem();
2284 
2285 		(void)strtok(pi, "/");	/* Skip login */
2286 		u=strtok(NULL, "/");	/* mailboxid */
2287 		sqwebmail_sessiontoken=strtok(NULL, "/"); /* sessiontoken */
2288 		q=strtok(NULL, "/");	/* login time */
2289 		login_time=0;
2290 		while (q && *q >= '0' && *q <= '9')
2291 			login_time=login_time * 10 + (*q++ - '0');
2292 
2293 		if (maildir_cache_search(u, login_time, setuidgid, NULL)
2294 		    && prelogin(u))
2295 		{
2296 			free(pi);
2297 			error("Unable to access your mailbox, sqwebmail permissions may be wrong.");
2298 		}
2299 
2300 		time(&current_time);
2301 
2302 		/* Ok, boys and girls, time to validate the connection as
2303 		** follows */
2304 
2305 		if (	!sqwebmail_sessiontoken
2306 
2307 		/* 1. Read IPFILE.  Check that it's timestamp is current enough,
2308 		** and the session hasn't timed out.
2309 		*/
2310 
2311 			|| !(p=read_sqconfig(".", IPFILE, &last_time))
2312 
2313 /*			|| last_time > current_time	*/
2314 
2315 			|| last_time + timeouthard < current_time
2316 
2317 		/* 2. IPFILE will contain seven words - IP address, session
2318 		** token, language, locale, ispell dictionary,
2319 		** timezone, charset.  Validate both.
2320 		*/
2321 			|| !(q=strdup(p))
2322 			|| !(p=strtok(q, " "))
2323 			|| (strcmp(p, ip_addr) && strcmp(p, "none"))
2324 			|| !(p=strtok(NULL, " "))
2325 			|| strcmp(p, sqwebmail_sessiontoken)
2326 			|| !(p=strtok(NULL, " "))
2327 			|| !(sqwebmail_content_language=strdup(p))
2328 			|| !(p=strtok(NULL, " "))
2329 			|| !(sqwebmail_content_locale=strdup(p))
2330 			|| !(p=strtok(NULL, " "))
2331 			|| !(sqwebmail_content_ispelldict=strdup(p))
2332 			|| !(p=strtok(NULL, " "))
2333 			|| set_timezone(p)
2334 			|| !(p=strtok(NULL, " "))
2335 			|| !(sqwebmail_content_charset=strdup(p))
2336 
2337 		/* 3. Check the timestamp on the TIMESTAMP file.  See if the
2338 		** session has reached its soft timeout.
2339 		*/
2340 
2341 			|| !read_sqconfig(".", TIMESTAMP, &last_time)
2342 
2343 /*			|| last_time > current_time	*/
2344 
2345 			|| last_time + timeoutsoft < current_time)
2346 		{
2347 			setgid(getgid());
2348 			setuid(getuid());	/* Drop root prevs */
2349 			if (chdir("/") < 0)
2350 			{
2351 				output_form("expired.html");
2352 				return;
2353 			}
2354 			cgi_setup();
2355 			init_default_locale();
2356 			free(pi);
2357 
2358 			u=getenv("SQWEBMAIL_SHAREDMUNGENAMES");
2359 
2360 			maildir_info_munge_complex(u && *u);
2361 
2362 			if (strcmp(cgi("form"), "logout") == 0)
2363 				/* Already logged out, and the link
2364 				** had target=_parent tag.
2365 				*/
2366 			{
2367 				http_redirect_top("");
2368 				return;
2369 			}
2370 			output_form("expired.html");
2371 			return;
2372 		}
2373 		free(q);
2374 		cgiformdatatempdir("tmp");
2375 		cgi_setup();	/* Read CGI environment */
2376 		if (reset_cookie)
2377 			cgi_put("setcookie", "0");
2378 
2379 		/* Update soft timeout stamp */
2380 
2381 		write_sqconfig(".", TIMESTAMP, "");
2382 
2383 		/* We must always have the folder CGI arg */
2384 
2385 		if (!*(sqwebmail_folder=cgi("folder")))
2386 		{
2387 			init_default_locale();
2388 			output_form("expired.html");
2389 			free(pi);
2390 			return;
2391 		}
2392 
2393 		sqwebmail_mailboxid=u;
2394 
2395 		{
2396 			struct stat stat_buf;
2397 
2398 			if (stat(".", &stat_buf) < 0)
2399 			{
2400 				output_form("expired.html");
2401 				free(pi);
2402 				return;
2403 			}
2404 
2405 			sqwebmail_homedir_dev=stat_buf.st_dev;
2406 			sqwebmail_homedir_ino=stat_buf.st_ino;
2407 		}
2408 
2409 #if	HAVE_LOCALE_H
2410 #if	HAVE_SETLOCALE
2411 		setlocale(LC_ALL, sqwebmail_content_locale);
2412 #if	USE_LIBCHARSET
2413 		setlocale(LC_CTYPE, sqwebmail_content_locale);
2414 		sqwebmail_system_charset = locale_charset();
2415 #elif	HAVE_LANGINFO_CODESET
2416 		setlocale(LC_CTYPE, sqwebmail_content_locale);
2417 		sqwebmail_system_charset = sys_locale_charset
2418 			= strdup(nl_langinfo(CODESET));
2419 #else
2420 		sqwebmail_system_charset = NULL;
2421 #endif  /* USE_LIBCHARSET */
2422 		setlocale(LC_CTYPE, "C");
2423 		setlang();
2424 #endif
2425 #endif
2426 		CHECKFILENAME(sqwebmail_folder);
2427 
2428 		strcpy(sqwebmail_folder_rights, ALL_RIGHTS);
2429 		acl_computeRightsOnFolder(sqwebmail_folder,
2430 					  sqwebmail_folder_rights);
2431 
2432 		pref_init();
2433 		(void)sqpcp_loggedin();
2434 		if (auth_getoptionenvint("disableshared"))
2435 		{
2436 			maildir_acl_disabled=1;
2437 			maildir_newshared_disabled=1;
2438 		}
2439 
2440 		if (strcmp(cgi("form"), "empty"))
2441 		{
2442 			if (*cgi("refresh"))
2443 			{
2444 				printf("Refresh: %ld; URL=",
2445 				       (long)get_timeoutsoft()/2);
2446 				output_scriptptrget();
2447 				printf("&empty=1&refresh=1\n");
2448 			}
2449 		}
2450 
2451 		output_user_form(cgi("form"));
2452 		free(pi);
2453 	}
2454 	else
2455 		/* Must be one of those special forms */
2456 	{
2457 	char	*rm;
2458 	long	n;
2459 
2460 		if (pi_malloced)	free(pi_malloced);
2461 
2462 		if ((rm=getenv("REQUEST_METHOD")) == 0 ||
2463 			(strcmp(rm, "POST") == 0 &&
2464 				((rm=getenv("CONTENT_TYPE")) != 0 &&
2465 				strncasecmp(rm,"multipart/form-data;", 20)
2466 					== 0)))
2467 			emsg("multipart/formdata posts not allowed","");
2468 
2469 		/* Some additional safety checks */
2470 
2471 		rm=getenv("CONTENT_LENGTH");
2472 		n= rm ? atol(rm):0;
2473 		if (n < 0 || n > 256)	enomem();
2474 
2475 		cgi_setup();
2476 		init_default_locale();
2477 
2478 		if (*(u=trim_spaces(cgi("username"))))
2479 			/* Request to log in */
2480 		{
2481 		const char *p=cgi("password");
2482 		const char *mailboxid;
2483 		const char *u2=cgi("logindomain");
2484 		char	*ubuf=malloc(strlen(u)+strlen(u2)+2);
2485 
2486 			if (ubuf == NULL) enomem();
2487 			strcpy(ubuf, u);
2488 			if (*u2)
2489 				strcat(strcat(ubuf, "@"), u2);
2490 
2491 			maildir_cache_start();
2492 
2493 			if (*p && (mailboxid=do_login(ubuf, p, ip_addr))
2494 			    != 0)
2495 			{
2496 				char	*q;
2497 				const	char *saveip=ip_addr;
2498 				char	*tz;
2499 
2500 				sqwebmail_mailboxid=mailboxid;
2501 				sqwebmail_folder="INBOX";
2502 				sqwebmail_sessiontoken=random128();
2503 
2504 				tz=get_timezone();
2505 				if (*cgi("sameip") == 0)
2506 					saveip="none";
2507 
2508 				q=malloc(strlen(saveip)
2509 					 +strlen(sqwebmail_sessiontoken)
2510 					 +strlen(sqwebmail_content_language)
2511 					 +strlen(sqwebmail_content_ispelldict)
2512 					 +strlen(sqwebmail_content_charset)
2513 					 +strlen(tz)
2514 					 +strlen(sqwebmail_content_locale)+7);
2515 				if (!q)	enomem();
2516 				sprintf(q, "%s %s %s %s %s %s %s", saveip,
2517 					sqwebmail_sessiontoken,
2518 					sqwebmail_content_language,
2519 					sqwebmail_content_locale,
2520 					sqwebmail_content_ispelldict,
2521 					tz,
2522 					sqwebmail_content_charset);
2523 				write_sqconfig(".", IPFILE, q);
2524 				free(q);
2525 				free(tz);
2526 				time(&login_time);
2527 				{
2528 					char buf[1024];
2529 
2530 					buf[sizeof(buf)-1]=0;
2531 					if (getcwd(buf, sizeof(buf)-1) == 0)
2532 					{
2533 						fprintf(stderr,
2534 						       "CRIT: getcwd() failed: %s\n",strerror(errno));
2535 						fake_exit(1);
2536 					} /* oops */
2537 
2538 					maildir_cache_save(mailboxid,
2539 							   login_time,
2540 							   buf,
2541 							   geteuid(), getegid()
2542 							   );
2543 
2544 				}
2545 				write_sqconfig(".", TIMESTAMP, "");
2546 #if	HAVE_LOCALE_H
2547 #if	HAVE_SETLOCALE
2548 				setlocale(LC_ALL, sqwebmail_content_locale);
2549 #if	USE_LIBCHARSET
2550 				setlocale(LC_CTYPE, sqwebmail_content_locale);
2551 				sqwebmail_system_charset = locale_charset();
2552 #elif	HAVE_LANGINFO_CODESET
2553 				setlocale(LC_CTYPE, sqwebmail_content_locale);
2554 
2555 				sqwebmail_system_charset = sys_locale_charset
2556 					= strdup(nl_langinfo(CODESET));
2557 #else
2558 				sqwebmail_system_charset = NULL;
2559 #endif	/* USE_LIBCHARSET */
2560 				setlocale(LC_CTYPE, "C");
2561 				setlang();
2562 #endif
2563 #endif
2564 				pref_init();
2565 				(void)maildir_create(INBOX "." DRAFTS);
2566 
2567 				if (!pref_noautorenamesent)
2568 					(void)rename_sent_folder(1);
2569 				(void)maildir_create(INBOX "." SENT);
2570 				(void)maildir_create(INBOX "." TRASH);
2571 				maildir_autopurge();
2572 				unlink(SHAREDPATHCACHE);
2573 
2574 				sqpcp_login(ubuf, p);
2575 				maildir_acl_reset(".");
2576 
2577 				http_redirect_argss(*cgi("inpublic") ?
2578 						    "&form=folders":
2579 						    "&form=refreshfr", "", "");
2580 				free(ubuf);
2581 				return;
2582 			}
2583 			maildir_cache_cancel();
2584 
2585 			free(ubuf);
2586 			setgid(getgid());
2587 			setuid(getuid());
2588 			output_form("invalid.html");	/* Invalid login */
2589 			return;
2590 		}
2591 
2592 		setgid(getgid());
2593 		setuid(getuid());
2594 		if ( *(u=cgi("redirect")))
2595 			/* Redirection request to hide the referral tag */
2596 		{
2597 			redirect(u);
2598 		}
2599 		else if ( *cgi("noframes") == '1')
2600 			output_form("login.html");	/* Main frame */
2601 		else
2602 		if ( *cgi("empty") == '1')
2603 		{
2604 			output_form("empty.html");	/* Minor frameset */
2605 		}
2606 
2607 /*
2608 ** Apparently we can't show just SCRIPT NAME as our frameset due to some
2609 ** weird bug in Communicator which, under certain conditions, will get
2610 ** confused figuring out which page views have expired.  POSTs with URLs
2611 ** referring to SCRIPT_NAME will be replied with an expiration header, and
2612 ** Communicator will assume that index.html also has expired, forcing a
2613 ** frameset reload the next time the Communicator window is resized,
2614 ** essentially logging the user off.
2615 */
2616 
2617 		else if (*cgi("index") == '1')
2618 			output_form("index.html");	/* Frameset Window */
2619 		else
2620 		{
2621 			http_redirect_top("?index=1");
2622 		}
2623 
2624 		return;
2625 	}
2626 	return;
2627 }
2628 
2629 #ifdef	malloc
2630 
2631 #undef	malloc
2632 #undef	realloc
2633 #undef	free
2634 #undef	strdup
2635 #undef	calloc
2636 
2637 static void *allocp[1000];
2638 
2639 extern void *malloc(size_t), *realloc(void *, size_t), free(void *),
2640 	*calloc(size_t, size_t);
2641 extern char *strdup(const char *);
2642 
my_strdup(const char * c)2643 char *my_strdup(const char *c)
2644 {
2645 size_t	i;
2646 
2647 	for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2648 		if (!allocp[i])
2649 			return (allocp[i]=strdup(c));
2650 	abort();
2651 	return (0);
2652 }
2653 
my_malloc(size_t n)2654 void *my_malloc(size_t n)
2655 {
2656 size_t	i;
2657 
2658 	for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2659 		if (!allocp[i])
2660 			return (allocp[i]=malloc(n));
2661 	abort();
2662 	return (0);
2663 }
2664 
my_calloc(size_t a,size_t b)2665 void *my_calloc(size_t a, size_t b)
2666 {
2667 size_t	i;
2668 
2669 	for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2670 		if (!allocp[i])
2671 			return (allocp[i]=calloc(a,b));
2672 	abort();
2673 	return (0);
2674 }
2675 
my_realloc(void * p,size_t s)2676 void *my_realloc(void *p, size_t s)
2677 {
2678 size_t	i;
2679 
2680 	for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2681 		if (p && allocp[i] == p)
2682 		{
2683 		void	*q=realloc(p, s);
2684 
2685 			if (q)	allocp[i]=q;
2686 			return (q);
2687 		}
2688 	abort();
2689 }
2690 
my_free(void * p)2691 void my_free(void *p)
2692 {
2693 size_t i;
2694 
2695 	for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2696 		if (p && allocp[i] == p)
2697 		{
2698 			free(p);
2699 			allocp[i]=0;
2700 			return;
2701 		}
2702 	abort();
2703 }
2704 #endif
2705 
2706 /* Trim leading and trailing white spaces from string */
2707 
trim_spaces(const char * s)2708 char *trim_spaces(const char *s)
2709 {
2710 	char *p, *q;
2711 
2712 	p=strdup(s);
2713 	if (!p)
2714 		enomem();
2715 
2716 	if (*p)
2717 	{
2718 		for (q=p+strlen(p)-1; q >= p && isspace(*q); q--)
2719 			*q=0;
2720 
2721 		for (q=p; *q && isspace(*q); q++)
2722 			;
2723 		if (p != q)
2724 			p=q;
2725 	}
2726 
2727 	return (p);
2728 }
2729 
2730