/****************************************************************
 * This software is Copyright (C) 1986-1998 by                  *
 *                                                              *
 * F6FBB - Jean-Paul ROUBELAT,  jpr@f6fbb.org                   *
 * 6, rue George Sand                                           *
 * 31120 - Roquettes - France                                   *
 *                                                              *
 * License to copy and use this software is granted for         *
 * non-commercial use provided that it is identified as         *
 *                                                              *
 * "FBB packet-radio BBS software by Jean-Paul ROUBELAT, F6FBB" *
 *                                                              *
 * in all material mentioning or referencing this software      *
 * or this function.                                            *
 *                                                              *
 * These notices must be retained in any copies of any part of  *
 * this documentation and/or software.                          *
 *                                                              *
 * Parts of code have been taken from many other softwares.     *
 * Thanks for the help.                                         *
 ****************************************************************/

#include <serv.h>

/*
 * Module Nø1 emulation WA7MBL
 */

static int mbl_lx (void);
static int mbl_bloc_liste (void);
static int strfind (bullist *, char *);
static int teste_liste (bullist *);
static int mess_bloc_liste (void);


static void list_mine (char);

/* Commande 'L' -> List messages */

#include "aff_stat.c"

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

static int manque_forward (bullist * lbul)
{
	int i;

	if ((*lbul->bbsv) && (lbul->status == 'N'))
	{
		for (i = 0; i < NBMASK; i++)
			if (lbul->fbbs[i])
				return (0);
		return (1);
	}
	return (0);
}


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.type) && (pvoie->recliste.type != lbul->type))
		return (0);
	if ((pvoie->recliste.status) && (pvoie->recliste.status != lbul->status))
		return (0);
	if ((pvoie->recliste.route) && (!manque_forward (lbul)))
		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.find)
		return (strfind (lbul, pvoie->recliste.find));

	if (*pvoie->recliste.bbs)
	{
		if (*pvoie->recliste.bbs == '-')
		{
			if (*lbul->bbsv)
				return (0);
		}
		else
		{
			if (!strmatch (bbs_via (lbul->bbsv), pvoie->recliste.bbs))
				return (0);
		}
	}

	return (1);
}


static int mbl_bloc_liste (void)
{
	int retour = 1;
	unsigned offset = pvoie->recliste.offset;
	bloc_mess *bptr = pvoie->recliste.ptemp;
	bullist ligne;

	pvoie->sr_mem = pvoie->seq = FALSE;

	ouvre_dir ();

	while (bptr)
	{
		if (!pvoie->reverse)
			--offset;

		if (bptr->st_mess[offset].noenr)
		{
			read_dir (bptr->st_mess[offset].noenr, &ligne);

			if (ligne.numero < pvoie->recliste.debut)
				break;
			if ((ligne.type) && (droit_ok (&ligne, 1)) && (teste_liste (&ligne)))
			{
				if (pvoie->recliste.last-- == 0L)
					break;
				if (pvoie->temp1)
				{
					pvoie->temp2 -= entete_liste ();
					pvoie->temp1 = 0;
				}
				aff_status (&ligne);
				--pvoie->temp2;
			}
		}

		if (pvoie->reverse)
		{
			if (++offset == T_BLOC_MESS)
			{
				bptr = bptr->suiv;
				offset = 0;
			}
		}
		else
		{
			if (offset == 0)
			{
				bptr = prec_dir (bptr);
				offset = T_BLOC_MESS;
			}
		}

		if (pvoie->temp2 == 0)
		{
			retour = 2;
			break;
		}

		if (pvoie->memoc >= MAXMEM)
		{
			pvoie->sr_mem = TRUE;
			retour = 0;
			break;
		}
		if (trait_time > MAXTACHE)
		{
			pvoie->seq = TRUE;
			retour = 0;
			break;
		}

	}

	ferme_dir ();

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

	if ((retour) && (pvoie->temp1))
		texte (T_MBL + 3);
	return (retour);
}


void mess_liste (int pr)
{
	int mode_list = 1;
	int verbose = 0;

	switch (pvoie->niv3)
	{

	case 0:
		pvoie->temp1 = 1;
		pvoie->temp2 = pvoie->lignes;
		ch_niv3 (1);
		break;

	case 1:
		break;

	case 2:
		while_space ();
		switch (toupper (*indd))
		{
		case 'A':
			mode_list = 0;
			retour_mbl ();
			break;
		case 'V':
			verbose = 1;
		case 'R':
			mode_list = 0;
			incindd ();
			if (isdigit (*indd))
			{
				list_read (verbose);
				pvoie->sr_mem = 1;
				if (mbl_mess_read () == 0)
				{
					pvoie->sr_mem = 0;
					texte (T_QST + 6);
				}
			}
			else
			{
				texte (T_ERR + 3);
				texte (T_QST + 6);
			}
			break;
		default:
			pvoie->temp2 = pvoie->lignes;
			ch_niv3 (1);
			break;
		}
		break;

	case 3:
		mode_list = 0;
		if (read_mess (1) == 0)
			ch_niv3 (4);
		break;

	case 4:
		mode_list = 0;
		pvoie->sr_mem = 1;
		if (mbl_mess_read () == 0)
		{
			pvoie->sr_mem = 0;
			texte (T_QST + 6);
			ch_niv3 (2);
		}
		break;

	default:
		fbb_error (ERR_NIVEAU, "MESS-LIST", pvoie->niv3);
	}
	if (mode_list)
	{
		if (pr)
		{
			pvoie->lignes = -1;
			switch (mess_bloc_liste ())
			{
			case 0:
				break;
			case 1:
				retour_mbl ();
				break;
			case 2:
				texte (T_QST + 6);
				ch_niv3 (2);
				break;
			}
		}
		else
		{
			pvoie->lignes = -1;
#if 0
			switch (mess_bloc_liste ())
			{
			case 0:
				break;
			case 1:
				retour_mbl ();
				break;
			case 2:
				ch_niv3 (1);
				break;
			}
#else
			mess_bloc_liste ();
			pvoie->sr_mem = pvoie->seq = FALSE;
			libere_tread (voiecur);
			libere_tlist (voiecur);
			pvoie->mbl = 1;
			maj_niv (N_MBL, 0, 0);
#endif
		}
	}
}

static int mess_bloc_liste (void)
{
	int retour = 1;
	rd_list *ptemp;
	bullist ligne;
	mess_noeud *mptr;

	pvoie->sr_mem = pvoie->seq = FALSE;

	ouvre_dir ();

	while ((ptemp = pvoie->t_list) != NULL)
	{
		if (pvoie->temp1)
		{
			pvoie->temp1 = 0;
			entete_liste ();
			--pvoie->temp2;
		}
		mptr = findmess (ptemp->nmess);
		if (mptr)
		{
			read_dir (mptr->noenr, &ligne);
			aff_status (&ligne);
		}
		--pvoie->temp2;
		pvoie->t_list = pvoie->t_list->suite;
		m_libere (ptemp, sizeof (rd_list));
		if (pvoie->temp2 == 0)
		{
			retour = 2;
			break;
		}
		if (pvoie->memoc >= MAXMEM)
		{
			pvoie->sr_mem = TRUE;
			retour = 0;
			break;
		}
		if (trait_time > MAXTACHE)
		{
			pvoie->seq = TRUE;
			retour = 0;
			break;
		}
	}
	ferme_dir ();
	if ((retour) && (pvoie->temp1))
		texte (T_MBL + 3);
	return (retour);
}

static void list_mine (char mode)
{
	char s[2];
	int nouveau = 0;
	unsigned num_ind;

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


void list_messages (int nouveau, unsigned num_ind, int pr)
{
	int trouve = 0;
	unsigned offset = 0;
	bloc_mess *bptr = tete_dir;
	mess_noeud *mptr;
	rd_list *ptemp = NULL;
	bullist bul;

	ouvre_dir ();
	/* pvoie->typlist = 0; */

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

	while (bptr)
	{
		offset = T_BLOC_MESS;
		while (offset--)
		{
			mptr = &(bptr->st_mess[offset]);
			if ((mptr->noenr) && (mptr->no_indic == num_ind))
			{
				read_dir (mptr->noenr, &bul);
				if (((!nouveau) || (nouveau && (bul.status == 'N')))
					&& (bul.status != 'H') && (bul.status != 'A'))
				{
					if (ptemp)
					{
						ptemp->suite = (rd_list *) m_alloue (sizeof (rd_list));
						ptemp = ptemp->suite;
					}
					else
					{
						pvoie->t_list = ptemp = (rd_list *) m_alloue (sizeof (rd_list));
					}
					ptemp->suite = NULL;
					ptemp->nmess = mptr->nmess;
					ptemp->verb = 1;
					trouve = 1;
				}
			}
		}
		bptr = prec_dir (bptr);
	}
	ferme_dir ();

	if (!trouve)
	{
		if (nouveau)
			texte (T_MBL + 4);
		else
			texte (T_MBL + 3);
		retour_mbl ();
	}
	else
	{
		maj_niv (N_MBL, 16, 0);
		mess_liste (pr);
	}
}


int mbl_lx (void)
{
	char c;
	long no, date;
	int ok = 1, premier = TRUE;
	int i;
	bloc_mess *temp;
	bullist *pbul;
	long numero;

	pvoie->reverse = 0;

	init_recliste (voiecur);

	if (!ISPRINT (*indd))
	{
		pvoie->recliste.debut = pvoie->finf.lastmes + 1;
		pvoie->l_mess = nomess;
	}
	else
	{
		sup_ln (indd);
		fbb_log (voiecur, 'M', strupr (indd - 1));
		c = *indd;
		++indd;
		switch (c)
		{

		case 'A':
			pvoie->recliste.status = 'A';
			break;

		case 'B':
			pvoie->recliste.type = 'B';
			break;

		case 'D':
			c = *indd++;
			if ((c == '<') || (c == '>'))
			{
				if (teste_espace ())
				{
					if ((date = date_to_time (indd)) == 0L)
					{
						ok = 0;
						texte (T_ERR + 3);
					}
					else
					{
						switch (c)
						{
						case '>':
							pvoie->recliste.avant = date /* + 86400L */ ;
							break;
						case '<':
							pvoie->recliste.apres = date - 86400L;
							break;
						}
					}
				}
				else
				{
					texte (T_ERR + 2);
					ok = 0;
				}
			}
			else
			{
				ok = 0;
				sprintf (varx[0], "LD%c", c);
				texte (T_ERR + 1);
			}
			break;

		case 'E':
			pvoie->recliste.route = 1;
			break;

		case 'F':
			pvoie->recliste.status = 'F';
			break;

		case 'H':
			pvoie->temp1 = 0;
			list_held ();
			ok = 0;
			break;

		case 'K':
			pvoie->recliste.status = 'K';
			break;

		case 'L':
			if (!ISPRINT (*indd))
			{
				pvoie->recliste.last = 1;
			}
			else if (teste_espace ())
			{
				if (isdigit (*indd))
					pvoie->recliste.last = lit_chiffre (0);
				else
				{
					texte (T_ERR + 3);
					ok = 0;
				}
			}
			else
			{
				texte (T_ERR + 2);
				ok = 0;
			}
			break;

		case 'M':
		case 'N':
			list_mine (c);
			ok = 2;
			break;

		case 'P':
			pvoie->recliste.type = 'P';
			break;

		case 'S':
			if (teste_espace ())
			{
				pvoie->recliste.find[0] = '*';
				strn_cpy (17, (pvoie->recliste.find) + 1, strupr (indd));
				strcat (pvoie->recliste.find, "*");
			}
			else
			{
				texte (T_ERR + 2);
				ok = 0;
			}
			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
			{
				strcpy (pvoie->recliste.bbs, "-");
			}
			break;

		case 'R':
			pvoie->reverse = 1;
		case ' ':
			teste_espace ();
			if (*indd == '\0')
			{
				pvoie->recliste.l = TRUE;
				pvoie->recliste.debut = pvoie->finf.lastmes + 1;
				pvoie->l_mess = nomess;
				break;
			}
			if (strchr (indd, '-'))
			{
				if (isdigit (*indd))
					pvoie->recliste.debut = lit_chiffre (1);
				else
				{
					texte (T_ERR + 3);
					ok = 0;
					break;
				}
				++indd;
				if (isdigit (*indd))
					pvoie->recliste.fin = lit_chiffre (1);
				if (pvoie->recliste.fin <= pvoie->recliste.debut)
					ok = 0;
			}
			else
			{
				while ((no = lit_chiffre (1)) != 0L)
				{
					if ((pbul = ch_record (NULL, no, '\0')) != NULL)
					{
						if (droit_ok (pbul, 1))
						{
							if (premier)
							{
								entete_liste ();
								premier = 0;
							}
							aff_status (pbul);
						}
					}
					else
						texte (T_ERR + 10);
				}
				if (premier)
					texte (T_MBL + 3);
				ok = 0;
			}
			break;

		default:
			if (isdigit (c))
			{
				list_mine (c);
				ok = 0;
			}
			else
			{
				/*
				   sprintf(varx[0], "L%c", c) ;
				   texte(T_ERR + 1) ;
				 */
				ok = 3;
			}
			break;
		}
	}
	if (ok == 1)
	{
		if (pvoie->reverse)
		{
			temp = tete_dir;
			numero = pvoie->recliste.debut;
			while (temp->suiv)
			{
				if (temp->suiv->st_mess[0].nmess > numero)
					break;
				temp = temp->suiv;
			}
			for (i = 0; i < T_BLOC_MESS; i++)
			{
				if (temp->st_mess[i].nmess == 0)
				{
					--i;
					break;
				}
				if (temp->st_mess[i].nmess >= numero)
					break;
			}
			if (i == T_BLOC_MESS)
				--i;
			pvoie->recliste.ptemp = temp;
			pvoie->recliste.offset = i;
		}
		else
		{
			pvoie->recliste.ptemp = last_dir ();
			pvoie->recliste.offset = T_BLOC_MESS;
		}
		pvoie->temp1 = 1;
	}
	return (ok);
}


void list_read (int verbose)
{
	long no;
	bullist *pbul;
	rd_list *ptemp = NULL;

	libere_tread (voiecur);

	while ((no = lit_chiffre (1)) != 0L)
	{
		if ((pbul = ch_record (NULL, no, 'Y')) != 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;
			}
			else
				texte (T_ERR + 10);
		}
		else
			texte (T_ERR + 10);
	}
}


int mbl_list (void)
{
	int mode_list = 1;
	int verbose = 0;
	int error = 0;

	switch (pvoie->niv3)
	{
	case 0:
		if (toupper (*indd) == 'C')
		{
			return (list_lc ());
		}

		switch (mbl_lx ())
		{
		case 0:
			retour_mbl ();
		case 2:
			mode_list = 0;
			break;
		case 1:
			pvoie->temp2 = pvoie->lignes;
			ch_niv3 (1);
			break;
		case 3:
			mode_list = 0;
			error = 1;
			--indd;
			break;
		}
		break;
	case 1:
		break;
	case 2:
		while_space ();
		switch (toupper (*indd))
		{
		case 'A':
			mode_list = 0;
			retour_mbl ();
			break;
		case 'V':
			verbose = 1;
		case 'R':
			mode_list = 0;
			incindd ();
			if (isdigit (*indd))
			{
				pvoie->aut_nc = 1;
				list_read (verbose);
				pvoie->sr_mem = 1;
				if (mbl_mess_read () == 0)
				{
					pvoie->sr_mem = 0;
					texte (T_QST + 6);
				}
			}
			else
			{
				texte (T_ERR + 3);
				texte (T_QST + 6);
			}
			break;
		default:
			pvoie->temp2 = pvoie->lignes;
			ch_niv3 (1);
			break;
		}
		break;
	case 3:
		mode_list = 0;
		pvoie->aut_nc = 1;
		if (read_mess (1) == 0)
			ch_niv3 (4);
		break;
	case 4:
		mode_list = 0;
		pvoie->aut_nc = 1;
		pvoie->sr_mem = 1;
		if (mbl_mess_read () == 0)
		{
			pvoie->sr_mem = 0;
			texte (T_QST + 6);
			ch_niv3 (2);
		}
		break;
	default:
		fbb_error (ERR_NIVEAU, "MSG-LIST", pvoie->niv3);
	}

	if (mode_list)
	{
		pvoie->lignes = -1;
		switch (mbl_bloc_liste ())
		{
		case 0:
			break;
		case 1:
			retour_mbl ();
			break;
		case 2:
			texte (T_QST + 6);
			ch_niv3 (2);
			break;
		}
	}
	return (error);
}


/* Test du password */

void mbl_passwd (void)
{
	char buffer[80];

	switch (pvoie->niv3)
	{
	case 0:
		snd_passwd (buffer);
		if (*buffer == '\0')
			retour_mbl ();
		else
		{
			outln (buffer, strlen (buffer));
			ch_niv3 (1);
		}
		break;
	case 1:
		if (tst_passwd (indd))
		{
			outln ("Ok", 2);
			change_droits (voiecur);
			sprintf (buffer, "SYS OK");
		}
		else
		{
			*pvoie->passwd = '\0';
			sprintf (buffer, "SYS FAILED");
		}
		fbb_log (voiecur, 'M', buffer);
		retour_mbl ();
		break;
	}
}


/* Commande 'S' -> Send messages */

int mbl_send (void)
{
	int error = 0;

	switch (toupper (*indd))
	{
	case 'X':
		if (!read_only ())
		{
			--indd;
			maj_niv (N_XFWD, 1, 0);
			xfwd ();
		}
		else
			retour_mbl ();
		break;
	case 'Y':
		if ((toupper (indd[1]) == 'S') && (!pvoie->read_only) && (droits (CMDSYS)))
		{
			maj_niv (N_MBL, 14, 0);
			mbl_passwd ();
		}
		else
		{
			error = 1;
			/* cmd_err(--indd) ; */
		}
		break;
	case 'R':
		if (!read_only ())
		{
			*indd = toupper (*indd);
			send_reply ();
		}
		else
			retour_mbl ();
		break;
	case 'C':
		if (!read_only ())
		{
			fbb_log (voiecur, 'S', strupr (indd));
			send_copy ();
		}
		else
			retour_mbl ();
		break;
	default:
		maj_niv (N_FORW, 0, 0);
		error = fwd ();
		break;
	}
	return (error);
}


/* Commande 'I' -> Info */

void mbl_info (void)
{
	char buffer[257];

	sprintf (buffer, "LANG\\%s.INF", nomlang + nlang * LG_LANG);
	if (!outfich (d_disque (buffer)))
		q_mark ();
}
