#include "global.h"
#ifdef DELEGATE
#include "ctype.h"
#include "commands.h"
#ifndef MSDOS
#include <time.h>
#endif
#include "mailbox.h"
#include "files.h"
#include "delegate.h"


#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: delegate.c,v 1.18 1997/08/19 01:19:22 root Exp $";
#endif

static void send_delegate_log (char *name);
static int read_delegate (struct delegate *del, const char *to);


int
delegate(fp,from, to)
FILE *fp;
const char *from;
const char *to;
{
struct delegate del;
char subject[256], realfrom[128];
long startat;
time_t t;
FILE *reply, *msg = NULLFILE;
char buf[1024];
int notified = 0;

	strncpy (subject, "Re: ", 256);
	parseheader (fp, realfrom, &subject[4], NULLCHAR, NULLCHAR, buf, &startat);
	t = time ((time_t *)0);
	if (!read_delegate (&del, to))
		return (1);
	if ((del.date && (t > del.date)) || (t < del.start))
		return (1);
	
	log(-1, "Delegating message to '%s' from '%s'", to, from);
	sprintf (buf, "%s/%s.del", Mailspool, to);
	reply = fopen (buf, READ_TEXT);
	if (reply)	{
		while (!feof(reply))	{
			(void) fgets (buf, 1020, reply);
			if (feof(reply))
				continue;
			if (strstr (buf,realfrom))	{
				notified = 1;
				break;
			}
		}
		(void) fclose (reply);
	}

	sprintf (buf, "%s/%s.del", Mailspool, to);
	reply = fopen (buf, APPEND_TEXT);
	if (reply)	{
		fprintf (reply, "From: '%s' on %s", realfrom, ptime(&t));
		(void) fclose (reply);
	}

	kwait (NULL);
	if (del.notify)	{
		if (!notified)	{
			reply = tmpfile();
			if (reply != NULLFILE)	{
				fprintf (reply, "Your mail to user %s@%s is being managed in their absence.\n",
					to, Hostname);
				if (del.hold)
					fprintf (reply, "Mail is being held at %s till %s's return.\n", Hostname, to);
				if (del.forward)
					fprintf (reply, "A copy of your message has been forwarded to '%s'\nat the request of %s during this absence.\n",
						del.forward, to);
				if (del.index != -1)	{
					fprintf (reply, "\n***** A message from '%s' *****\n", to);
					msg = fopen (DelegateFile, READ_TEXT);
					if (msg)	{
						fseek (msg, del.index, SEEK_SET);
						while (!feof(msg))	{
							(void) fgets (buf, 1020, msg);
							if (feof(msg))
								continue;
							if (*buf == '[')
								break;
							fputs (buf, reply);
						}
						(void) fclose (msg);
					}
					sprintf(buf,"%s/%s.sig",Signature,to);
					if((msg = fopen(buf,READ_TEXT)) != NULLFILE)		{
						while(fgets(buf,1020,msg) != NULLCHAR)	{
							kwait (NULL);		/* just to be nice to others */
							fputs(buf,reply);
						}
						(void) fclose (msg);
					}
				}
				rewind(reply);
				(void) rdaemon (reply, NULLCHAR, to, realfrom, subject, 'P', 0);
				(void) fclose(reply);
				log(-1, "Sending delegation notify message to '%s'", realfrom);
			}
		} else
			log(-1, "Skipping delegation notify message to '%s'", realfrom);
	}
	if (del.forward)	{
		fseek (fp, startat, SEEK_SET);
		strcat (subject, " (delegated)");
		(void) rdaemon (fp, NULLCHAR, from, del.forward, &subject[4], 'P', 0);
	}
	return (del.hold);
}

void
setup_delegate (m)
struct mbx *m;
{
char buf[1024], lasttime[30];
struct delegate del;
FILE *fpout, *fpin;
time_t t = (time_t)0;

	tputs ("Setting up user forwarding delegation options\n\n");
	tflush();
	sprintf (buf, "%s/delegate.hlp", Helpdir);
	(void) DisplayFile (buf, m->user);

	del.hold = 0;
	del.date = (size_t)0;
	del.forward = NULLCHAR;
	del.notify = 0;
	
	tputs ("Hold a copy of all messages received (*y/n) ?\n");
	if (mbxrecvline(m) == -1)
		goto done;

	if (tolower (*m->line) != 'n')
		del.hold = 1;

	tputs ("Forward a copy of all messages received to another person (y/*n) ?\n");
	if (mbxrecvline(m) == -1)
		goto done;

	if (tolower (*m->line) != 'y')
		del.forward = NULLCHAR;
	else	{
		tputs ("Forward to which user ?\n");
		if (mbxrecvline(m) != -1)
			del.forward = strdup (m->line);
	}

	tputs ("Notify sender of your absence (*y/n) ?\n");
	if (mbxrecvline(m) == -1)
		goto done;

	if (tolower (*m->line) != 'n')	{
		del.notify = 1;
		tputs ("Now you can enter a personal message to attach to notifications...\n");
		m->stype = 'M';
		(void) dombupload(0, (char **)0, (void *)m);
		m->stype = 'D';
	}


	del.start = t = time((time_t *)0);

	tputs ("How many days before we start delegation (<CR> for start now) ?\n");
	if (mbxrecvline(m) == -1)
		goto done;

	if (*m->line)	{
		del.start = atoi(m->line);
		if (del.start)	{
			del.start *= 86400;
			del.start += t;
		} else
			del.start = t;
	}

	tputs ("How many days before we terminate delegation (<CR> for no end date) ?\n");
	if (mbxrecvline(m) == -1)
		goto done;

	if (*m->line)	{
		del.date = atoi(m->line);
		if (del.date)	{
			del.date *= 86400;
			del.date += t;
		}
	}

	fpout = fopen (DelegateFile, APPEND_TEXT);
	if (fpout)	{
		if (del.date)
			strncpy (lasttime, ptime(&del.date), 30);
		else
			strncpy (lasttime, "No ending date set\n", 30);
		fprintf (fpout, "[%s]\n:hold o%s:\n:forward %s:\n:begin %lu: %s:end %lu: %s:notify o%s:\n",
			m->name, (del.hold) ? "n" : "ff",
			(del.forward) ? del.forward : "", (unsigned long) del.start, ptime(&del.start),
			(unsigned long) del.date, lasttime, (del.notify) ? "n" : "ff");
		if (del.notify)	{
			sprintf (buf, "%s/%s.del", Signature, m->name);
			fpin = fopen (buf, READ_TEXT);
			if (fpin)	{
				while (!feof(fpin))	{
					(void) fgets (buf, 1020, fpin);
					if (feof(fpin))
						continue;
					fputs (buf, fpout);
				}
				(void) fclose (fpin);
			}
		}
		(void) fclose (fpout);
	}
	tputs ("Delegation setup complete!\n\n");
/*	display_delegation (m->name);	*/
done:
	if (del.forward)
		free (del.forward);
}


void
display_delegation (to)
char *to;
{
struct delegate del;

	if (!read_delegate (&del, to))	{
		tprintf ("No delegation information on file at %s\n", Hostname);
		return;
	}
	tprintf ("Your mail w%s be held for you...\nYour mail w%s be forwarded to %s...\n",
		(del.hold) ? "ill" : "on't", (del.forward) ? "ill" : "on't",
		(del.forward) ? del.forward : "anyone");
	tprintf ("Senders w%s be notified of your absence...\n",
		(del.notify) ? "ill" : "on't");
	tprintf ("This delegation starts on %s", ptime(&del.start));
	tprintf ("This delegation w%s terminate automatically",
		(del.date) ? "ill" : "on't");
	if (del.date)
		tprintf (" on %s", ptime(&del.date));
	else
		tputs ("\n");
	if (del.forward)
		free (del.forward);
}



static void
send_delegate_log (name)
char *name;
{
FILE *fpout;
char buf[1024];
time_t t;

	t = time ((time_t *)0);
	sprintf (buf, "%s/%s.del", Mailspool, name);
	fpout = fopen (buf, UPDATE_TEXT);
	if (fpout)	{
		fseek (fpout, 0, SEEK_END);
		fprintf (fpout, "\nLog completed: %s", ptime(&t));
		rewind (fpout);
		(void) rdaemon (fpout, NULLCHAR, NULLCHAR, name, "Delegation log", 'P', 0);
		(void) fclose (fpout);
	}
	unlink (buf);
}


void
clear_delegate (m)
struct mbx *m;
{
FILE *fpout, *fpin;
char buf[1024];
int intheentry = 0;

	sprintf (buf, "%s.bak", DelegateFile);
	(void) rename (DelegateFile, buf);
	fpin = fopen (buf, READ_TEXT);
	if (fpin)	{
		fpout = fopen(DelegateFile, WRITE_TEXT);
		if (fpout)	{
			while (!feof(fpin))	{
				(void) fgets (buf, 1020, fpin);
				if (feof(fpin))
					continue;
				if (*buf == '[')	{
					if (!strncmp(m->name, &buf[1], strlen(m->name)) && buf[strlen(m->name) + 1] == ']')
						intheentry = 1;
					else
						intheentry = 0;
				}
				if (!intheentry)
					fputs (buf, fpout);
			}
			(void) fclose (fpout);
		}
		(void) fclose (fpin);
		send_delegate_log (m->name);
	}
}


static int
read_delegate (del, to)
struct delegate *del;
const char *to;
{
FILE *fpin;
char buf[1024];
int intheentry = 0;
char *cp = NULLCHAR;
long lasttell = 0;
int foundit = 0;

	del->hold = del->notify = 0;
	del->date = (time_t)0;
	del->index = 0L;
	del->forward = NULLCHAR;

	fpin = fopen (DelegateFile, READ_TEXT);
	if (fpin)	{
		while (!feof(fpin))	{
			lasttell = ftell(fpin);
			(void) fgets (buf, 1020, fpin);
			if (feof(fpin))
				continue;

			if (*buf == '[')	{
				if (to && !strncmp(to, &buf[1], strlen(to)) && buf[strlen(to) + 1] == ']')	{
					intheentry = 1;
					foundit = 1;
				} else	{
					intheentry = 0;
					if (foundit)	{
						del->index = -1;
						break;
					}
				}
				continue;
			}
			if (intheentry)	{
				if (*buf != ':')	{
					del->index = lasttell;
					break;
				}
				if (!strncmp (&buf[1], "hold", 4))
					del->hold = (buf[7] == 'n');
				if (!strncmp (&buf[1], "notify", 6))
					del->notify = (buf[9] == 'n');
				if (!strncmp (&buf[1], "end", 3))
					del->date = atol(&buf[5]);
				if (!strncmp (&buf[1], "begin", 5))
					del->start = atol(&buf[7]);
				if (!strncmp (&buf[1], "forward", 7))	{
					cp = strchr(&buf[1], ':');
					if (cp)
						*cp = 0;
					if (buf[9])
						del->forward = strdup(&buf[9]);
				}
			}
		}
		(void) fclose (fpin);
	}
	return (foundit);
}


void
purge_delegate ()
{
FILE *fpin, *fpout;
char buf[1024], name[50];
char *cp = NULLCHAR;
long lasttell = 0, entrybegins = 0;
time_t t, date;
int keep, firstline;

	sprintf (buf, "%s.bak", DelegateFile);
	unlink (buf);
	(void) rename (DelegateFile, buf);
	t = time((time_t *)0);
	fpin = fopen (buf, READ_TEXT);
	if (fpin == NULLFILE)
		return;
	fpout = fopen(DelegateFile, WRITE_TEXT);
	if (fpout)	{
		while (!feof(fpin))	{
			/* We are here at the beginning of an entry "[name]" */
			entrybegins = ftell(fpin);
			keep = 0;
			(void) fgets (buf, 1020, fpin);
			if (feof(fpin))
				continue;
			/* save the name line */
			strncpy (name, buf, 49);

			while (!feof(fpin))	{
				(void) fgets (buf, 1020, fpin);
				if (feof(fpin))
					continue;

				if (*buf != ':')
					/* if we got here, "end" was missing, drop it */
					break;
				if (!strncmp (&buf[1], "end", 3))	{
					date = atol(&buf[5]);
					if (!date || date > t)
						keep = 1;
					break;
				}
			}

			/* We now know the beginning and whether to expire it */
			clearerr (fpin);	/* just in case */
			fseek (fpin, entrybegins, SEEK_SET);
			firstline = 1;
			while (!feof(fpin))	{
				lasttell = ftell(fpin);
				(void) fgets (buf, 1020, fpin);
				if (feof(fpin))
					continue;
				if (!firstline && *buf == '[')	{
					fseek (fpin, lasttell, SEEK_SET);
					break;
				}
				if (keep)
					fputs (buf, fpout);
				firstline = 0;
			}
			if (!keep)	{
				cp = strchr (name, ']');
				if (cp)
					*cp = 0;
				send_delegate_log (&name[1]);
			}
		}
		(void) fclose (fpout);
	}
	(void) fclose (fpin);
}


#endif /* DELEGATE */
