	Configuration file

	The configuration file describes the available applets. The
	file is read at start-up and loaded into five lists:
	[[agents]], [[viewers]], [[filters]], [[printers]],
	[[user_functions]].

	The configuration file contains five types of items. Each item
	starts with a keyword. Each item has three or four lines in a
	fixed order, each starting with a keyword. A line may contain
	a [[#]], which causes the rest of the line to be ignored
	(rather: treated as whitespace).

	MIME-types may include wildcards [[*]] and [[?]]. The file is
	case-sensitive. Empty lines are ignored. The labels after the
	LABEL keyword are separated by commas. Each label may include
	spaces (but no commas).

        VIEWER suffix
        TYPE mime-type
        FILE path/file

        AGENT suffix
        PROTOCOL protocol
        FILE path/file

        FILTER suffix
        FROM mime-type
        TO mime-type
        FILE path/file

        FUNCTION suffix
        LABELS label-1, label-2, label-3...     # zero or more
        ICONS xpm-file-1, xpm-file-2...         # same number of icons
        FILE path/file

        PRINTER suffix
        TYPE mime-type
        FILE path/file
        
	The function [[read_config]] reads the configuration file. It
	should be called only once. Except for some warning messages,
	nothing serious should happen if the function is called again,
	though.

	TO DO: the [[read_config]] file should look for the file in
	the user's home directory.'

<<*>>=
#include "config.h"
#include "str.h"
#include "w3a.h"

/* #define SAVE					/* Save to file, */
						/* instead of external */
						/* viewer */
EXPORT typedef struct {
    Strip suffix;
    Strip file;
    char **mime_types;
    float *prefs;
    int nrtypes;
    Bool (*init)(char ***mime_types, int *nrtypes, float **prefs);
    Bool (*open)(const W3ADocumentInfo, W3AWindow, long);
    int (*write)(long, const char *buf, size_t nbytes);
    Bool (*close)(long);
    Bool (*info)(long, W3ADocumentInfo *);
    void (*event)(long id, long sourceid, long eventtype, void *params);
} Viewer;

EXPORT typedef struct {
    Strip suffix;
    Strip file;
    char **protocols;
    int nrprotocols;
    Bool (*init)(char ***protocols, int *nrprotocols);
    int (*open)(const char *, int, int, const char *);
    int (*done)(int);
    int (*peek)(int);
    int (*read)(int, char *, size_t);
    int (*write)(int, const char *, size_t);
    Bool (*close)(int);
    Bool (*delete)(const char *);
    Bool (*info)(int, W3ADocumentInfo *);
} Agent;

EXPORT typedef struct {
    Strip suffix;
    Strip file;
    char **from;
    char **to;
    float *prefs;
    int nrfromto;
    Bool (*init)(char ***from, char ***to, int *nrfromto, float **prefs);
    Bool (*open)(const char *, const char *, const char *, const char *, long);
    int (*write)(long, const char *, size_t);
    int (*read)(long, char *, size_t);
    Bool (*close)(long);
} Filter;

EXPORT typedef struct {
    Strip suffix;
    Strip file;
#if 0
    char **labels;
    char **icons;
    int nrlabels;
#endif
    Bool (*init)(long, char ***, ThreeIcons *icons_data[], int *);
    Bool (*doit)(int, int, int);
    void (*event)(long sourceid, long eventtype, void *params);
    long id;					/* Single instance */
} UserFunction;

EXPORT typedef struct {
    Strip suffix;
    Strip file;
    char **mime_types;
    int nrtypes;
    Bool (*init)(char ***mime_types, int *nrtypes);
    Bool (*open)(const W3ADocumentInfo, long);
    int (*write)(long, const char *, size_t);
    Bool (*close)(long);
} Printer;

EXPORT Viewer *viewers = NULL;
EXPORT Agent *agents = NULL;
EXPORT Filter *filters = NULL;
EXPORT UserFunction *userfns = NULL;
EXPORT Printer *printers = NULL;

EXPORT int nragents = 0;
EXPORT int nrfilters = 0;
EXPORT int nrfunctions = 0;
EXPORT int nrprinters = 0;
EXPORT int nrviewers = 0;


static Bool read_word(FILE *f, char *word, size_t buflen)
{
    int i;
    char c;
        
    buflen--;
    do {
        c = getc(f);
        if (c == '#') do c = getc(f); while (c != EOF && c != '\n');
        if (c == EOF) return FALSE;
    } while (isspace(c));
    i = 0;
    do {
        word[i++] = c;
        c = getc(f);
    } while (i < buflen && c != EOF && !isspace(c));
    word[i] = '\0';
    return TRUE;
}


static Bool skipblanks(FILE *f)
{
    int c;

    while ((c = getc(f)) != EOF && (c == ' ' || c == '\t')) ;
    ungetc(c, f);
    return TRUE;
}


static void read_viewer(FILE *f, const char *filename)
{
    char suffix[256], word[20], file[1024];
    Viewer v;

    if (!read_word(f, suffix, sizeof(suffix))
        || !read_word(f, word, sizeof(word)) || !eq(word, "FILE")
        || !read_word(f, file, sizeof(file)))
        warning("Incorrect configuration file: %s\n", filename);
    else {
	renewarray(viewers, nrviewers + 1);
        viewers[nrviewers].suffix = str2strip(suffix);
        viewers[nrviewers].mime_types = NULL;
        viewers[nrviewers].prefs = NULL;
	viewers[nrviewers].nrtypes = 0;
        viewers[nrviewers].file = str2strip(file);
        viewers[nrviewers].init = NULL;
	nrviewers++;
    }
}


static void read_agent(FILE *f, const char *filename)
{
    char suffix[256], word[20], file[1024];
    Agent a;
    
    if (!read_word(f, suffix, sizeof(suffix))
        || !read_word(f, word, sizeof(word)) || !eq(word, "FILE")
        || !read_word(f, file, sizeof(file)))
        warning("Incorrect configuration file: %s\n", filename);
    else {
	renewarray(agents, nragents + 1);
        agents[nragents].suffix = str2strip(suffix);
        agents[nragents].protocols = NULL;
        agents[nragents].nrprotocols = 0;
        agents[nragents].file = str2strip(file);
        agents[nragents].init = NULL;
	nragents++;
    }
}


static void read_filter(FILE *f, const char *filename)
{
    char suffix[256], word[20], file[1024];
    Filter a;

    if (!read_word(f, suffix, sizeof(suffix))
        || !read_word(f, word, sizeof(word)) || !eq(word, "FILE")
        || !read_word(f, file, sizeof(file)))
        warning("Incorrect configuration file: %s\n", filename);
    else {
	renewarray(filters, nrfilters + 1);
        filters[nrfilters].suffix = str2strip(suffix);
        filters[nrfilters].from = NULL;
        filters[nrfilters].to = NULL;
        filters[nrfilters].prefs = NULL;
        filters[nrfilters].nrfromto = 0;
        filters[nrfilters].file = str2strip(file);
        filters[nrfilters].init = NULL;
	nrfilters++;
    }
}


static void read_printer(FILE *f, const char *filename)
{
    char suffix[256], word[20], file[1024];
    Printer p;

    if (!read_word(f, suffix, sizeof(suffix))
        || !read_word(f, word, sizeof(word)) || !eq(word, "FILE")
        || !read_word(f, file, sizeof(file)))
        warning("Incorrect configuration file: %s\n", filename);
    else {
	renewarray(printers, nrprinters + 1);
        printers[nrprinters].suffix = str2strip(suffix);
        printers[nrprinters].mime_types = NULL;
        printers[nrprinters].nrtypes = 0;
        printers[nrprinters].file = str2strip(file);
        printers[nrprinters].init = NULL;
	nrprinters++;
    }
}


static void read_function(FILE *f, const char *filename)
{
    char suffix[256], word[20], file[1024];
    UserFunction u;

    if (!read_word(f, suffix, sizeof(suffix))
        || !read_word(f, word, sizeof(word)) || !eq(word, "FILE")
        || !read_word(f, file, sizeof(file)))
        warning("Incorrect configuration file: %s\n", filename);
    else {
	renewarray(userfns, nrfunctions + 1);
        userfns[nrfunctions].suffix = str2strip(suffix);
#if 0
        userfns[nrfunctions].labels = NULL;
        userfns[nrfunctions].icons = NULL;
	userfns[nrfunctions].nrlabels = 0;
#endif
        userfns[nrfunctions].file = str2strip(file);
        userfns[nrfunctions].init = NULL;
        userfns[nrfunctions].id = -1;
	nrfunctions++;
    }
}


#if 1
#include "HTML.h"
static Viewer html_viewer = {
    NULL, NULL, NULL, NULL, 0, initHTML, openHTML, writeHTML, closeHTML,
    infoHTML, eventHTML,
};
#include "SGML.h"
static Viewer sgml_viewer = {
    NULL, NULL, NULL, NULL, 0, initSGML, openSGML, writeSGML, closeSGML,
    infoSGML, eventSGML,
};
#include "GIF.h"
static Viewer gif_viewer = {
    NULL, NULL, NULL, NULL, 0, initGIF, openGIF, writeGIF, closeGIF,
    infoGIF, eventGIF,
};
#include "XPM.h"
static Viewer xpm_viewer = {
    NULL, NULL, NULL, NULL, 0, initXPM, openXPM, writeXPM, closeXPM,
    infoXPM, eventXPM,
};
#include "XBM.h"
static Viewer xbm_viewer = {
    NULL, NULL, NULL, NULL, 0, initXBM, openXBM, writeXBM, closeXBM,
    infoXBM, eventXBM,
};
#include "Debug.h"
static Viewer debug_viewer = {
    NULL, NULL, NULL, NULL, 0, initDebug, openDebug, writeDebug, closeDebug,
    infoDebug, eventDebug,
};
#include "Telnet.h"
static Viewer telnet_viewer = {
    NULL, NULL, NULL, NULL, 0, initTelnet, openTelnet, writeTelnet, closeTelnet,
    infoTelnet, eventTelnet,
};
#include "PBM.h"
static Viewer pbm_viewer = {
    NULL, NULL, NULL, NULL, 0, initPBM, openPBM, writePBM, closePBM,
    infoPBM, eventPBM,
};
#include "Plain.h"
static Viewer plain_viewer = {
    NULL, NULL, NULL, NULL, 0, initPlain, openPlain, writePlain, closePlain,
    infoPlain, eventPlain,
};
#include "Postscript.h"
static Viewer postscript_viewer = {
    NULL, NULL, NULL, NULL, 0, initPostscript, openPostscript,
    writePostscript, closePostscript, infoPostscript, eventPostscript,
};
#ifdef SAVE
#include "Save.h"
static Viewer save_viewer = {
    NULL, NULL, NULL, NULL, 0, initSave, openSave, writeSave, closeSave,
    infoSave, eventSave,
};
#endif
#include "Extern.h"
static Viewer extern_viewer = {
    NULL, NULL, NULL, NULL, 0, initExtern, openExtern, writeExtern, closeExtern,
    infoExtern, eventExtern,
};
#include "HTTP.h"
static Agent http_agent = {
    NULL, NULL, NULL, 0, initHTTP, openHTTP, doneHTTP, peekHTTP,
    readHTTP, writeHTTP, closeHTTP, deleteHTTP, infoHTTP,
};
#include "Gopher.h"
static Agent gopher_agent = {
    NULL, NULL, NULL, 0, initGopher, openGopher, doneGopher, peekGopher,
    readGopher, writeGopher, closeGopher, deleteGopher, infoGopher,
};
#include "TELNET.h"
static Agent telnet_agent = {
    NULL, NULL, NULL, 0, initTELNET, openTELNET, doneTELNET, peekTELNET,
    readTELNET, writeTELNET, closeTELNET, deleteTELNET, infoTELNET,
};
#include "MailTo.h"
static Agent mailto_agent = {
    NULL, NULL, NULL, 0, initMailTo, openMailTo, doneMailTo, peekMailTo,
    readMailTo, writeMailTo, closeMailTo, deleteMailTo, infoMailTo,
};
#include "FTP.h"
static Agent ftp_agent = {
    NULL, NULL, NULL, 0, initFTP, openFTP, doneFTP, peekFTP,
    readFTP, writeFTP, closeFTP, deleteFTP, infoFTP,
};
#include "Hotlist.h"
static UserFunction hotlist_fn = {
    NULL, NULL, initHotlist, doHotlist, eventHotlist, 0
};
#include "History.h"
static UserFunction history_fn = {
    NULL, NULL, initHistory, doHistory, eventHistory, 0
};
#endif /* 1 */


EXPORT void read_config(const char *file)
{
    FILE *f;
    char word[256];

#if 1
#if 0
    debug_viewer.suffix = str2strip("Debug");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = debug_viewer;
    nrviewers++;
#endif

    html_viewer.suffix = str2strip("HTML");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = html_viewer;
    nrviewers++;

    sgml_viewer.suffix = str2strip("SGML");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = sgml_viewer;
    nrviewers++;

    gif_viewer.suffix = str2strip("GIF");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = gif_viewer;
    nrviewers++;

    xpm_viewer.suffix = str2strip("XPM");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = xpm_viewer;
    nrviewers++;

    xbm_viewer.suffix = str2strip("XBM");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = xbm_viewer;
    nrviewers++;

    telnet_viewer.suffix = str2strip("Telnet");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = telnet_viewer;
    nrviewers++;

    pbm_viewer.suffix = str2strip("PBM");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = pbm_viewer;
    nrviewers++;

    plain_viewer.suffix = str2strip("Plain");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = plain_viewer;
    nrviewers++;

    postscript_viewer.suffix = str2strip("Postscript");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = postscript_viewer;
    nrviewers++;

#ifdef SAVE
    save_viewer.suffix = str2strip("Save");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = save_viewer;
    nrviewers++;
#endif

    extern_viewer.suffix = str2strip("Extern");
    renewarray(viewers, nrviewers + 1);
    viewers[nrviewers] = extern_viewer;
    nrviewers++;

    http_agent.suffix = str2strip("HTTP");
    renewarray(agents, nragents + 1);
    agents[nragents] = http_agent;
    nragents++;

    gopher_agent.suffix = str2strip("Gopher");
    renewarray(agents, nragents + 1);
    agents[nragents] = gopher_agent;
    nragents++;

    ftp_agent.suffix = str2strip("FTP");
    renewarray(agents, nragents + 1);
    agents[nragents] = ftp_agent;
    nragents++;

    telnet_agent.suffix = str2strip("TELNET");
    renewarray(agents, nragents + 1);
    agents[nragents] = telnet_agent;
    nragents++;

    mailto_agent.suffix = str2strip("MailTo");
    renewarray(agents, nragents + 1);
    agents[nragents] = mailto_agent;
    nragents++;

    ftp_agent.suffix = str2strip("FTP");
    renewarray(agents, nragents + 1);
    agents[nragents] = ftp_agent;
    nragents++;

    hotlist_fn.suffix = str2strip("Hotlist");
    renewarray(userfns, nrfunctions + 1);
    userfns[nrfunctions] = hotlist_fn;
    nrfunctions++;

    history_fn.suffix = str2strip("History");
    renewarray(userfns, nrfunctions + 1);
    userfns[nrfunctions] = history_fn;
    nrfunctions++;
#endif /* 1 */

    if ((f = fopen(file, "r"))) {
	while (read_word(f, word, sizeof(word))) {
	    if (eq(word, "VIEWER")) read_viewer(f, file);
	    else if (eq(word, "AGENT")) read_agent(f, file);
	    else if (eq(word, "FILTER")) read_filter(f, file);
	    else if (eq(word, "PRINTER")) read_printer(f, file);
	    else if (eq(word, "FUNCTION")) read_function(f, file);
	    else warning("Error in %s --> %s\n", file, word);
	}
	fclose(f);
    }
}
