#include "dtmf.h"
#include "Images.hex"

extern __far struct Custom custom;

UBYTE   vers[] = "$VER: DualTone Multi Frequency V2.2";

char dirProg[50];
struct WBStartup *WBenchMsg;

struct coordonnee
{
	long    LastRecord;
	long    NextRecord;
	char    nom[STRGADGCAR];
	char    prenom[STRGADGCAR];
	char    adresse1[STRGADGCAR];
	char    adresse2[STRGADGCAR];
	char    codepost[STRGADGCOD];
	char    ville[STRGADGCAR];
	char    pays[STRGADGCAR];
	char    telephone1[STRGADGTEL];
	char    telephone2[STRGADGTEL];
	char    fax[STRGADGTEL];
	char    note1[STRGADGCAR];
	char    note2[STRGADGCAR];
};

struct Gadget IconGadget =
{
	(struct Gadget *) NULL,
	153,
	0,
	30,
	10,
	GFLG_GADGHCOMP | GFLG_GADGIMAGE,
	GACT_IMMEDIATE | GACT_RELVERIFY,
	GTYP_BOOLGADGET,
	(APTR) NULL,
	(APTR) NULL,
	(struct IntuiText *) NULL,
	(ULONG) NULL,
	(APTR) NULL,
	0,
	(APTR) NULL
};

struct NewWindow IconWindow =
{
	550,
	0,
	50,
	10,
	0,
	1,
	NULL,
	SMART_REFRESH | WINDOWDRAG,
	(struct Gadget *) NULL,
	(struct Image *) NULL,
	(UBYTE *) "DTMF",
	(struct Screen *) NULL,
	(struct Bitmap *) NULL,
	0,
	0,
	0,
	0,
	WBENCHSCREEN
};

UBYTE   frequency[2][4] =
{
	{FREQRAN1, FREQRAN2, FREQRAN3, FREQRAN4},
	{FREQCOL1, FREQCOL2, FREQCOL3, FREQCOL4}};

UBYTE   periode[2][4] =
{
	{127, 135, 138, 125},
	{133, 132, 136, 135}};

UBYTE   Tonalite[16][2] =
{
	{3, 1},			//  0
	 {0, 0},		//  1
	 {0, 1},		//  2
	 {0, 2},		//  3
	 {1, 0},		//  4
	 {1, 1},		//  5
	 {1, 2},		//  6
	 {2, 0},		//  7
	 {2, 1},		//  8
	 {2, 2},		//  9
	 {3, 0},		//  *
	 {3, 2},		//  #
	 {0, 3},		//  A
	 {1, 3},		//  B
	 {2, 3},		//  C
	 {3, 3}};		//  D

__chip BYTE DualTone[2][4][44];

int     longTone[2][4];

/*
 * Pour une generation de tonalite parfaite, l'impulsion bifrequence
 * doit durer au moins 40 ms, pour un silence au moins egal a 40 ms egalement.
 * La frequence suivante doit arriver dans un delai de 10 a 20 secondes.
 */

struct timeval timePulse =
{
	0,
	100000
};

struct timeval timeSpace =
{
	0,
	75000

};

struct timeval timePause =
{
	0,
	150000

};

struct Screen *pubScreen;
struct DrawInfo *PubDrawInfo;
APTR   *vi;

char    ASCString[MAXNUM + 1];
char    RexxTelChaine[MAXNUM + 1];
char    Undo[50];

char    Touche[] =
{"0123456789*#ABCD:"},
        prefChannel;

BYTE    Num = 17,
        composeNom,
        GUI = 1;

char    RxCmd[20],
        RxArg1[20],
        RxArg2[20],
        RxArg3[20],
        RxArg4[20],
        RxArg5[20],
        RxArg6[20],
        RxArg7[20],
        RxArg8[20],
        RxArg9[20],
        RxArg10[20],
        RxArg11[20],
        RxArg12[20];

char   *Command[] =
{"COMPOSE", "RECOMPOSE", "AJOUTEFICH", "UNKNOW"};

int     connue,
        FileWindowNotClosed = 1;

ULONG   angle1,
        angle2;

USHORT  HeightScreenFont,
        WidthScreenFont;

WORD    winRepLeft = 250,
        winRepTop = 25,
        winClavLeft = 50,
        winClavTop = 25;

struct IOAudio *allocIOB;
struct timerequest *tr;
BYTE    allocationMap[] =
{LEFT0F | LEFT1F,
 RIGHT0F | RIGHT1F};
BYTE    allocationMapLeft[] =
{LEFT0F | LEFT1F};
BYTE    allocationMapRight[] =
{RIGHT0F | RIGHT1F};

BOOL	FromWB;
void    CalcFreq(void);
void    Compose(BYTE);
int     Recompose(BYTE *);
int     wbain(struct WBStartup *);
void    About(struct Screen *);
void    CloseFileWindow(void);
void    wait_for_timer(struct timerequest *, struct timeval *);
void    CheckToolTypes(char *);
int     wbmain(struct WBStartup *);
int     main(int, char **);

/*****************************************************************************************
 *****************************************************************************************/

int
wbmain(struct WBStartup *wbs)
{
	return (main(0, (char **) wbs));
}

/*****************************************************************************************
 *****************************************************************************************/

int
main(int argc, char **argv)
{
	int i, j, notclosed = 1;
	ULONG signals, Class;
	UWORD Code;
	APTR Address;
	struct IntuiMessage *Message = 0;
	struct RexxMsg *rexxMsg = 0, memRexxMsg;

	if (!(conwin = (struct FILE *) fopen("CON:10/10/620/180/DTMF_ERROR/auto/close/wait", "r+")))
		cleanUp("Can't open output window\n", 6);

	FromWB = (argc == 0 ? TRUE : FALSE);

	if (argc == 0)
		WBenchMsg = (struct WBStartup *) argv;

	Chaine[0] = '\0';

	if (argc >= 1)
	{
		char    dirName[100];
		BPTR    lockDir;

		lockDir = GetProgramDir();
		if (lockDir)
			NameFromLock(lockDir, dirName, 100);

		AssignPath("DTMF", dirName);

        strcat (dirName, "/");
		GetProgramName((STRPTR) & dirName[strlen(dirName)], 100 - strlen(dirName));

		CheckToolTypes(dirName);
	}
	else
	{
		char    dirName[100];
		struct WBArg *wbarg;

		wbarg = WBenchMsg->sm_ArgList;

		NameFromLock(wbarg->wa_Lock, dirName, 100);
		AssignPath("DTMF", dirName);

		CheckToolTypes(wbarg->wa_Name);
	}
	if (argc > 1)
	{
		int     erreur = 0,
		        i;

		for (i = 1; i < argc; i++)
		{
			if ((argv[i][0] >= '0') && (argv[i][0] <= '9'))
			{
				strcpy(Chaine, argv[i]);
				GUI = 0;
			}

			else if (argv[i][0] == '-')
			{
				switch (toupper(argv[i][1]))
				    {
				    case 'T':
					    switch (toupper(argv[i][2]))
						{
						case 'T':
							int     value;

							if ((value = atoi(&argv[i][3])) >= 40)
								timePulse.tv_micro = value * 1000;
							break;

						case 'S':
							int     value;

							if ((value = atoi(&argv[i][3])) >= 40)
								timeSpace.tv_micro = value * 1000;
							break;

						case 'P':
							int     value;

							if ((value = atoi(&argv[i][3])) >= 40)
								timePause.tv_micro = value * 1000;
							break;

						default:
							cleanUp("\nl'option -t. est incorrecte\n", 6);
							break;
						}
					    break;

				    case 'C':
					    switch (toupper(argv[i][2]))
						{
						case 'D':
							allocIOB->ioa_Data = (UBYTE *) allocationMapRight;
							allocIOB->ioa_Length = sizeof(allocationMapRight);
							break;

						case 'G':
							allocIOB->ioa_Data = (UBYTE *) allocationMapLeft;
							allocIOB->ioa_Length = sizeof(allocationMapLeft);
							break;

						default:
							cleanUp("\nl'option -c. est incorrecte\n", 6);
							break;
						}
					    break;

				    case 'W':
					    switch (toupper(argv[i][2]))
						{
						case 'C':	     /* coordonnées de la fenêtre clavier */
							switch (toupper(argv[i][3]))
							    {
							    case 'L':
								    winClavLeft = atoi(&argv[i][4]);
								    break;

							    case 'T':
								    winClavTop = atoi(&argv[i][4]);
								    break;

							    default:
								    cleanUp("\nl'option -wc. est incorrecte\n", 6);
								    break;
							    }
							break;

						case 'R':	     /* coordonnées de la fenêtre répertoire */
							switch (toupper(argv[i][3]))
							    {
							    case 'L':
								    winRepLeft = atoi(&argv[i][4]);
								    break;

							    case 'T':
								    winRepTop = atoi(&argv[i][4]);
								    break;

							    default:
								    cleanUp("\nl'option -wr. est incorrecte\n", 6);
								    break;
							    }
							break;

						default:
							cleanUp("\nl'option -w. est incorrecte\n", 6);
							break;
						}
					    break;

				    default:
					    cleanUp("\nl'option -.. est incorrecte\n", 6);
					    break;
				    }
			}
			else
			{
				composeNom = i++;
				GUI = 0;
			}

		}
	}
	OpenAll();

	CalcFreq();

	if (composeNom)
	{
		abonne.nom[0] = '\0';
		abonne.prenom[0] = '\0';
		abonne.adresse1[0] = '\0';
		abonne.adresse2[0] = '\0';
		abonne.codepost[0] = '\0';
		abonne.ville[0] = '\0';
		abonne.pays[0] = '\0';
		abonne.telephone1[0] = '\0';
		abonne.telephone2[0] = '\0';
		abonne.fax[0] = '\0';
		abonne.note1[0] = '\0';
		abonne.note2[0] = '\0';
		strcpy(abonne.nom, argv[composeNom]);
		if (Recherche())
		{
			if ((atoi(argv[composeNom + 1]) > 0) && (atoi(argv[composeNom + 1]) < 4))
			{
				switch (atoi(argv[composeNom + 1]))
				    {
				    case 1:
					    strcpy(Chaine, abonne.telephone1);
					    break;
				    case 2:
					    strcpy(Chaine, abonne.telephone2);
					    break;
				    case 3:
					    strcpy(Chaine, abonne.fax);
					    break;
				    }
			}
			else
				cleanUp("\nLe deuxième argument est incorrect\n", 6);
		}
	}
	if (!GUI)
	{
		int     erreur = 0;

		erreur = Recompose(Chaine);
		if (erreur)
			cleanUp("\nLe numéro spécifié comporte des chiffres incorrects\n", erreur);
		else
			cleanUp("", 0);
	}

	ModifyIDCMP(MyWindow, IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_MENUPICK | BUTTONIDCMP);

	i = 0;
	while (notclosed)
	{
		if (!FileWindow)
			signals = Wait((1 << MyWindow->UserPort->mp_SigBit) | (rexxPortBit));
		else
			signals = Wait((1 << MyWindow->UserPort->mp_SigBit) | (rexxPortBit) | (1 << FileWindow->UserPort->mp_SigBit));

		if (signals & (1 << MyWindow->UserPort->mp_SigBit))
		{
			while (notclosed && (Message = (struct IntuiMessage *) GT_GetIMsg(MyWindow->UserPort)))
			{
				Class = Message->Class;
				Code = Message->Code;
				Address = Message->IAddress;

				GT_ReplyIMsg((struct IntuiMessage *) Message);

				switch (Class)
				    {
				    case IDCMP_CLOSEWINDOW:
					    if (FileWindow)
					    {
						    CloseFileWindow();
					    }
					    ModifyIDCMP(MyWindow, 0L);
					    notclosed = 0;
					    cleanUp("", 0);
					    break;

				    case IDCMP_MENUPICK:
					    if (Code != MENUNULL)
					    {
						    switch (ITEMNUM(Code))
							{
							case 0:
								Repertoire();
								Num = 18;
								break;

							case 1:
								About(pubScreen);
								break;

							default:
								break;
							}
					    }
					    break;

				    case IDCMP_GADGETUP:
					    Num = ((struct Gadget *) Address)->GadgetID;

					    break;

				    case IDCMP_VANILLAKEY:
					    switch (Code)
						{
						case '0':
							Num = 0;
							break;

						case '1':
							Num = 1;
							break;

						case '2':
							Num = 2;
							break;

						case '3':
							Num = 3;
							break;

						case '4':
							Num = 4;
							break;

						case '5':
							Num = 5;
							break;

						case '6':
							Num = 6;
							break;

						case '7':
							Num = 7;
							break;

						case '8':
							Num = 8;
							break;

						case '9':
							Num = 9;
							break;

						case '-':
							Num = 10;
							break;

						case '+':
							Num = 11;
							break;

						case '[':
							Num = 12;
							break;

						case ']':
							Num = 13;
							break;

						case '/':
							Num = 14;
							break;

						case '*':
							Num = 15;
							break;

						case '.':
							Num = 16;
							break;

						case 13:
							Num = 17;
							break;

						default:
							Chaine[0] = '\0';
							i = 0;

							break;
						}
					    break;

				    default:
					    break;
				    }
			}

			if ((Num < 17) && (i < MAXNUM))
			{
				Chaine[i++] = Touche[Num];
				Chaine[i] = '\0';
				Compose(Num);
				Num = 18;
			}

			if (Num == 17)
			{
				Recompose(Chaine);
			}
			GT_SetGadgetAttrs(gadText, MyWindow, NULL,
					  GTTX_Text, Chaine,
					  TAG_END);
		}

		else if (signals & rexxPortBit)
		{
			while (rexxMsg = (struct RexxMsg *) GetMsg(rexxPort))
			{
				CopyMem(rexxMsg, &memRexxMsg, sizeof(struct RexxMsg));

				ReplyMsg((struct Message *) rexxMsg);

				sscanf(memRexxMsg.rm_Args[0], "%s", RxCmd);
				connue = 0;
				while ((strcmp(RxCmd, Command[connue++])) && (connue < NB_REXXCMD)) ;
				switch (connue)
				    {
				    case 1:			     // COMPOSE

					    sscanf(memRexxMsg.rm_Args[0], "%s %s", RxCmd, RxArg1);
					    strcpy(RexxTelChaine, RxArg1);
					    Recompose(RexxTelChaine);
					    break;

				    case 2:			     // RECOMPOSE

					    Recompose(RexxTelChaine);
					    break;

				    case 3:			     // AJOUTEFICH

					    abonne.nom[0] = '\0';
					    abonne.prenom[0] = '\0';
					    abonne.adresse1[0] = '\0';
					    abonne.adresse2[0] = '\0';
					    abonne.codepost[0] = '\0';
					    abonne.ville[0] = '\0';
					    abonne.pays[0] = '\0';
					    abonne.telephone1[0] = '\0';
					    abonne.telephone2[0] = '\0';
					    abonne.fax[0] = '\0';
					    abonne.note1[0] = '\0';
					    abonne.note2[0] = '\0';

					    i = strspn(memRexxMsg.rm_Args[0], RxCmd) + 1;
					    for (j = 0; ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.nom[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.nom[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.prenom[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.prenom[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.adresse1[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.adresse1[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.adresse2[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.adresse2[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.codepost[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.codepost[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.ville[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.ville[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.pays[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.pays[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.telephone1[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.telephone1[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.telephone2[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.telephone2[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.fax[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.fax[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.note1[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.note1[j] = '\0';
					    }

					    if (memRexxMsg.rm_Args[0][i] == '\0')
						    break;

					    for ((j = 0, i++); ((memRexxMsg.rm_Args[0][i] != '.') && (memRexxMsg.rm_Args[0][i] != '\0')); i++)
					    {
						    abonne.note2[j++] = memRexxMsg.rm_Args[0][i];
						    abonne.note2[j] = '\0';
					    }

					    Ajoute();
					    break;

				    default:			     // UNKNOW

					    break;
				    }

			}
		}
		else if (signals & (1 << FileWindow->UserPort->mp_SigBit))
		{
			while (FileWindowNotClosed && (Message = (struct IntuiMessage *) GetMsg(FileWindow->UserPort)))
			{
				Class = Message->Class;
				Code = Message->Code;
				Address = Message->IAddress;

				ReplyMsg((struct Message *) Message);
				HandleFileWindow(Class, Code, Address);
			}
		}
	}
	return (0);
}

/****************************************************************/
/*
 * Compose une touche
 */
/*
 */
/*
 */
/*
 * Paramètres: BYTE numéro de la touche
 */
/*
 * Retour: NULL
 */
/****************************************************************/
void
Compose(BYTE touche)
{
	BYTE    ligne = Tonalite[touche][0];

	BYTE    colonne = Tonalite[touche][1];

	custom.aud[channel0].ac_ptr = DualTone[0][ligne];
	custom.aud[channel0].ac_len = longTone[0][ligne];
	custom.aud[channel0].ac_per = periode[0][ligne];
	custom.aud[channel0].ac_vol = 64;

	custom.aud[channel1].ac_ptr = DualTone[1][colonne];
	custom.aud[channel1].ac_len = longTone[1][colonne];
	custom.aud[channel1].ac_per = periode[1][colonne];
	custom.aud[channel1].ac_vol = 64;

	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | channels;	     // Lancement des canaux DMA audio

	wait_for_timer(tr, &timePulse);

	custom.dmacon = channels;				     // arrêt du DMA

}

/****************************************************************/
/*
 * Recompose un numéro de téléphone
 */
/*
 */
/*
 */
/*
 * Paramètres: BYTE *tableau des chiffres
 */
/*
 * Retour: NULL
 */
/****************************************************************/
int
Recompose(BYTE * numTel)
{
	int     i = 0,
	        num,
	        erreur = 0;

	while (numTel[i] != '\0')
	{
		switch (numTel[i])
		    {
		    case '0':
		    case '1':
		    case '2':
		    case '3':
		    case '4':
		    case '5':
		    case '6':
		    case '7':
		    case '8':
		    case '9':
			    num = numTel[i] - '0';
			    break;
		    case '*':
			    num = 10;
			    break;
		    case '#':
			    num = 11;
			    break;
		    case 'A':
		    case 'B':
		    case 'C':
		    case 'D':
			    num = numTel[i] - 'A' + 12;
			    break;
		    case ':':
			    num = 16;
			    break;
		    default:
			    erreur = 1;
			    goto next;
			    break;
		    }
		Compose(num);

		if (num == 16)
			wait_for_timer(tr, &timePause);
		else
			wait_for_timer(tr, &timeSpace);
	      next:
		i++;
	}
	return (erreur);
}

/****************************************************************/
/*
 * calcul des paires de fréquences à partir d'une
 */
/*
 * sinusoïde de référence
 */
/*
 */
/*
 * Paramètres: NULL
 */
/*
 * Retour: NULL
 */
/****************************************************************/
void
CalcFreq()
{
	int     i,
	        j;
	BYTE    sineTable1[SINETABLESIZE],
	        sineTable2[SINETABLESIZE];

    // Calcul de la période de référence des fréquences basses dont l'amplitude
    // est 1.25 celle des fréquences hautes. En réalité sur la ligne téléphonique
    // les fréquences basses sont émises à 275 mV pour 220 mV en fréquences hautes

	for (i = 0; i < SINETABLESIZE; ++i)
	{
		sineTable1[i] = (BYTE) (127 * sin(i * (2 * PI / SINETABLESIZE)));
	}
	for (i = 0; i < SINETABLESIZE; ++i)
	{
		sineTable2[i] = (BYTE) (101 * sin(i * (2 * PI / SINETABLESIZE)));
	}

    // ici on calcule les 8 fréquences de numérotation (une periode chacune).
    // & 0x3ff permet de réaliser rapidement un comptage modulo 1024,
    // puisque la période de référence comporte 1024 valeurs.

	for (i = 0; i < 4; i++)
	{
		for (j = 0;;)
		{
		    // définition des formes d'onde des lignes
			DualTone[0][i][j++] = sineTable1[(angle1 += frequency[0][i]) & 0x3ff];
			if ((j > 1) && (DualTone[0][i][j - 2] <= 0) && (DualTone[0][i][j - 1] >= 0))
			{
				longTone[0][i] = j / 2;
				break;
			}
		}

		for (j = 0;;)
		{
		    // définition des formes d'onde des colonnes

			DualTone[1][i][j++] = sineTable2[(angle2 += frequency[1][i]) & 0x3ff];
			if ((j > 1) && (DualTone[1][i][j - 2] <= 0) && (DualTone[1][i][j - 1] >= 0))
			{
				longTone[1][i] = j / 2;
				break;
			}
		}
		angle1 = angle2 = 0;
	}
}

void
wait_for_timer(struct timerequest *tr, struct timeval *tv)
{

	tr->tr_node.io_Command = TR_ADDREQUEST;			     /*
								      * * * add a new timer request
								      */

/*
 * structure assignment
 */
	tr->tr_time = *tv;

/*
 * post request to the timer -- will go to sleep till done
 */
	DoIO((struct IORequest *) tr);
}

void
About(struct Screen *Scr)
{
	struct TextAttr topaz8165 =
	{(STRPTR) "topaz.font", 8, 1, 65};
	struct TextAttr topaz81281 =
	{(STRPTR) "topaz", 8, 128, 1};
	APTR    Win0VisualInfo;

	struct IntuiText aboutWinTexts[] =
	{
		1, 3, JAM1, 5, 3, &topaz8165, (UBYTE *) "DualTone MultiFrequency V2.2", &aboutWinTexts[1],
		2, 3, JAM1, 57, 20, &topaz81281, (UBYTE *) "Ecrit par Alain Bonnefoy", &aboutWinTexts[2],
		2, 3, JAM1, 57, 32, &topaz81281, (UBYTE *) "6, Allée Vincent Scotto", &aboutWinTexts[3],
		2, 3, JAM1, 57, 44, &topaz81281, (UBYTE *) "26000 VALENCE", &aboutWinTexts[4],
		2, 3, JAM1, 58, 55, &topaz81281, (UBYTE *) "FRANCE", &aboutWinTexts[5],
		1, 3, JAM1, 6, 68, &topaz81281, (UBYTE *) "Merci à:", &aboutWinTexts[6],
		1, 3, JAM1, 19, 79, &topaz81281, (UBYTE *) "Electronique RadioPlans", &aboutWinTexts[7],
		1, 3, JAM1, 38, 89, &topaz81281, (UBYTE *) "pour les tonalités", &aboutWinTexts[8],
		1, 3, JAM1, 18, 101, &topaz81281, (UBYTE *) "Ian OConnor pour Designer", &aboutWinTexts[9],
		1, 3, JAM1, 19, 113, &topaz81281, (UBYTE *) "Mattew Dillon pour Dice", &aboutWinTexts[10],
		1, 3, JAM1, 19, 125, &topaz81281, (UBYTE *) "Philippe Le Molaire", &aboutWinTexts[11],
		1, 3, JAM1, 40, 136, &topaz81281, (UBYTE *) "Pour son idée sur la", &aboutWinTexts[12],
		1, 3, JAM1, 40, 146, &topaz81281, (UBYTE *) "génération des tonalités", NULL
	};

	struct Window *aboutWin = NULL;
	UWORD   offx,
	        offy;

	offx = Scr->WBorLeft;
	offy = Scr->WBorTop + Scr->Font->ta_YSize + 1;
	if (NULL != (Win0VisualInfo = GetVisualInfoA(Scr, NULL)))
		if ((aboutWin = (struct Window *) OpenWindowTags(NULL,
								 WA_Left, 206,
								 WA_Top, 138,
								 WA_Width, 251 + offx,
								 WA_Height, 161 + offy,
								 WA_Title, "A propos de DTMF",
								 WA_MinWidth, 150,
								 WA_MinHeight, 25,
								 WA_MaxWidth, 1200,
								 WA_MaxHeight, 1200,
								 WA_DragBar, TRUE,
								 WA_CloseGadget, TRUE,
								 WA_Activate, TRUE,
								 WA_SmartRefresh, TRUE,
								 WA_AutoAdjust, TRUE,
								 WA_IDCMP, IDCMP_CLOSEWINDOW,
								 TAG_END)))
		{
			for (int loop = 0; loop < 13; loop++)
				if (aboutWinTexts[loop].ITextFont == NULL)
					aboutWinTexts[loop].ITextFont = aboutWin->WScreen->Font;
			PrintIText(aboutWin->RPort, aboutWinTexts, offx, offy);
			WaitPort(aboutWin->UserPort);
			CloseWindow(aboutWin);
		}
}

void
CheckToolTypes(char *name)
{
	struct Library *IconBase;
struct DiskObject *dobj;
	char  **toolarray;
	char   *s;

	if ((allocIOB = (struct IOAudio *) AllocMem(sizeof(struct IOAudio), MEMF_PUBLIC | MEMF_CLEAR)) == 0)
        cleanUp("Out of memory", 6);

	if (!(IconBase = OpenLibrary("icon.library", 33)))
		cleanUp("Can't open icon.library\n", 6);

	if ((*name) && (dobj = GetDiskObject(name)))
	{
		toolarray = (char **) dobj->do_ToolTypes;
		if (s = (char *) FindToolType(toolarray, "WINCLAVTOP"))
		{
			winClavTop = atoi(s);
		}
		if (s = (char *) FindToolType(toolarray, "WINCLAVLEFT"))
		{
			winClavLeft = atoi(s);
		}
		if (s = (char *) FindToolType(toolarray, "WINREPTOP"))
		{
			winRepTop = atoi(s);
		}
		if (s = (char *) FindToolType(toolarray, "WINREPLEFT"))
		{
			winRepLeft = atoi(s);
		}

		if (s = (char *) FindToolType(toolarray, "PREFCHANNEL"))
		{
			if (MatchToolValue(s, "left"))
			{
				allocIOB->ioa_Data = (UBYTE *) allocationMapLeft;
				allocIOB->ioa_Length = sizeof(allocationMapLeft);
			}
			else if (MatchToolValue(s, "right"))
			{
				allocIOB->ioa_Data = (UBYTE *) allocationMapRight;
				allocIOB->ioa_Length = sizeof(allocationMapRight);
			}
			else
				cleanUp("Vous devez spécifier comme argument de PREFCHANNEL : left ou right", 6);
		}
		else
		{
			allocIOB->ioa_Data = (UBYTE *) allocationMap;
			allocIOB->ioa_Length = sizeof(allocationMap);
		}

		if (s = (char *) FindToolType(toolarray, "TIMEPULSE"))
		{
			int     value;

			if ((value = atoi(s)) >= 40)
				timePulse.tv_micro = value * 1000;
		}
		if (s = (char *) FindToolType(toolarray, "TIMESPACE"))
		{
			int     value;

			if ((value = atoi(s)) >= 40)
				timeSpace.tv_micro = value * 1000;
		}
		if (s = (char *) FindToolType(toolarray, "TIMEPAUSE"))
		{
			int     value;

			if ((value = atoi(s)) >= 40)
				timePause.tv_micro = value * 1000;
		}
		FreeDiskObject(dobj);
	}
	else
	{
		allocIOB->ioa_Data = (UBYTE *) allocationMap;
		allocIOB->ioa_Length = sizeof(allocationMap);
	}

	if (IconBase != NULL)
		CloseLibrary((struct Library *) IconBase);

}
