   /****************************************************************
    Copyright (C) 1986-2000 by

    F6FBB - Jean-Paul ROUBELAT
    6, rue George Sand
    31120 - Roquettes - France
	jpr@f6fbb.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Parts of code have been taken from many other softwares.
    Thanks for the help.
    ****************************************************************/

#include <serv.h>

/*
 * Module MBL_READ.C
 */

#define NO_STATUS

static int mbl_rx (int);
static int read_mine (int);
static int teste_liste (bullist *);

/* Commande 'R' -> Read message */
/* Commande 'V' -> Read verbose message */

#include "aff_stat.c"

static int strfind (bullist * pbul, char *cherche)
{
	return (strmatch (ltitre (1, pbul), cherche));
}


static int teste_liste (bullist * lbul)
{
	if (lbul->numero < pvoie->recliste.debut)
		return (0);
	if (lbul->numero > pvoie->recliste.fin)
		return (0);
	if (lbul->date < pvoie->recliste.avant)
		return (0);
	if (lbul->date > pvoie->recliste.apres)
		return (0);

	if (!droits (COSYSOP))
	{
		if (strcmp (lbul->desti, "KILL") == 0)
			return (0);
		if (lbul->type == 'A')
			return (0);
		if ((lbul->status == 'K') && (pvoie->recliste.status != 'K'))
			return (0);
		if ((lbul->status == 'A') && (pvoie->recliste.status != 'A'))
			return (0);
	}

	if (*pvoie->recliste.find)
		return (strfind (lbul, pvoie->recliste.find));

	if ((pvoie->recliste.type) && (pvoie->recliste.type != lbul->type))
		return (0);
	if ((pvoie->recliste.status) && (pvoie->recliste.status != lbul->status))
		return (0);
	if ((*pvoie->recliste.exp) && (!strmatch (lbul->exped, pvoie->recliste.exp)))
		return (0);
	if ((*pvoie->recliste.dest) && (!strmatch (lbul->desti, pvoie->recliste.dest)))
		return (0);
	if (*pvoie->recliste.bbs)
	{
		if (*pvoie->recliste.bbs == '-')
		{
			if (*lbul->bbsv)
				return (0);
		}
		else
		{
			if (!strmatch (lbul->bbsv, pvoie->recliste.bbs))
				return (0);
		}
	}

	return (1);
}


static int read_mine (int mode)
{
	/* Lecture des messages personnels */

	bloc_mess *temp = tete_dir;
	int i, nouveau = 0, trouve = 0;
	unsigned indic;
	bullist pbul;
	mess_noeud *lptr;
	char s[80];
	rd_list *ptemp = NULL;

	if (isdigit (mode))
	{
		s[0] = (char) mode;
		s[1] = '\0';
		insnoeud (s, &indic);
	}
	else
	{
		if (mode == 'N')
			nouveau = 1;
		indic = pvoie->no_indic;
	}

	ouvre_dir ();

	while (temp->suiv)
		temp = temp->suiv;

	while (temp)
	{
		i = T_BLOC_MESS;
		while (i--)
		{
			lptr = &temp->st_mess[i];
			if ((lptr->noenr) && (lptr->no_indic == indic))
			{
				read_dir (lptr->noenr, &pbul);
				if ((pbul.type) && (pbul.status != 'H') && ((!nouveau) || (nouveau && (pbul.status == 'N'))))
				{
					trouve = 1;
					if (ptemp)
					{
						ptemp->suite = (rd_list *) m_alloue (sizeof (rd_list));
						ptemp = ptemp->suite;
					}
					else
						pvoie->t_read = ptemp = (rd_list *) m_alloue (sizeof (rd_list));
					ptemp->suite = NULL;
					ptemp->nmess = lptr->nmess;
					ptemp->verb = pvoie->recliste.l;
				}
			}
		}
		temp = prec_dir (temp);
	}

	ferme_dir ();

	if (!trouve)
	{
		if (nouveau)
			texte (T_MBL + 4);
		else
			texte (T_MBL + 3);
	}
	return (trouve);
}


int mbl_bloc_list (void)
{
	int retour = 0;
	bullist ligne;
	rd_list *ptemp;
	unsigned offset = pvoie->recliste.offset;
	bloc_mess *bptr = pvoie->recliste.ptemp;
	mess_noeud *mptr;

	ptemp = pvoie->t_read;
	while (ptemp)
		ptemp = ptemp->suite;

	pvoie->seq = FALSE;
	ouvre_dir ();
	while (bptr)
	{
		--offset;
		mptr = &(bptr->st_mess[offset]);
		read_dir (mptr->noenr, &ligne);
		if (ligne.numero < pvoie->recliste.debut)
			break;
		if ((mptr->noenr) && (droit_ok (&ligne, 1)) && (teste_liste (&ligne)))
		{
			if (pvoie->recliste.last-- == 0L)
				break;
			if (pvoie->temp1)
				pvoie->temp1 = 0;
			/* Entre le numero trouve en liste */
			if (ptemp)
			{
				ptemp->suite = (rd_list *) m_alloue (sizeof (rd_list));
				ptemp = ptemp->suite;
			}
			else
			{
				pvoie->t_read = ptemp = (rd_list *) m_alloue (sizeof (rd_list));
			}
			ptemp->suite = NULL;
			ptemp->nmess = ligne.numero;
			ptemp->verb = pvoie->recliste.l;
		}
		if (offset == 0)
		{
			bptr = prec_dir (bptr);
			offset = T_BLOC_MESS;
		}
		if (!(POP (no_port (voiecur))) && (trait_time > MAXTACHE))
		{
			pvoie->seq = TRUE;
			retour = 1;
			break;
		}
	}
	ferme_dir ();

	pvoie->recliste.offset = offset;
	pvoie->recliste.ptemp = bptr;

	if ((!retour) && (pvoie->t_read))
		retour = 2;
	return (retour);
}


int mbl_rx (int verbose)
{
	int error = 0;
	long no;
	int c, ok = TRUE;
	bullist *pbul;
	rd_list *ptemp = NULL;

	df ("mbl_rx", 1);
/*
   print_fonction(stdout); print_history(stdout); sleep_(10);
   for (;;);
 */
	sup_ln (indd);
	c = toupper (*indd);
	++indd;

	if ((c != ' ') && (*indd != ' ') && (*indd != '\0'))
	{
		ff ();
		return (1);
	}

	pvoie->aut_nc = 1;

	libere_tread (voiecur);
	init_recliste (voiecur);
	pvoie->recliste.l = verbose;

	switch (c)
	{

	case 'A':
		pvoie->recliste.status = 'A';
		break;
	case 'B':
		pvoie->recliste.type = 'B';
		break;
	case 'E':
		if (droits (COSYSOP))
		{
			int v;

			for (v = 0; v < NBVOIES; v++)
			{
				if ((svoie[v]->niv1 == N_MBL) && (svoie[v]->niv2 == 18))
				{
					texte (T_TRT + 0);
					ok = 0;		/* Interdit le multi-acces */

					break;
				}
			}
			if (ok)
			{
				maj_niv (N_MBL, 18, 0);
				ff ();
				return (review ());
			}
		}
		else
		{
			--indd;
			error = 1;
			ok = 4;
		}
		break;
	case 'F':
		pvoie->recliste.status = 'F';
		break;
	case 'K':
		pvoie->recliste.status = 'K';
		break;
	case 'L':
		if (teste_espace ())
		{
			if (isdigit (*indd))
				pvoie->recliste.last = lit_chiffre (0);
			else
			{
				texte (T_ERR + 3);
				ok = 0;
			}
		}
		else
		{
			/* texte(T_ERR + 2) ; */
			--indd;
			error = 1;
			ok = 4;
		}
		break;
	case 'M':
	case 'N':
		if (read_mine (c))
			ok = 2;
		else
			ok = 0;
		break;
	case 'P':
		pvoie->recliste.type = 'P';
		break;
	case 'S':
		if (teste_espace ())
			strn_cpy (19, pvoie->recliste.find, indd);
		else
		{
			/* texte(T_ERR + 2) ; */
			--indd;
			error = 1;
			ok = 4;
		}
		break;
	case 'T':
		pvoie->recliste.type = 'T';
		break;
	case 'U':
		pvoie->recliste.type = 'P';
		pvoie->recliste.status = 'N';
		break;
	case 'X':
		pvoie->recliste.status = 'X';
		break;
	case 'Y':
		pvoie->recliste.status = 'Y';
		break;
	case '$':
		pvoie->recliste.status = '$';
		break;
	case '<':
		if (teste_espace ())
		{
			strn_cpy (6, pvoie->recliste.exp, indd);
		}
		else
		{
			texte (T_ERR + 2);
			ok = 0;
		}
		break;
	case '>':
		if (teste_espace ())
		{
			strn_cpy (6, pvoie->recliste.dest, indd);
		}
		else
		{
			texte (T_ERR + 2);
			ok = 0;
		}
		break;
	case '@':
		if (teste_espace ())
		{
			strn_cpy (6, pvoie->recliste.bbs, indd);
		}
		else
		{
			/* texte(T_ERR + 2) ; */
			--indd;
			error = 1;
			ok = 4;
		}
		break;
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		if (read_mine (c))
			ok = 2;
		else
			ok = 0;
		break;
	case ' ':
		if (strchr (indd, '-'))
		{
			if (isdigit (*indd))
				pvoie->recliste.debut = lit_chiffre (1);
			else
			{
				texte (T_ERR + 3);
				ok = 0;
				break;
			}
			++indd;				/* saute le tiret */
			if (isdigit (*indd))
				pvoie->recliste.fin = lit_chiffre (1);
			if (pvoie->recliste.fin <= pvoie->recliste.debut)
				ok = 0;
		}
		else
		{
			ok = 0;
			while ((no = lit_chiffre (1)) != 0L)
			{
				if ((pbul = ch_record (NULL, no, ' ')) != NULL)
				{
					if (droit_ok (pbul, 1))
					{
						if (ptemp)
						{
							ptemp->suite = (rd_list *) m_alloue (sizeof (rd_list));
							ptemp = ptemp->suite;
						}
						else
						{
							pvoie->t_read = ptemp = (rd_list *) m_alloue (sizeof (rd_list));
						}
						ptemp->suite = NULL;
						ptemp->nmess = no;
						ptemp->verb = verbose;
						ok = 2;
					}
					else
						texte (T_ERR + 10);
				}
				else
					texte (T_ERR + 10);
					
				/* Only one message by request in POP mode */
				if (POP (no_port (voiecur)))
					break;
			}
		}
		break;
	default:
		if ((c == '\0') && (verbose))
		{
			texte (T_MBL + 8);
			ok = 0;
		}
		else
		{
			error = 1;
			--indd;
			ok = 4;
		}
		break;
	}
	switch (ok)
	{
	case 0:
		retour_mbl ();
		break;
	case 1:
		pvoie->recliste.ptemp = last_dir ();
		pvoie->recliste.offset = T_BLOC_MESS;
		pvoie->temp1 = 1;
		pvoie->sr_mem = 1;
		ch_niv3 (1);
		mbl_read (verbose);
		break;
	case 2:
		pvoie->sr_mem = 1;
		ch_niv3 (2);
		mbl_read (verbose);
		break;
	}
	ff ();
	return (error);
}

int mbl_read (int verbose)
{
	int error = 0;

	df ("mbl_read", 1);

	switch (pvoie->niv3)
	{
	case 0:
		error = mbl_rx (verbose);
		break;
	case 1:
		switch (mbl_bloc_list ())
		{
		case 0:				/* Pas de message */
			texte (T_MBL + 3);
			retour_mbl ();
		case 1:				/* Pas fini */
			break;
		case 2:				/* Termine */
			ch_niv3 (2);
			mbl_read (verbose);
			break;
		}
		break;
	case 2:
		if (mbl_mess_read () == 0)
		{
			retour_mbl ();
		}
		break;
	case 3:
		if (read_mess (1) == 0)
			ch_niv3 (2);
		break;
	default:
		fbb_error (ERR_NIVEAU, "MSG-READ", pvoie->niv3);
	}
	ff ();
	return (error);
}


static void entete_mess (bullist * ligne)
{
	*ptmes = *ligne;
	if (*(ligne->bbsv))
		sprintf (varx[0], "@%-6s  ", ligne->bbsv);
	else
		*varx[0] = '\0';
	texte (T_MBL + 35);
	texte (T_MBL + 38);
}


static void end_read_mess (void)
{
	char s[80];
	rd_list *ptemp = pvoie->t_read;

	if (ptemp)
	{
		sprintf (s, "R %ld", ptemp->nmess);
		fbb_log (voiecur, 'M', s);
		cr_cond ();
		if (POP (no_port (voiecur)))
		{
			out("\033", 1);
		}
		else	
		{
			texte (T_MBL + 33);
		}
		marque_obuf ();
		pvoie->t_read = ptemp->suite;
		m_libere (ptemp, sizeof (rd_list));
	}
}

char *pop_date(long date)
{
	char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
	char *mon[]= {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
	struct tm *sdate;
	static char cdate[40];
	
	sdate = localtime (&date);
	sprintf (cdate, "%s, %02d %s %d %02d:%02d:%02d %+03ld00",
			day[sdate->tm_wday],
			sdate->tm_mday,
			mon[sdate->tm_mon], 
			sdate->tm_year + 1900,
			sdate->tm_hour,
			sdate->tm_min,
			sdate->tm_sec,
			-timezone/3600);
	return cdate;
}

int read_mess (int verbose)
{
	int nb;
	FILE *fptr;
	char chaine[256];
	rd_list *ptemp = pvoie->t_read;

	nb = 0;
	
	if ((fptr = ouvre_mess (O_TEXT, ptemp->nmess, '\0')) != NULL)
	{
		fseek (fptr, pvoie->enrcur, 0);
		if (!verbose)
			fseek (fptr, supp_header (fptr, 1), 0);
		fflush (fptr);
		while ((nb = read (fileno (fptr), chaine, 250)) > 0)
		{
			outs (chaine, nb);
			if (!(POP (no_port (voiecur))) && (pvoie->memoc >= MAXMEM))
			{
				/*        if (!getvoie(CONSOLE]->connect) cprintf("Max atteint\r\n") ; */
				pvoie->enrcur = ftell (fptr);
				break;
			}
		}
		ferme (fptr, 45);
	}
	if (nb == 0)
		end_read_mess ();

	return (nb);
}


static void trans_header (char *ptr, char *bbsfrom, long date)
{
	static char ligne[80];

	int c;
	int champ;
	int nb;
	int len;
	int bbs;
	char rbbs[80];
	char home[41];

	ptr += 2;
	champ = 2;
	nb = 0;
	bbs = 0;

	*home = '\0';
	date = 0L;

	do
	{

		c = *ptr;

		switch (champ)
		{

		case 0:
			switch (c)
			{
			case '@':
				bbs = 1;
				champ = 3;
				nb = 0;
				break;
			case '#':
				champ = 6;
				nb = 0;
				break;
			case '$':
				champ = 7;
				nb = 0;
				break;
			case '[':
				champ = 4;
				nb = 0;
				break;
			case 'Z':
				if (*(ptr + 1) == ':')
				{
					++ptr;
					champ = 5;
					nb = 0;
				}
				break;
			default:
				if ((bbs == 0) && (isdigit (c)))
				{
					nb = 0;
					rbbs[nb++] = c;
					champ = 6;
				}
			}

		case 1:
			if (isspace (c))
				champ = 0;
			break;

		case 2:				/* Lecture de la date - Mettre la date la plus ancienne */
			if (nb <= 10)
				rbbs[nb] = c;
			if (nb == 10)
			{
				long rdate ;
				
				rbbs[11] = '\0';
				rbbs[6] = '\0';
				if ((rdate = date_to_time (rbbs)) != 0L)
					date = rdate + hour_to_time (rbbs + 7);
				champ = 1;
			}
			++nb;
			break;

		case 3:				/* Lecture du home BBS */
			if ((nb == 0) && (c == ':'))
				break;
			if ((ISGRAPH (c)) && (nb < 40))
			{
				rbbs[nb++] = c;
			}
			else
			{
				rbbs[nb] = '\0';
				strn_cpy (40, home, rbbs);
				champ = 0;
			}
			break;

		case 4:				/* Lecture du Qth */
			if ((c != ']') && (nb < 30))
			{
				rbbs[nb++] = c;
			}
			else
			{
				rbbs[nb] = '\0';
				champ = 0;
			}
			break;

		case 5:				/* Lecture du Zip Code */
			if ((ISGRAPH (c)) && (nb < 8))
			{
				rbbs[nb++] = c;
			}
			else
			{
				rbbs[nb] = '\0';
				champ = 0;
			}
			break;
		case 6:				/* Lecture du home premier numero */
			if ((nb == 0) && (c == ':'))
				break;
			if ((isdigit (c)) && (nb < 10))
			{
				rbbs[nb++] = c;
			}
			else
			{
				rbbs[nb] = '\0';
				if ((bbs == 0) && (c == '@'))
				{
					bbs = 1;
					champ = 3;
					nb = 0;
				}
				else
					champ = 0;
			}
			break;
		case 7:				/* Lecture du BID/MID */
			if ((nb == 0) && (c == ':'))
				break;
			if ((ISGRAPH (c)) && (nb < 12))
			{
				rbbs[nb++] = c;
			}
			else
			{
				rbbs[nb] = '\0';
				champ = 0;
			}
			break;

		}

		++ptr;
	}
	while (ISPRINT (c));

	len = sprintf(ligne, "Received: from %s ; %s", home, pop_date(date));
	outsln(ligne, len);

	strcpy(bbsfrom, home);
}

static char *read_headers(long date)
{
	int nb;
	FILE *fptr;
	char chaine[256];
	rd_list *ptemp = pvoie->t_read;
	static  char bbs[41];

	nb = 0;
	*bbs = '\0';
	
	if ((fptr = ouvre_mess (O_TEXT, ptemp->nmess, '\0')) != NULL)
	{
		while (fgets(chaine, sizeof(chaine), fptr))
		{
			if (strncmp("R:", chaine, 2) != 0)
				break;
			trans_header(chaine, bbs, date);
		}
		ferme (fptr, 45);
	}
	
	return bbs;
}

char *xuidl(long numero, char *callsign)
{
	int i;
	char call[10];
	static char str[50];
	
	sprintf(call, "%6s", callsign);
	for (i = 0 ; i < 6 ; i++)
		sprintf(str+i*2, "%02x", call[i] & 0xff);
	sprintf(str+i*2, "%032lx", numero);
	
	return str;
}

int mbl_mess_read (void)
{
	bullist *pbul;
	rd_list *ptemp;

	while ((ptemp = pvoie->t_read) != NULL)
	{
		/*    cprintf("Lit le %ld\r\n", ptemp->nmess) ;     */
		if ((pbul = ch_record (NULL, ptemp->nmess, 'Y')) != NULL)
		{
			if (POP (no_port (voiecur)))
			{
				int nb;
				char chaine[80];
				char name[80];
				char exped[80];
				char *reply;
				Wps *wps;

				/* Get the name from WP */				
				wps = wp_find(pbul->exped, 0);
				if ((wps) && (*wps->name) && (*wps->name != '?'))
				{
					sprintf(name, "%s (%s)", pbul->exped, wps->name);
				}
				else
				{
					strcpy(name, pbul->exped);
				}
				
				/* Dump headers and get the older BBS for return address */
				reply = read_headers(pbul->date);
				if (*reply == '\0')
					reply = mypath;
				
	/**** SHOULD BE CONFIGURABLE (BEGIN) ****/
	
				if (*pop_host)	
				{
					/*** address like f6fbb%f6fbb.fmlr.fra.eu@f6fbb.ampr.org */
					nb = sprintf(exped, "%s%%%s@%s", pbul->exped, reply, pop_host);
				}
				else
				{
					nb = sprintf(exped, "%s@%s", pbul->exped, reply);
				}
	
	/**** SHOULD BE CONFIGURABLE (END) ****/

				nb = sprintf(chaine, "Date: %s", pop_date(pbul->datesd));
				outsln (chaine, nb);
				nb = sprintf(chaine, "From: %s <%s>", name, exped);
				outsln (chaine, nb);
				nb = sprintf(chaine, "To: %s", pbul->desti);
				outsln (chaine, nb);
				if (pbul->type == 'B')
				{
					/* News */
					nb = sprintf(chaine, "Subject: [%s] %s", pbul->desti, pbul->titre);
					outsln (chaine, nb);
					nb = sprintf(chaine, "Message-ID: <%ld@%s>", pbul->numero, mycall);
					outsln (chaine, nb);
				}
				else
				{
					/* Mail */
					nb = sprintf(chaine, "Subject: %s", pbul->titre);
					outsln (chaine, nb);
					nb = sprintf(chaine, "Message-ID: <%ld@%s>", pbul->numero, mycall);
					outsln (chaine, nb);
					nb = sprintf(chaine, "X-UIDL: %s", xuidl(pbul->numero, mycall));
					outsln (chaine, nb);
				}
				cr();
			}
			else
			{
				entete_mess (pbul);
			}
			pvoie->enrcur = 0L;
			if (read_mess (ptemp->verb))
			{
				ch_niv3 (3);
				return (1);
			}
		}
		else
		{
			pvoie->t_read = ptemp->suite;
			m_libere (ptemp, sizeof (rd_list));
		}
	}
	return (0);
}


void libere_tread (int voie)
{
	rd_list *ptemp = svoie[voie]->t_read;
	rd_list *pprec;

	while ((pprec = ptemp) != NULL)
	{
		ptemp = pprec->suite;
		m_libere (pprec, sizeof (rd_list));
	}
	svoie[voie]->t_read = NULL;
}


void libere_tlist (int voie)
{
	rd_list *ptemp = svoie[voie]->t_list;
	rd_list *pprec;

	while ((pprec = ptemp) != NULL)
	{
		ptemp = pprec->suite;
		m_libere (pprec, sizeof (rd_list));
	}
	svoie[voie]->t_list = NULL;
}
 
