   /****************************************************************
    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>
#include <modem.h>

/*
 *  Module FBBdos
 */

static int execute_dos (void);
static int rx_file (char *, int);

static void copy_file (void);
static void dos_copy (void);
static void edit_label (void);
static void help_appel (char **);
static void menu_dos (void);
static void put_file (void);
static void view (void);

static int where_loop;
/*
 * F_FILTER feature
 *
 * Parameters :
 *    Callsign-SSID
 *    Temp filename
 *    Number of the calling process (Xmodem=11, YAPP=17)
 *    Number of the user's record in INF.SYS
 *
 * Return value
 *    0 : File OK, can be recorded.
 *    1 : File not OK, will be discarded.
 *
 * Comments
 *    The datas sent to stdout by F_FILTER
 *    will be redirected to the user.
 */
 
 
/* return the next argument from indd and updates the indd pointer */
char *get_nextparam(void)
{
	char *ptr;
	
	while (*indd && isspace(*indd))
		++indd;
	
	if (*indd == '"')
	{
		ptr = ++indd;
		while (*indd && (*indd != '"'))
			++indd;
		if (*indd)
			*indd++ = '\0';		
	}
	else
	{
		ptr = indd;
		while (*indd && isgraph(*indd))
			++indd;
		if (*indd)
			*indd++ = '\0';
	}
	
	return (*ptr) ? ptr : NULL ;
}

int test_temp (int voie)
{
	static int test = 1;
	int retour = 1;
	int ret;
	char temp[128];
	char s[256];


	temp_name (voie, temp);
	indd[80] = '\0';

	if (test)
	{
		char dir[80];
		char file[80];
		FILE *fptr;

		strcpy (dir, "X:\\");	/* fill string with form of response: X:\ */
		dir[0] = 'A' + getdisk ();	/* replace X with current drive letter */
		getcurdir (0, dir + 3);	/* fill rest of string with current directory */
		sprintf (file, "%s\\f_filter.%02d", dir, voiecur);

#ifdef __LINUX__
		strcpy(file, back2slash(file));
#endif
		if ((fptr = fopen (file, "wt")) == NULL)
			return (-1);

		fprintf (fptr, "#\n# Downloaded File information\n#\n");
#ifdef __LINUX__
		fprintf (fptr, "TempName = %s\n", back2slash(temp));
		fprintf (fptr, "FileName = %s\n", back2slash(pvoie->sr_fic));
#else
		fprintf (fptr, "TempName = %s\n", temp);
		fprintf (fptr, "FileName = %s\n", pvoie->sr_fic);
#endif
		fprintf (fptr, "Label = %s\n", pvoie->label);
		fprintf (fptr, "#\n");

		fclose (fptr);

		{
			char buffer[1024];
			
			*buffer = '\0';
			
#ifdef __LINUX__
			sprintf (s, "%sf_filter %s-%d %d %u %s",
					 FILTDIR,
					 pvoie->sta.indicatif.call, pvoie->sta.indicatif.num,
					 pvoie->niv1, pvoie->ncur->coord, file);
			ret = filter (s, buffer, sizeof (buffer), NULL, FILTDIR);
#else
			sprintf (s, "f_filter %s-%d %d %u %s",
					 pvoie->sta.indicatif.call, pvoie->sta.indicatif.num,
					 pvoie->niv1, pvoie->ncur->coord, file);
			ret = filter (s, buffer, sizeof (buffer), NULL, NULL);
#endif

			buffer[1023] = '\0';
			if (*buffer)
				out (buffer, strlen (buffer));
		}

		unlink (file);

		switch (ret)
		{
		case -1:
			test = 0;
			clear_outbuf (voiecur);
			break;
		case 1:
			retour = 0;
			break;
		default:
			break;
		}
	}

	return (retour);
}

int user_ok (void)
{
	if (droits (MODLABEL | SUPFIC | ACCESDOS))
		return (1);

	if (*pvoie->finf.priv)
		return (1);

	if (P_MODM (voiecur))
	{
		if (max_mod == 0)
			return (1);
		if (pvoie->finf.download > max_mod)
			return (0);
	}
	else
	{
		if (max_yapp == 0)
		{
			return (1);
		}
		if (pvoie->finf.download > max_yapp)
		{
			return (0);
		}
	}
	return (1);
}
void retour_dos (void)
{
	retour_niveau ();
	prompt (pvoie->finf.flags, pvoie->niv1);
}


char *local_path (char *chaine)
{
	int size, lg;
	static char temp[256];

	strcpy (temp, chaine);
	size = lg = strlen (temp);
	if ((lg > 2) && (temp[1] == ':'))
		size = lg - 2;
	if (size > 1)
		if (temp[lg - 1] == '\\')
			temp[lg - 1] = '\0';
	return (temp);
}


int tst_point (char *chaine)
{
	char *ptr;
	char vdisk;

	if ((voiecur != CONSOLE) &&
		(pvoie->kiss != -2) &&
		((ptr = strchr (chaine, ':')) != NULL))
	{
		--ptr;
		vdisk = toupper (*ptr) - 'A';
		if (vdisk == 15)
		{
			if (*pvoie->finf.priv == '\0')
			{
				texte (T_ERR + 29);
				return (FALSE);
			}
		}
		else if ((vdisk > 7) || (PATH[(int)vdisk][0] == '\0'))
		{
			texte (T_ERR + 29);
			return (FALSE);
		}
	}

	if (!droits (ACCESDOS))
	{
		if (strstr (chaine, ".."))
		{
			texte (T_ERR + 15);
			return (FALSE);
		}
	}
	return (TRUE);
}


#if 0
/*
 * Attend une structure tm en entree
 * Retourne le nombre de secondes depuis 1-1-1970
 */
static long date_to_second (struct tm *dat)
{
	static char Days[12] =
	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	long x;
	register int i;
	register int days;
	int hours;

	x = 24L * 60L * 60L * 3652L + timezone;		/* Convertit de 1980 a 1970 */
	i = dat->tm_year;
	if (i > 1900)
		i -= 1900;
	x += (i >> 2) * (1461L * 24L * 60L * 60L);
	x += (i & 3) * (24L * 60L * 60L * 365L);
	if (i & 3)
		x += 24L * 3600L;
	days = 0;
	i = dat->tm_mon - 1;
	while (i > 0)
	{
		i--;
		days += Days[i];
	}
	days += dat->tm_mday - 1;
	if (dat->tm_mon > 2 && (dat->tm_year & 3) == 0)
		days++;					/* bissextile */
	hours = days * 24 + dat->tm_hour;	/* Heures */
	x += hours * 3600L;
	x += 60L * dat->tm_min + dat->tm_sec;
	return (x);
}
#endif

void send_file (int type)
{
	int fin, retour;
	char *ptr;
	struct stat bufstat;

	switch (pvoie->niv3)
	{
	case 0:
		if (!user_ok ())
		{
			texte (T_ERR + 18);
			retour_dos ();
			break;
		}

		fin = 0;
		if (type)
			pvoie->lignes = -1;
		get_nextparam();
		if ((ptr = get_nextparam()) == NULL)
			fin = T_ERR + 20;
		else if (tst_point (ptr))
		{
			strcpy (pvoie->sr_fic, tot_path (ch_slash (ptr), pvoie->dos_path));
			retour = stat (pvoie->sr_fic, &bufstat);
			strcpy (pvoie->appendf, ptr);
			if ((retour == -1) || ((bufstat.st_mode & S_IFREG) == 0))
			{
				fin = T_ERR + 11;
			}
			else
			{
				pvoie->enrcur = 0L;
				pvoie->size_trans = 0L;
				pvoie->temp2 = type;
				if (senddata (0))
				{
					fin = -1;
					pvoie->finf.download += (int) (pvoie->size_trans / 1024L);
				}
				else
					ch_niv3 (1);
			}
		}
		if (fin)
		{
			if (type)
				ctrl_z ();
			if (fin > 0)
				texte (fin);
			retour_dos ();
		}
		break;
	case 1:
		if (senddata (0))
		{
			if (pvoie->temp2)
				ctrl_z ();
			pvoie->finf.download += (int) (pvoie->size_trans / 1024L);
			retour_dos ();
		}
		break;
	}

}


void put_file (void)
{
	FILE *fptr;
	obuf *msgtemp;
	char temp[128];

	if ((fptr = fopen (temp_name (voiecur, temp), "at")) != NULL)
	{
		while ((msgtemp = pvoie->msgtete) != NULL)
		{
			fwrite (msgtemp->buffer, msgtemp->nb_car, 1, fptr);
			pvoie->memoc -= msgtemp->nb_car;
			pvoie->msgtete = msgtemp->suiv;
			m_libere ((char *) msgtemp, sizeof (*msgtemp));
		}
		fclose (fptr);
	}
	libere (voiecur);
}


static int rx_file (char *ptr, int nbcar)
{
	int ncars;
	obuf *msgtemp;
	char *ptcur;

	if ((msgtemp = pvoie->msgtete) != NULL)
	{
		while (msgtemp->suiv)
			msgtemp = msgtemp->suiv;
	}
	else
	{
		msgtemp = (obuf *) m_alloue (sizeof (obuf));
		pvoie->msgtete = msgtemp;
		msgtemp->nb_car = msgtemp->no_car = 0;
		msgtemp->suiv = NULL;
	}
	ncars = msgtemp->nb_car;
	ptcur = msgtemp->buffer + ncars;
	while (nbcar--)
	{
		if (*ptr == '\32')
		{
			msgtemp->nb_car = ncars;
			put_file ();
			ltoa (pvoie->tailm, varx[0], 10);
			texte (T_DOS + 5);
			return (FALSE);
		}
		++pvoie->tailm;
		if (*ptr == '\r')
		{
			++pvoie->tailm;
			*ptr = '\n';
		}
		++pvoie->memoc;
		*ptcur++ = *ptr++;
		if (++ncars == 250)
		{
			msgtemp->nb_car = ncars;
			msgtemp->suiv = (obuf *) m_alloue (sizeof (obuf));
			msgtemp = msgtemp->suiv;
			msgtemp->nb_car = msgtemp->no_car = ncars = 0;
			msgtemp->suiv = NULL;
			ptcur = msgtemp->buffer;
		}
	}
	msgtemp->nb_car = ncars;
	if (pvoie->memoc > MAXMEM)
		put_file ();
	return (TRUE);
}


void receive_file (void)
{
	char *ptr;
	struct stat bufstat;

	switch (pvoie->niv3)
	{
	case 0:
		if (read_only ())
		{
			retour_dos ();
			break;
		}

		get_nextparam();
		if ((ptr = get_nextparam()) == NULL)
		{
			texte (T_ERR + 20);
			retour_dos ();
			break;
		}
		if ((!tst_point (ptr)) || (!aut_ecr (ch_slash (ptr), 1)))
		{
			retour_dos ();
			break;
		}
		entete_saisie ();
		pvoie->tailm = 0L;
		n_cpy (40, pvoie->appendf, ptr);
		strcpy (pvoie->sr_fic, tot_path (ch_slash (pvoie->appendf), pvoie->dos_path));
		if (stat (pvoie->sr_fic, &bufstat) == -1)
		{
			del_temp (voiecur);
			/* unlink(pvoie->sr_fic) ; */
			pvoie->xferok = 0;
			texte (T_YAP + 3);
			maj_niv (9, 3, 2);
		}
		else
		{
			texte (T_ERR + 23);
			retour_dos ();
		}
		break;
	case 1:
		if (rx_file (indd, nb_trait) == 0)
		{
			pvoie->xferok = 1;
			if (test_temp (voiecur))
			{
				rename_temp (voiecur, pvoie->sr_fic);
				wr_dir (pvoie->sr_fic, pvoie->sta.indicatif.call);
			}
			retour_dos ();
		}
		break;
	case 2:
		new_label ();
		texte (T_DOS + 6);
		maj_niv (9, 3, 1);
		break;
	}
}


void dos_copy (void)
{
	struct stat bufstat;
	int fd_orig, fd_dest;
	long nb_oct;
	Rlabel rlabel;
	FILE *fptr;
	char *ptri, *ptro, *ptr;
	char orig[80];
	int r;

	get_nextparam();

	if ((ptri = get_nextparam()) == NULL)
	{
		texte (T_ERR + 20);
		return;
	}

	if ((ptro = get_nextparam()) == NULL)
	{
		texte (T_ERR + 21);
		return;
	}

	if (strcmpi (ptri, ptro) == 0)
	{
		texte (T_ERR + 23);
		return;
	}

	if (!tst_point (ptri))
		return;
	if (!tst_point (ptro))
		return;

	strcpy (orig, tot_path (ch_slash (ptri), pvoie->dos_path));

	stat (orig, &bufstat);
	strcpy (pvoie->appendf, ptri);

	if ((bufstat.st_mode & S_IFREG) == 0)
	{
		texte (T_ERR + 11);
		return;
	}

	if ((fd_orig = open (orig, O_RDONLY | O_BINARY)) == EOF)
	{
		texte (T_ERR + 11);
		return;
	}

	if (!aut_ecr (ch_slash (ptro), 1))
	{
		close (fd_orig);
		return;
	}

	strcpy (pvoie->appendf, ptro);
	strcpy (pvoie->sr_fic, tot_path (ch_slash (ptro), pvoie->dos_path));

	r = stat (pvoie->sr_fic, &bufstat);
	if ((r == 0 && (bufstat.st_mode & S_IFREG) == 0) || errno != ENOENT)
	{
		texte (T_ERR + 11);
		return;
	}

	if ((fd_dest = open (pvoie->sr_fic, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE)) == EOF)
	{
		texte (T_ERR + 30);
		close (fd_orig);
		return;
	}

	nb_oct = copy_fic (fd_orig, fd_dest, NULL);

	close (fd_orig);
	close (fd_dest);
	wr_dir (pvoie->sr_fic, pvoie->sta.indicatif.call);

	*rlabel.label = '\0';

	ptr = vir_path(orig);
	fptr = NULL;

	if ((ptr) && ((fptr = fopen (d_disque ("YAPPLBL.DAT"), "rb")) != NULL))
	{
		while (fread (&rlabel, sizeof (Rlabel), 1, fptr))
		{
			if (strcmp (ptr, rlabel.nomfic) == 0)
			{
				fclose (fptr);
				fptr = NULL;
				w_label (pvoie->sr_fic, rlabel.label);
				break;
			}
		}
	}

	if (fptr)
		fclose (fptr);

	ltoa (nb_oct, varx[0], 10);
	texte (T_DOS + 7);
	return;
}


void copy_file (void)
{
	if (!read_only ())
		dos_copy ();
	prompt_dos ();
}


void del_file (void)
{
	char *ptr;

	if (!read_only ())
	{
		get_nextparam();
		if ((ptr = get_nextparam()) == NULL)
		{
			texte (T_ERR + 20);
		}
		else
		{
			if (tst_point (ptr))
			{
				if (aut_ecr (ch_slash (ptr), 1))
				{
					strcpy (pvoie->appendf, ptr);
					if (unlink (tot_path (ptr, pvoie->dos_path)) == 0)
						texte (T_DOS + 10);
					else
						texte (T_ERR + 11);
				}
			}
		}
	}
	retour_dos ();
}


static void edit_label (void)
{
	char *ptr;

	switch (pvoie->niv3)
	{
	case 0:
		if (droits (MODLABEL))
		{
			struct stat st;
			
			get_nextparam();
			if ((ptr = get_nextparam()) == NULL)
			{
				texte (T_ERR + 20);
				retour_dos ();
				break;
			}
			
			if (!tst_point (ptr) || !aut_ecr (ptr, 0))
			{
				retour_dos ();
				break;
			}

			n_cpy (40, pvoie->appendf, ptr);
			strcpy (pvoie->sr_fic, tot_path (ch_slash (pvoie->appendf), pvoie->dos_path));

			if (stat (pvoie->sr_fic, &st) == -1)
			{
				texte (T_ERR + 11);
				retour_dos ();
				break;
			}

			texte (T_YAP + 3);
			ch_niv3 (1);
		}
		else
		{
			texte (T_ERR + 1);
			retour_dos ();
		}
		break;

	case 1:
		while ((*indd) && (!ISPRINT (*indd)))
			++indd;
		if (ISGRAPH (*indd))
		{
			w_label (pvoie->sr_fic, sup_ln (indd));
			cr();
			dir_yapp(pvoie->appendf);
		}
		retour_dos ();
		break;
	}
}


void help_appel (char *appel[])
{
	char s[80];
	int i = 0;

	texte (T_DOS + 8);
	texte (T_DOS + 9);
	while (1)
	{
		if (*appel[i] == '\0')
			break;
		sprintf (s, "%-10s", appel[i]);
		outs (s, strlen (s));
		if ((++i % 6) == 0)
			outs ("\n", 1);
	}
	outs ("\n\n", 2);
}


#ifdef __WINDOWS__
static int execute_dos (void)
{
	char buf[80];
	char cmd[256];
	int disk;
	int i;
	int ret;
	char cur_dir[MAXPATH];
	char fbbdos_dir[MAXPATH];

	while (isalnum (*indd))
		++indd;
	while_space ();

	if (*indd)
	{
		/* recupere disque et repertoire courants */
		disk = getdisk ();
		strcpy (cur_dir, "X:\\");
		cur_dir[0] = 'A' + disk;
		getcurdir (0, cur_dir + 3);

		strcpy (fbbdos_dir, tot_path ("", pvoie->dos_path));

		if ((i = strlen (fbbdos_dir)) > 3)
			fbbdos_dir[i - 1] = '\0';

		operationnel = 2;

		{
			char deroute[80];

			wsprintf (deroute, "%sexecute.$$$", MBINDIR);
			ret = call_nbdos (&indd, 1, REPORT_MODE, deroute, fbbdos_dir, NULL);
			if (ret != -1)
				outfichs (deroute);
			unlink (deroute);
		}

		operationnel = 1;

		if (ret == -1)
			texte (T_ERR + 8);
		else if (ret != 0)
		{
			texte (T_ERR + 8);
			wsprintf (buf, "Errorlevel = %d", ret);
			outln (buf, strlen (buf));
		}
	}
	else
	{
		texte (T_ERR + 20);
	}

	prompt_dos ();
	return (1);
}

#endif

#ifdef __LINUX__
static int execute_dos(void)
{
  char buf[256];
  int ret;

  /* run a task under linux. This task is blocking ... */

  /* Skip DOS command */
  while (isalnum (*indd))
    ++indd;
  while_space ();

  operationnel = 2;

  {
    char deroute[80];
    char fbbdos_dir[256];
    char *ptr;
    int i;

    strcpy (fbbdos_dir, tot_path ("", pvoie->dos_path));
    if ((i = strlen (fbbdos_dir)) > 3)
		fbbdos_dir[i - 1] = '\0';

    sprintf(deroute, "%sexecute.xxx", MBINDIR);

    ptr = indd;

    /* Look for a semi-column */

    while (*ptr)
    {
      if (*ptr == ';')
         *ptr = ' ';
      ptr++;
    }

    ret = call_nbdos (&indd, 1, REPORT_MODE, deroute, fbbdos_dir, NULL);

    if (ret != -1)
      outfichs (deroute);
    unlink (deroute);

  }

  operationnel = 1;

	if (ret == -1)
		texte (T_ERR + 8);
	else if (ret != 0)
	{
		texte (T_ERR + 8);
		sprintf (buf, "Errorlevel = %d", ret);
		outln (buf, strlen (buf));
	}

  prompt_dos ();
  return(1);
}
#endif

#ifdef __FBBDOS__
static int execute_dos (void)
{
	int retour = 1;
	static char slash_c[] = "/C";
	char *arg[20];
	char *ptr;
	char log[80];
	int i = 0;
	int disk;
	int ofst;
	int duplic, oldstdout, oldstderr;
	char deroute[80];
	char cur_dir[MAXPATH];
	char fbbdos_dir[MAXPATH];

	sprintf (deroute, "%s\\EXECUTE.$$$", getcwd (log, 80));

	strtok (indd, " ");

	arg[i++] = getenv ("COMSPEC");
	arg[i++] = slash_c;
	while ((arg[i] = strtok (NULL, " ")) != NULL)
		++i;

	if (i == 2)
	{
		retour = -1;
		texte (T_ERR + 20);
	}

	else
	{
		ofst = 2;
		ptr = strrchr (arg[2], '.');
		if (ptr)
		{
			if (strcmp (strupr (ptr + 1), "BAT") == 0)
				ofst = 0;
		}

		deb_io ();

		/* redirige stdout et stderr sur le fichier EXECUTE.$$$ */
		duplic = open (deroute, O_CREAT | O_RDWR, S_IWRITE | S_IREAD);
		oldstdout = dup (1);
		oldstderr = dup (2);
		dup2 (duplic, 1);
		dup2 (duplic, 2);
		close (duplic);

		/* recupere disque et repertoire courants */
		disk = getdisk ();
		strcpy (cur_dir, "X:\\");
		cur_dir[0] = 'A' + disk;
		getcurdir (0, cur_dir + 3);

		strcpy (fbbdos_dir, tot_path ("", pvoie->dos_path));
		setdisk (fbbdos_dir[0] - 'A');

		if ((i = strlen (fbbdos_dir)) > 3)
			fbbdos_dir[i - 1] = '\0';
		chdir (fbbdos_dir);

		operationnel = 2;

		break_ok ();
		retour = spawnvp (P_WAIT, arg[ofst], arg + ofst);
		if (retour == -1)
		{
			ofst = 0;
			retour = spawnvp (P_WAIT, arg[ofst], arg + ofst);
		}
		break_stop ();
		operationnel = 1;

		/* remet disque et repertoire courants */
		setdisk (disk);
		chdir (cur_dir);

		/* Supprime les redirections */
		dup2 (oldstdout, 1);
		dup2 (oldstderr, 2);
		close (oldstdout);
		close (oldstderr);

		fin_io ();
		outfich (deroute);
		unlink (deroute);
		if (retour == -1)
			texte (T_ERR + 8);
		else if (retour != 0)
		{
			texte (T_ERR + 8);
			sprintf (log, "Errorlevel = %d", retour);
			outln (log, strlen (log));
		}
	}

	prompt_dos ();
	return (retour);
}

#endif

static void view (void)
{
	char *ptr;
	char temp[256];

	get_nextparam();
	ptr = get_nextparam();
	if ((ptr) && (strchr (ptr, '/') == NULL))
	{
#ifdef __LINUX__
		{
			static char *fbb_view = "fbb_view";
			char *vptr = getenv("FBB_VIEW");

			if (vptr == NULL)
				vptr = fbb_view;
			sprintf (temp, "DOS %s %s", vptr, back2slash(ptr));
		}
#else
		sprintf (temp, "DOS FV %s", ptr);
#endif
		indd = temp;
		maj_niv (9, 99, 0);
		execute_dos ();
		cr ();
	}
	else
	{
		texte (T_ERR + 20);
		prompt_dos ();
	}
}


static int where (int lg, char *path, char *pattern)
{
	struct ffblk ffblk;
	char rech[80];
	char temp[128];
	int done = 1;
	int premier = 1;
	int retour = 0;

	strcpy (rech, path);
#ifdef __LINUX__
	strcat (rech, "*");
#else
	strcat (rech, "*.*");
#endif

	++where_loop;

	done = findfirst (rech, &ffblk, FA_DIREC);
	while (!done)
	{
		if (*ffblk.ff_name != '.')
		{
			if (ffblk.ff_attrib & FA_DIREC)
			{
				strcpy (temp, path);
				strcat (temp, ffblk.ff_name);
				strcat (temp, "\\");
				if ((strncmp(temp+1, ":\\PROC\\", 7) != 0) && (where_loop < 16))
				{
					if (where (lg, temp, pattern))
						retour = 1;
				}
				premier = 1;
			}
			else
			{
				if (strmatch (ffblk.ff_name, pattern))
				{
					if (premier)
					{
						char v;

						if (pvoie->vdisk == 8)
							v = 'P';
						else
							v = 'A' + pvoie->vdisk;
						sprintf (temp, "%c:%s :", v, path + lg);
						outln (temp, strlen (temp));
						premier = 0;
					}
					*varx[4] = *varx[5] = *varx[6] = *varx[7] = '\0';
					sprintf (varx[0], "      %-13s", ffblk.ff_name);
					var_cpy (2, dir_date (ffblk.ff_fdate));
					*varx[3] = '\0';
					if ((ffblk.ff_attrib & FA_DIREC) != 0)
					{
						var_cpy (1, "<DIR> ");
					}
					else
					{
						sprintf (varx[1], "%6ld", ffblk.ff_fsize);
					}
					texte (T_DOS + 3);
					retour = 1;
					if (pvoie->memoc >= MAXMEM)
						break;
				}
			}
		}
		done = findnext (&ffblk);
	}

	--where_loop;

	return (retour);
}


static void where_file (void)
{
	int lg;
	int retour = 0;
	char *ptr;

	get_nextparam();
	pvoie->noenr_menu = 0L;

	ptr = get_nextparam();

	if (ptr == NULL)
	{
		texte (T_ERR + 20);
		retour_dos ();
		return;
	}

	if (tst_point (ptr))
	{
		char cur_dir[80];
		int sav_vdisk = pvoie->vdisk;

		for (pvoie->vdisk = 0; pvoie->vdisk < 9; ++pvoie->vdisk)
		{
			if (*PATH[pvoie->vdisk] == '\0')
				continue;

			if ((pvoie->vdisk == 8) && (*pvoie->finf.priv == '\0'))
				continue;

			/* strcpy (cur_dir, tot_path ("\0", "\\")); */
			strcpy (cur_dir, PATH[pvoie->vdisk]);
			lg = strlen (cur_dir);

			where_loop = 0;
			if (where (lg - 1, cur_dir, ptr))
				retour = 1;
		}
		pvoie->vdisk = sav_vdisk;
	}
	if (pvoie->memoc >= MAXMEM)
		outln ("....", 4);
	else if (!retour)
		texte (T_DOS + 2);
	retour_dos ();
}


void menu_dos (void)
{
	int i, error = 0;
	int vdisk;

	char *iptr, *optr, commande[80];
	static char *appel[] =
	{
		"HELP", "?", "O",
		"DIR", "EDIT", "GET", "PUT", "CD", "MD", "MKDIR",
		"COPY", "DEL", "RD", "RMDIR", "TYPE", "DU", "YGET", "YPUT",
		"XGET", "XPUT", "LIST", "VIEW", "NEW", "LABEL", "WHERE",
		"X1GET", "ZGET", "ZPUT", "BGET", "BPUT",
		"EXIT", "QUIT", "F", "B", "\0"
	};
	char com[80];
	char temp[80];

	limite_commande ();
	while (*indd && (!ISGRAPH (*indd)))
		indd++;
	strn_cpy (70, com, indd);
	sup_ln (indd);

	if (*indd == '\0')
	{
		prompt_dos ();
		return;
	}

	if (strncmp (com, "PRIV", 4) == 0)
	{
		fbb_log (voiecur, 'D', com);
		if (*pvoie->finf.priv)
		{
			pvoie->vdisk = 8;
			strcpy (pvoie->dos_path, "\\");
		}
		else
			texte (T_ERR + 29);
		prompt_dos ();
		return;
	}

	if ((droits (EXEDOS)) && (strncmp (com, "DOS", 3) == 0))
	{
		fbb_log (voiecur, 'D', com);
		maj_niv (9, 99, 0);
		execute_dos ();
		return;
	}

	if ((com[1] == ':') && (!ISGRAPH (com[2])))
	{
#ifdef __LINUX__
	  if (voiecur == CONSOLE)
		 {
			static char *txt="Cannot select a virtual disk in console mode";
			outln(txt, strlen(txt));
			prompt_dos ();
			return;
		 }
#endif
		vdisk = toupper (com[0]) - 'A';
		if (vdisk == 15)
		{
			vdisk = 8;
		}
		strcat (com, "\\");
		if ((voiecur == CONSOLE) && (is_dir (com)))
		{
			pvoie->vdisk = vdisk;
			strcpy (pvoie->dos_path, "\\");
		}
		else if ((voiecur != CONSOLE) && (vdisk < 8) && (*PATH[vdisk]))
		{
			pvoie->vdisk = vdisk;
			strcpy (pvoie->dos_path, "\\");
		}
		else if ((vdisk == 8) && (*pvoie->finf.priv))
		{
			pvoie->vdisk = vdisk;
			strcpy (pvoie->dos_path, "\\");
		}
		else
			texte (T_ERR + 29);
		prompt_dos ();
		return;
	}

	if ((strncmp (com, "HELP", 4) == 0) || (*com == '?') || (*com == 'H'))
	{
		if (*com == '?')
			++indd;
		else
		{
			while (ISGRAPH (*indd))
				++indd;
		}
		while_space ();
		if (*indd == '\0')
			*--indd = '?';
		if (!out_help (indd))
			help_appel (appel);
		*indd = '\0';
	}

	if ((strncmp (com, "CD", 2) == 0) && (ISGRAPH (*(com + 2))))
	{
		sprintf (temp, "CD %s", com + 2);
		indd = temp;
	}

	if (*indd)
	{
		iptr = indd;
		optr = commande;
		while (ISGRAPH (*iptr))
		{
			*optr = (islower(*iptr)) ? toupper(*iptr) : *iptr;
			iptr++;
			optr++;
		}
		*optr = '\0';
		if (*commande == 'O')
			commande[1] = '\0';

		i = 0;
		while (1)
		{
			optr = commande;
			var_cpy (0, optr);
			if (*appel[i] == '\0')
			{
				texte (T_ERR + 1);
				prompt_dos ();
				return;
			}
			if (strncmp (appel[i], optr, 3) == 0)
				break;
			++i;
		}

		pvoie->temp1 = N_DOS;

		switch (i)
		{
		case 0:
		case 1:				/* help_appel(appel) ; */
			break;
		case 2:
			indd = com + 1;
			mbl_options ();
			retour_dos ();
			break;
		case 3:
			maj_niv (9, 1, 0);
			dir ();
			break;
		case 4:
			maj_niv (9, 9, 0);
			edit ();
			break;
		case 5:
			maj_niv (9, 2, 0);
			send_file (1);
			break;
		case 6:
			if (!is_room ())
			{
				outln ("*** Disk full !", 15);
				error = 4;
				break;
			}
			maj_niv (9, 3, 0);
			receive_file ();
			break;
		case 7:
			maj_niv (9, 4, 0);
			change_dir ();
			break;
		case 8:
		case 9:
			maj_niv (9, 5, 0);
			make_dir ();
			break;
		case 10:
			if (!is_room ())
			{
				outln ("*** Disk full !", 15);
				error = 4;
				break;
			}
			maj_niv (9, 6, 0);
			copy_file ();
			break;
		case 11:
			maj_niv (9, 7, 0);
			del_file ();
			break;
		case 12:
		case 13:
			maj_niv (9, 8, 0);
			remove_dir ();
			break;
		case 14:
			maj_niv (9, 2, 0);
			send_file (0);
			break;
		case 15:
			du ();
			break;
		case 16:
			if (!user_ok ())
			{
				error = 3;
			}
			else
			{
				if (P_MODM (voiecur))
				{
					var_cpy (0, "YMODEM");
					maj_niv (N_MOD, 4, XS_INIT);
					pvoie->type_yapp = 2;
					xmodem ();
				}
				else
				{
					indd += 3;
					*indd = 'D';
					maj_niv (N_YAPP, 0, 0);
					menu_yapp ();
				}
			}
			break;
		case 17:
			if (!is_room ())
			{
				outln ("*** Disk full !", 15);
				error = 4;
				break;
			}
			if (P_MODM (voiecur))
			{
#if defined(__WINDOWS__) || defined(__LINUX__)
				var_cpy (0, "YMODEM");
				maj_niv (N_MOD, 4, XR_INIT);
				pvoie->type_yapp = 2;
				xmodem ();
#else
				var_cpy (0, "YMODEM");
				pvoie->type_yapp = 2;
				error = 2;
#endif
			}
			else
			{
				indd += 3;
				*indd = 'U';
				maj_niv (N_YAPP, 0, 0);
				menu_yapp ();
			}
			break;
		case 18:
			var_cpy (0, "XMODEM");
			if (P_MODM (voiecur))
			{
				if (!user_ok ())
					error = 3;
				else
				{
					maj_niv (N_MOD, 4, XS_INIT);
					pvoie->type_yapp = 0;
					xmodem ();
				}
			}
			else
				error = 2;
			break;
		case 19:
			if (!is_room ())
			{
				outln ("*** Disk full !", 15);
				error = 4;
				break;
			}
			var_cpy (0, "XMODEM");
			if (P_MODM (voiecur))
			{
				maj_niv (N_MOD, 4, XR_INIT);
				pvoie->type_yapp = 0;
				xmodem ();
			}
			else
				error = 2;
			break;
		case 20:
			maj_niv (9, 10, 0);
			list ();
			break;
		case 21:
			maj_niv (9, 11, 0);
			view ();
			break;
		case 22:
			maj_niv (9, 12, 0);
			dir_new ();
			break;

		case 23:
			maj_niv (9, 14, 0);
			edit_label ();
			break;

		case 24:
			maj_niv (9, 16, 0);
			where_file ();
			break;

		case 25:
			var_cpy (0, "1K-XMODEM");
			if (P_MODM (voiecur))
			{
				if (!user_ok ())
					error = 3;
				else
				{
					maj_niv (N_MOD, 4, XS_INIT);
					pvoie->type_yapp = 1;
					xmodem ();
				}
			}
			else
				error = 2;
			break;
		case 26:
			var_cpy (0, "ZMODEM");
			if (P_MODM (voiecur))
			{
				if (!user_ok ())
					error = 3;
				else
				{
					maj_niv (N_MOD, 4, XS_INIT);
					pvoie->type_yapp = 3;
					xmodem ();
				}
			}
			else
				error = 2;
			break;
		case 27:
			if (!is_room ())
			{
				outln ("*** Disk full !", 15);
				error = 4;
				break;
			}
			var_cpy (0, "ZMODEM");
			if ((P_MODM (voiecur)) && ((BIOS (no_port (voiecur)) == P_WINDOWS) || (BIOS (no_port (voiecur)) == P_LINUX)))
			{
				if (!user_ok ())
					error = 3;
				else
				{
					maj_niv (N_MOD, 4, XR_INIT);
					pvoie->type_yapp = 3;
					xmodem ();
				}
			}
			else
				error = 2;
			break;
		case 28:
			if (!user_ok ())
			{
				error = 3;
			}
			else
			{
				maj_niv (N_BIN, 0, 0);
				bin_transfer ();
			}
			break;
		case 29:
			if (!is_room ())
			{
				outln ("*** Disk full !", 15);
				error = 4;
				break;
			}
			maj_niv (N_BIN, 0, 4);
			bin_transfer ();
			break;
		case 30:
		case 31:
		case 32:
			error = 1;
			retour_mbl ();
			break;
		case 33:
			indd = com + 1;
			if (bye ())
			{
				error = 1;
				maj_niv (N_MENU, 0, 0);
				sortie ();
			}
			break;
		default:
			error = 1;
			retour_mbl ();
			break;
		}

		switch (error)
		{

		case 2:
			texte (T_YAP + 2);
			prompt_dos ();
			break;

		case 3:
			texte (T_ERR + 18);
			prompt_dos ();
			break;

		case 4:
			prompt_dos ();
			break;

		case 0:
			fbb_log (voiecur, 'D', com);
			break;
		}
	}
	else
		prompt_dos ();
}


void dos (void)
{
	switch (pvoie->niv2)
	{
	case 0:
		menu_dos ();
		break;
	case 1:
		dir ();
		break;
	case 2:
		send_file (0);
		break;
	case 3:
		receive_file ();
		break;
	case 4:
		change_dir ();
		break;
	case 5:
		make_dir ();
		break;
	case 6:
		copy_file ();
		break;
	case 7:
		del_file ();
		break;
	case 8:
		remove_dir ();
		break;
	case 9:
		edit ();
		break;
	case 10:
		list ();
		break;
	case 11:
		view ();
		break;
	case 12:
		dir_new ();
		break;
	case 14:
		edit_label ();
		break;
	case 15:
		bin_transfer ();
		break;
	case 16:
		where_file ();
		break;
	case 99:
		execute_dos ();
		break;
	default:
		fbb_error (ERR_NIVEAU, "FBBDOS", pvoie->niv2);
		break;
	}
}
