/*
 *  Yes, yes, yes. No running commentary throughout the code, but I understand it
 *   (I think)
 *   (Yeah, have no fear, I remember now)
 */

#include "demo.h"
#include "adt.h"

void __regargs __chkabort(void);
void __regargs __chkabort(void) {}

static APTR win;
static APTR mainpage, lvpage, recentlv, shortlv, taggedlv, newlv, hostslv, readtext, getlv;
static APTR files_status, host_status, host_cancel_but, read_next_but, read_can_but, get_abort_but;
APTR get_gauge, app;
static APTR cfg_but, sort_but, view_but, read_but, name_but, get_but, host_but, quit_but;
static APTR search_str, search_next, search_can;
static APTR def_sort_but, def_view_but, def_getdir, def_tmpdir, def_uncomp, def_done;
static LONG sorttype=0, viewtype=0;

static LONG readpos;

static BOOL gotrecent=FALSE, gotshort=FALSE, gotnew=FALSE;
extern BOOL connected;

struct HostLineRec *host=NULL;
struct PrefsRec prefs;

static const char *SortEntries[] = { "Name", "Age", "Dir", NULL };
static const char *ViewEntries[] = { "New", "Recent", "All", "Tagged", NULL };
static const char *HostList[] = {
    "SCANDINAVIA ftp.luth.se pub/aminet/",
    "SWITZERLAND litamiga.epfl.ch pub/aminet/",
    "GERMANY ftp.uni-kl.de pub/aminet/",
    "GERMANY ftp.cs.tu-berlin.de pub/aminet/",
    "GERMANY ftp.uni-erlangen.de pub/aminet/",
    "GERMANY ftp.uni-paderborn.de pub/aminet/",
    "USA wcarchive.cdrom.com pub/aminet/",
    "USA ftp.etsu.edu pub/aminet/",
    "USA wuarchive.wustl.edu pub/aminet/",
    "UK src.doc.ic.ac.uk pub/aminet/",
    "AUSTRALIA splat.aarnet.edu.au pub/aminet/",
    NULL
};

/* breaks a string at the token 'mark', returning a pointer to the beggining
   of the string */

char *gettok(char **ptr, char mark, int *toklen)
{
  char *t, *start = *ptr;

  if( (t=(char*)strchr(*ptr,mark))) {
    *t=0;
    *ptr=t+1;
  }
  *toklen = t - start + 1;
  return start;
}


/*
 *  File listview hooks
 */


__saveds __asm struct FileLineRec *file_const_func(REG(a0) struct Hook *hook,
						   REG(a2) APTR mem_pool,
						   REG(a1) char *line)
{
    register struct FileLineRec *flr;
    char *ln = line;
    LONG fsize;
    register char *dir, *name, *readme, *descr;
    int dirlen, namelen, readmelen, descrlen, nothanks;

    flr = (struct FileLineRec *)AllocMem(sizeof(struct FileLineRec), MEMF_ANY);

    sscanf(gettok(&ln, '@', &nothanks), "%lx", &flr->time);
    if (flr->time > prefs.thistime)
	prefs.thistime = flr->time;

    dir = gettok(&ln, '@', &dirlen);
    name = gettok(&ln, ';', &namelen);
    sscanf(gettok(&ln, '@', &nothanks), "%lx", &fsize);
    readme = gettok(&ln, '@', &readmelen);
    descr = gettok(&ln, '\n', &descrlen);

    flr->recsize = dirlen + namelen + 5 + readmelen + descrlen;
    flr->dir = AllocMem(flr->recsize, MEMF_ANY|MEMF_CLEAR);
    flr->name = flr->dir + dirlen;
    flr->size = flr->name + namelen;
    flr->readme = flr->size + 5;
    flr->descr = flr->readme + readmelen;

    strcpy(flr->dir, dir);
    strcpy(flr->name, name);
    flr->intsize = fsize;
    if (fsize < 1000) sprintf(flr->size, "%dB", fsize);
	else if (fsize < 1000000) sprintf(flr->size, "%dK", fsize / 1024);
	else if (fsize < 10000000) sprintf(flr->size, "%.1fM", fsize / 1048576.0);
	else if (fsize < 1000000000) sprintf(flr->size, "%dM", fsize / 1048576);
	else strcpy(flr->size, "big");
    strcpy(flr->readme, readme);
    strcpy(flr->descr, descr);

    if(flr->readme[strlen(flr->readme)-1] == ';') {
	flr->readme[strlen(flr->readme)-1] = '\0';
	flr->flags |= FLAG_README;
    }

    return(flr);
}

static struct Hook file_const_hook = {
    {NULL, NULL},
    (void *)file_const_func,
    NULL, NULL
};

__saveds __asm LONG file_dest_func(REG(a0) struct Hook *hook,
				   REG(a2) APTR mem_pool,
				   REG(a1) struct FileLineRec *flr)
{
    FreeMem(flr->dir, flr->recsize);
    FreeMem(flr, sizeof(struct FileLineRec));
    return(0);
}

static struct Hook file_dest_hook = {
    {NULL, NULL},
    (void *)file_dest_func,
    NULL, NULL
};

__saveds __asm LONG file_disp_func(REG(a0) struct Hook *hook,
				   REG(a2) char *array[],
				   REG(a1) struct FileLineRec *flinerec)
{
    if (flinerec) {
	if (HAS_README(flinerec)) array[0] = "*";
	    else array[0] = "";
	array[1] = flinerec->name;
	array[2] = flinerec->dir;
	array[3] = flinerec->size;
	array[4] = flinerec->descr;
    } else {
	array[0] = "";
	array[1] = "\033c\0338Name";
	array[2] = "\033c\0338Dir";
	array[3] = "\033c\0338Size";
	array[4] = "\033c\0338Description";
   }
   return(0);
}

static struct Hook file_disp_hook = {
     {NULL, NULL},
     (void *)file_disp_func,
     NULL, NULL
};

__saveds __asm LONG file_cmp_func(REG(a1) struct FileLineRec *line1,
				  REG(a2) struct FileLineRec *line2)
{
    switch(sorttype) {
	case 0:
	    return(stricmp(line1->name, line2->name));
	    break;

	case 1:
	    if ((line1->time - line2->time) < 0)
		return(1);
	    else if ((line1->time - line2->time) > 0)
		return(-1);
	    else return(0);
	    break;

	case 2:
	    return(stricmp(line1->dir, line2->dir));
	    break;
    }
}

static struct Hook file_cmp_hook = {
    {NULL, NULL},
    (void *)file_cmp_func,
    NULL, NULL
};


/*
 *  Host listview hooks
 */

__saveds __asm struct HostLineRec *host_const_func(REG(a0) struct Hook *hook,
						   REG(a2) APTR mem_pool,
						   REG(a1) char *line)
{
    register struct HostLineRec *hlinerec;

    hlinerec = (struct HostLineRec *)AllocMem(sizeof(struct HostLineRec), MEMF_ANY);

    if (sscanf(line, "%s %s %s", hlinerec->country, hlinerec->host, hlinerec->dir) == 3)
	return(hlinerec);
    else return(NULL);
}

static struct Hook host_const_hook = {
    {NULL, NULL},
    (void *)host_const_func,
    NULL, NULL
};

__saveds __asm LONG host_dest_func(REG(a0) struct Hook *hook,
				   REG(a2) APTR mem_pool,
				   REG(a1) struct HostLineRec *hlinerec)
{
    FreeMem(hlinerec, sizeof(struct HostLineRec));
    return(0);
}

static struct Hook host_dest_hook = {
    {NULL, NULL},
    (void *)host_dest_func,
    NULL, NULL
};

__saveds __asm LONG host_disp_func(REG(a0) struct Hook *hook,
				   REG(a2) char *array[],
				   REG(a1) struct HostLineRec *hlinerec)
{
    if (hlinerec) {
	array[0] = hlinerec->country;
	array[1] = hlinerec->host;
	array[2] = hlinerec->dir;
    } else {
	array[0] = "\033c\0338Country";
	array[1] = "\033c\0338Host";
	array[2] = "\033c\0338Directory";
    }
    return(0);
}

static struct Hook host_disp_hook = {
    {NULL, NULL},
    (void *)host_disp_func,
    NULL, NULL
};

__saveds __asm LONG host_cmp_func(REG(a1) struct HostLineRec *line1,
				  REG(a2) struct HostLineRec *line2)
{
    return(stricmp(line1->host, line2->host));
}

static struct Hook host_cmp_hook = {
    {NULL, NULL},
    (void *)host_cmp_func,
    NULL, NULL
};

main(int argc, char *argv[])
{
    BOOL running = TRUE;

/* Initialise default prefs. */
    prefs.defsort = 0;
    prefs.defview = 0;
    strcpy(prefs.getdir, "RAM:");
    strcpy(prefs.tmpdir, "RAM:");
    strcpy(prefs.defcfg, "ENV:MUIAdt.prefs");
    strcpy(prefs.uncomp, "uncompress");
    prefs.server[0] = '\0';
    prefs.lasttime = 0;
    prefs.thistime = 0;

    init();

    app = ApplicationObject,
	  MUIA_Application_Title,	"MUIAdt",
	  MUIA_Application_Version,	"$VER: MUIadt 1.0 (28.4.94)",
	  MUIA_Application_Copyright,	"© 1994 by Jem Atahan",
	  MUIA_Application_Author,	"Jem Atahan",
	  MUIA_Application_Description, "AmiNet Download Tool",
	  MUIA_Application_Base,	"MADT",

	  SubWindow, win = WindowObject,
	      MUIA_Window_ID, MAKE_ID('M','A','I','N'),
	      MUIA_Window_Title, "MUIAdt",
	      MUIA_Window_Width, MUIV_Window_Width_Visible(80),
	      MUIA_Window_Height, MUIV_Window_Height_Visible(60),
	      WindowContents, mainpage = PageGroup,
		  Child, HGroup,
		      Child, VGroup,
			  MUIA_Weight, 1,
			  Child, VSpace(0),
			  Child, KeyLabel1("\33cSort by:", 's'), Child, sort_but = KeyCycle(SortEntries, 's'),
			  Child, KeyLabel1("\33cView by:", 'v'), Child, view_but = KeyCycle(ViewEntries, 'v'),
			  Child, Label1("\n\33cActions"),
			  Child, read_but = KeyButton("Readme", 'r'),
			  Child, name_but = PopobjectObject,
			      MUIA_Popstring_String, Label1(""),
			      MUIA_Popstring_Button, KeyButton("Name", 'n'),
			      MUIA_Popobject_Object, VGroup,
				  GroupFrame,
				  Child, KeyLabel1("\33cSearch for:", 'r'),
				  Child, search_str = KeyString("", 256, 'r'),
				  Child, search_next = KeyButton("Next", 'x'),
				  Child, search_can = KeyButton("Cancel", 'a'),
				  End,
			      End,
			  Child, get_but = KeyButton("Download", 'd'),
			  Child, host_but = KeyButton("Host", 'h'),
			  Child, VSpace(0),
			  Child, cfg_but = KeyButton("Config", 'c'),
			  Child, VSpace(0),
			  Child, quit_but = KeyButton("Quit", 'q'),
			  Child, VSpace(0),
			  End,
		      Child, VGroup,
			  MUIA_Weight, 100,
			  Child, lvpage = PageGroup,
			      Child, recentlv = ListviewObject,
				  MUIA_Listview_MultiSelect, TRUE,
				  MUIA_Listview_DoubleClick, TRUE,
				  MUIA_Listview_List, ListObject,
				      InputListFrame,
				      MUIA_List_Format, "W=1,W=200,W=50,W=10 P=\033r,W=600",
				      MUIA_List_Title, TRUE,
				      MUIA_List_ConstructHook, &file_const_hook,
				      MUIA_List_DestructHook, &file_dest_hook,
				      MUIA_List_CompareHook, &file_cmp_hook,
				      MUIA_List_DisplayHook, &file_disp_hook,
				      End,
				  End,
			      Child, shortlv = ListviewObject,
				  MUIA_Listview_MultiSelect, TRUE,
				  MUIA_Listview_DoubleClick, TRUE,
				  MUIA_Listview_List, ListObject,
				      InputListFrame,
				      MUIA_List_Format, "W=1,W=200,W=50,W=10 P=\033r,W=600",
				      MUIA_List_Title, TRUE,
				      MUIA_List_ConstructHook, &file_const_hook,
				      MUIA_List_DestructHook, &file_dest_hook,
				      MUIA_List_CompareHook, &file_cmp_hook,
				      MUIA_List_DisplayHook, &file_disp_hook,
				      End,
				  End,
			      Child, taggedlv = ListviewObject,
				  MUIA_Listview_Input, FALSE,
				  MUIA_Listview_List, ListObject,
				      InputListFrame,
				      MUIA_List_Format, "W=1,W=200,W=50,W=10 P=\033r,W=600",
				      MUIA_List_Title, TRUE,
				      MUIA_List_ConstructHook, &file_const_hook,
				      MUIA_List_DestructHook, &file_dest_hook,
				      MUIA_List_CompareHook, &file_cmp_hook,
				      MUIA_List_DisplayHook, &file_disp_hook,
				      End,
				  End,
			      Child, newlv = ListviewObject,
				  MUIA_Listview_MultiSelect, TRUE,
				  MUIA_Listview_DoubleClick, TRUE,
				  MUIA_Listview_List, ListObject,
				      InputListFrame,
				      MUIA_List_Format, "W=1,W=200,W=50,W=10 P=\033r,W=600",
				      MUIA_List_Title, TRUE,
				      MUIA_List_ConstructHook, &file_const_hook,
				      MUIA_List_DestructHook, &file_dest_hook,
				      MUIA_List_CompareHook, &file_cmp_hook,
				      MUIA_List_DisplayHook, &file_disp_hook,
				      End,
				  End,
			      End,
			  Child, HGroup,
			      Child, files_status = TextObject,
				  TextFrame,
				  MUIA_Background, MUII_TextBack,
				  MUIA_Text_PreParse, "\033c\0338",
				  End,
			      Child, HSpace(13),
			      End,
			  End,
		      End,
		  Child, VGroup,
		     Child, TextObject,
			 TextFrame,
			  MUIA_Background, MUII_TextBack,
			  MUIA_Text_PreParse, "\033c\033b\0338",
			  MUIA_Text_Contents, "Chose a host",
			  End,
		      Child, hostslv = ListviewObject,
			  MUIA_Listview_MultiSelect, FALSE,
			  MUIA_Listview_DoubleClick, TRUE,
			  MUIA_Listview_List, ListObject,
			      InputListFrame,
			      MUIA_List_Format, ",,",
			      MUIA_List_Title, TRUE,
			      MUIA_List_ConstructHook, &host_const_hook,
			      MUIA_List_DestructHook, &host_dest_hook,
			      MUIA_List_CompareHook, &host_cmp_hook,
			      MUIA_List_DisplayHook, &host_disp_hook,
			      MUIA_List_SourceArray, HostList,
			      End,
			  End,
		      Child, HGroup,
			  Child, host_cancel_but = KeyButton("Cancel", 'c'),
			  Child, host_status = TextObject,
			      MUIA_Weight, 800,
			      TextFrame,
			      MUIA_Background, MUII_TextBack,
			      MUIA_Text_PreParse, "\033c\0338",
			      MUIA_Text_Contents, "Not Connected",
			      End,
			  Child, HSpace(13),
			  End,
		      End,
		  Child, VGroup,
		      Child, TextObject,
			 TextFrame,
			  MUIA_Background, MUII_TextBack,
			  MUIA_Text_PreParse, "\033c\033b\0338",
			  MUIA_Text_Contents, "Readme file",
			  End,
		      Child, ListviewObject,
			  MUIA_Weight, 200,
			  MUIA_Listview_Input, FALSE,
			  MUIA_Listview_List, readtext = FloattextObject,
			      MUIA_Frame, MUIV_Frame_ReadList,
			      MUIA_Background, MUII_TextBack,
			      MUIA_Floattext_TabSize, 4,
			      MUIA_Floattext_Justify, TRUE,
			      End,
			  End,
		      Child, HGroup,
			  Child, read_next_but = KeyButton("Next", 'x'),
			  Child, read_can_but = KeyButton("Cancel", 'c'),
			  Child, HSpace(13),
			  End,
		      End,
		  Child, VGroup,
		      Child, TextObject,
			  TextFrame,
			  MUIA_Background, MUII_TextBack,
			  MUIA_Text_PreParse, "\033c\033b\0338",
			  MUIA_Text_Contents, "Downloading",
			  End,
		      Child, getlv = ListviewObject,
			  MUIA_Listview_Input, FALSE,
			  MUIA_Listview_DoubleClick, FALSE,
			  MUIA_Listview_List, ListObject,
			      InputListFrame,
			      MUIA_List_Format, "W=1,W=200,W=50,W=10 P=\033r,W=600",
			      MUIA_List_Title, TRUE,
			      MUIA_List_ConstructHook, &file_const_hook,
			      MUIA_List_DestructHook, &file_dest_hook,
			      MUIA_List_CompareHook, &file_cmp_hook,
			      MUIA_List_DisplayHook, &file_disp_hook,
			      End,
			  End,
		      Child, HGroup,
			  Child, VGroup,
			      MUIA_Weight, 50,
			      Child, get_abort_but = KeyButton("Abort", 'a'),
			      Child, VSpace(13),
			      End,
			  Child, VGroup,
			      GroupSpacing(1),
			      MUIA_Weight, 400,
			      Child, get_gauge = GaugeObject,
				  GaugeFrame,
				  MUIA_Gauge_Horiz, TRUE,
				  End,
			      Child, ScaleObject,
				  MUIA_Scale_Horiz, TRUE,
				  End,
			      End,
			  Child, HSpace(13),
			  End,
		      End,
		  Child, HGroup,
		      Child, HSpace(0),
		      Child, VGroup,
			  Child, VSpace(0),
			  Child, GroupObject,
			      GroupFrame,
			      Child, HGroup, Child, KeyLabel1("Default Sort by:", 's'), Child, def_sort_but = KeyCycle(SortEntries, 's'), End,
			      Child, HGroup, Child, KeyLabel1("Default View by:", 'v'), Child, def_view_but = KeyCycle(ViewEntries, 'v'), End,
			      Child, HGroup,
				  Child, KeyLabel1("Download Directory:", 'd'),
				  Child, def_getdir = PopaslObject,
				      MUIA_Popstring_String, KeyString("", 256, 'd'),
				      MUIA_Popstring_Button, PopButton(MUII_PopDrawer),
				      ASLFR_TitleText  , "Please select a drawer...",
				      ASLFR_DrawersOnly, TRUE,
				      End,
				  End,
			      Child, HGroup,
				  Child, KeyLabel1("Temporary Directory:", 't'),
				  Child, def_tmpdir = PopaslObject,
				      MUIA_Popstring_String, KeyString("", 256, 't'),
				      MUIA_Popstring_Button, PopButton(MUII_PopDrawer),
				      ASLFR_TitleText  , "Please select a drawer...",
				      ASLFR_DrawersOnly, TRUE,
				      End,
				  End,
			      Child, HGroup,
				  Child, KeyLabel1("Uncompress Command:", 'u'),
				  Child, def_uncomp = KeyString("", 256, 'u'),
				  End,
			      Child, HGroup, Child, HSpace(0), Child, def_done = KeyButton("Done", 'o'), Child, HSpace(0), End,
			      End,
			  Child, VSpace(0),
			  End,
		      Child, HSpace(0),
		      End,
		  End,
	      End,
	  End;
    if (!app) fail(app, "Couldn't create application.");

/* Respond to option button presses */
    DoMethod(sort_but, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, app, 2, MUIM_Application_ReturnID, ID_Sort);
    DoMethod(view_but, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, app, 2, MUIM_Application_ReturnID, ID_View);
    DoMethod(read_but, MUIM_Notify, MUIA_Pressed, FALSE, app, 2, MUIM_Application_ReturnID, ID_Readme);
    DoMethod(get_but, MUIM_Notify, MUIA_Pressed, FALSE, app, 2, MUIM_Application_ReturnID, ID_Get);
    DoMethod(host_but, MUIM_Notify, MUIA_Pressed, FALSE, mainpage, 3, MUIM_Set, MUIA_Group_ActivePage, 1);
    DoMethod(cfg_but, MUIM_Notify, MUIA_Pressed, FALSE, mainpage, 3, MUIM_Set, MUIA_Group_ActivePage, 4);
    DoMethod(quit_but, MUIM_Notify, MUIA_Pressed, FALSE, app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

/* Respond to buttons in the name search popup */
    DoMethod(search_str, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, app, 2, MUIM_Application_ReturnID, ID_Name);
    DoMethod(search_next, MUIM_Notify, MUIA_Pressed, FALSE, app, 2, MUIM_Application_ReturnID, ID_Name);
    DoMethod(search_can, MUIM_Notify, MUIA_Pressed, FALSE, name_but, 2, MUIM_Popstring_Close, TRUE);

/* Respond to double clicking in one of the file listviews */
    DoMethod(recentlv, MUIM_Notify, MUIA_Listview_DoubleClick,TRUE, app, 2, MUIM_Application_ReturnID, ID_Readme);
    DoMethod(shortlv, MUIM_Notify, MUIA_Listview_DoubleClick,TRUE, app, 2, MUIM_Application_ReturnID, ID_Readme);
    DoMethod(newlv, MUIM_Notify, MUIA_Listview_DoubleClick,TRUE, app, 2, MUIM_Application_ReturnID, ID_Readme);

/* Respond to the readme page buttons */
    DoMethod(read_next_but, MUIM_Notify, MUIA_Pressed, FALSE, app, 2, MUIM_Application_ReturnID, ID_ReadNext);
    DoMethod(read_can_but, MUIM_Notify, MUIA_Pressed, FALSE, mainpage, 3, MUIM_Set, MUIA_Group_ActivePage, 0);

/* Respond to the download abort button */
    DoMethod(get_abort_but, MUIM_Notify, MUIA_Pressed, FALSE, app, 2, MUIM_Application_ReturnID, ID_GetAbort);
/**/DoMethod(get_abort_but, MUIM_Notify, MUIA_Pressed, FALSE, mainpage, 3, MUIM_Set, MUIA_Group_ActivePage, 0);

/* Respond to events in the hosts page */
    DoMethod(hostslv, MUIM_Notify, MUIA_Listview_DoubleClick,TRUE, app, 2, MUIM_Application_ReturnID, ID_HostsDC);
    DoMethod(host_cancel_but, MUIM_Notify, MUIA_Pressed, FALSE, mainpage, 3, MUIM_Set, MUIA_Group_ActivePage, 0);

/* Respond to the config page buttons */
    DoMethod(def_done, MUIM_Notify, MUIA_Pressed, FALSE, app, 2, MUIM_Application_ReturnID, ID_Config);

/* Get Prefs */
    if (read_prefs()) set(files_status, MUIA_Text_Contents, "Welcome new user.");
    else set(files_status, MUIA_Text_Contents, "Welcome.");

/* Start the window up then */
    DoMethod(win, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
    set(win, MUIA_Window_Open, TRUE);

    while (running) {
	ULONG signal;

	switch (DoMethod(app, MUIM_Application_Input, &signal))
	{
	    case MUIV_Application_ReturnID_Quit:
		running = FALSE;
		break;

	    case ID_Sort: {
		int page;

		get(sort_but, MUIA_Cycle_Active, &sorttype);
		get(lvpage, MUIA_Group_ActivePage, &page);
		switch(page) {
		    case 0:
			DoMethod(recentlv, MUIM_List_Sort);
			break;
		    case 1:
			DoMethod(shortlv, MUIM_List_Sort);
			break;
		    case 2:
			DoMethod(taggedlv, MUIM_List_Sort);
			break;
		}
		break;
	    }

	    case ID_View:
		if (connected) {
		    get(view_but, MUIA_Cycle_Active, &viewtype);
		    switch(viewtype) {
			case 0:
			    show_new();
			    break;

			case 1:
			    show_recent();
			    break;

			case 2:
			    show_short();
			    break;

			case 3:
			    show_tagged();
			    break;
		    }
		} else set(files_status, MUIA_Text_Contents, "Not Connected");
		break;

	    case ID_Readme: {
		APTR curntlv;
		struct FileLineRec *flr;

		readpos = -1;
		curntlv = currentlv();
		DoMethod(curntlv, MUIM_List_NextSelected, &readpos);
		if (readpos == -1) break;
		DoMethod(curntlv, MUIM_List_GetEntry, readpos, &flr);
		if (HAS_README(flr)) readme(flr->dir, flr->readme);
		break;
	    }

	    case ID_ReadNext: {
		APTR curntlv;
		struct FileLineRec *flr;

		curntlv = currentlv();
		DoMethod(curntlv, MUIM_List_NextSelected, &readpos);
		if (readpos == -1) {
		    set(mainpage, MUIA_Group_ActivePage, 0);
		    break;
		}
		DoMethod(curntlv, MUIM_List_GetEntry, readpos, &flr);
		if (HAS_README(flr)) readme(flr->dir, flr->readme);
		break;
	    }

	    case ID_Name: {
		LONG pos;
		struct FileLineRec *flr;
		char *str;
		BOOL stop = FALSE;
		int len;

		get(search_str, MUIA_String_Contents, &str);
		len = strlen(str);
		get(currentlv(), MUIA_List_Active, &pos);
		if (pos < 0) pos = 0;
		else pos++;
		for(;!stop;pos++) {
		    DoMethod(currentlv(), MUIM_List_GetEntry, pos, &flr);
		    if (!flr) break;
		    if (!strnicmp(str, flr->name, len)) {
			set(currentlv(), MUIA_List_Active, pos);
			stop=TRUE;
		    }
		}
		break;
	    }

	    case ID_Get: {
		LONG page, pos=-1, pos2;
		struct FileLineRec *flr, *flr2;
		BOOL stop=FALSE;
		int result=0;

		if (connected) {
		    DoMethod(currentlv(), MUIM_List_NextSelected, &pos);
		    if (pos == -1) break;
		    DoMethod(getlv, MUIM_List_Clear, NULL);
		    get(lvpage, MUIA_Group_ActivePage, &page);
		    switch(page) {
			case 0:
			    copy_tagged(getlv); break;
			case 1:
			    copy_tagged(getlv); break;
			case 2:
			    copy_all(getlv); break;
			case 3:
			    copy_tagged(getlv); break;
		    }
		    set(mainpage, MUIA_Group_ActivePage, 3);

		    pos = 0;
		    while(result != 2) {
			char file[256], local[256];

			DoMethod(getlv, MUIM_List_GetEntry, pos, &flr);
			if (!flr) break;
			joinpaths(file, flr->dir, flr->name);
			joinpaths(local, prefs.getdir, flr->name);
			result = get_file(file, local, flr->intsize);
			if (!result) {
			    stop = FALSE;
			    pos2 = -1;
			    while(!stop) {
				DoMethod(currentlv(), MUIM_List_NextSelected, &pos2);
				if (pos2 == -1) break;
				DoMethod(currentlv(), MUIM_List_GetEntry, pos2, &flr2);
				if (flr2->time == flr->time) {
				    DoMethod(currentlv(), MUIM_List_Select, pos2, MUIV_List_Select_Off, NULL);
				    stop = TRUE;
				}
			    }
			    DoMethod(getlv, MUIM_List_Remove, pos);
			}
			else {
/*			      printf("error getting %s\n", file); */
			    pos++;
			}
		    }
		    /* Copy remaining entries back to lvpage */
		    set(mainpage, MUIA_Group_ActivePage, 0);
		}
		break;
	    }

	    case ID_HostsDC: {
		char *error;
		LONG pos;
		struct HostLineRec *hlr;

		/* Connect to host, login and dl recent */
		gotrecent = gotshort = gotnew = FALSE;
		DoMethod(recentlv, MUIM_List_Clear, NULL);
		DoMethod(newlv, MUIM_List_Clear, NULL);
		DoMethod(shortlv, MUIM_List_Clear, NULL);
		{
		    char file[256];
		    joinpaths(file, prefs.tmpdir, "RECENT.adt");
		    remove(file);
		    joinpaths(file, prefs.tmpdir, "SHORT.adt");
		    remove(file);
		}

		DoMethod(hostslv, MUIM_List_NextSelected, &pos);
		DoMethod(hostslv, MUIM_List_GetEntry, pos, &hlr);
		set(host_status, MUIA_Text_Contents, "Connecting");
		if (!(error = ftp_connect(hlr->host, hlr->dir))) {
		    set(host_status, MUIA_Text_Contents, "Connected");
		    set(mainpage, MUIA_Group_ActivePage, 0);
		    DoMethod(app, MUIM_Application_ReturnID, ID_View);
		    set(mainpage, MUIA_Group_ActivePage, 0);
		    host = hlr;
		} else if (error[0] == '*') {
		    set(host_status, MUIA_Text_Contents, error+1);
		    fail(app, error+1);
		} else set(host_status, MUIA_Text_Contents, error);
		break;
	    }

	    case ID_Config: {
		char *tmp;
		get(def_sort_but, MUIA_Cycle_Active, &prefs.defsort);
		get(def_view_but, MUIA_Cycle_Active, &prefs.defview);
		get(def_getdir, MUIA_String_Contents, &tmp);
		strcpy(prefs.getdir, tmp);
		get(def_tmpdir, MUIA_String_Contents, &tmp);
		strcpy(prefs.tmpdir, tmp);
		get(def_uncomp, MUIA_String_Contents, &tmp);
		strcpy(prefs.uncomp, tmp);
		set(mainpage, MUIA_Group_ActivePage, 0);
		break;
	    }

	}
	if (signal) Wait(signal);
    }
    {
	char file[256];
	joinpaths(file, prefs.tmpdir, "RECENT.adt");
	remove(file);
	joinpaths(file, prefs.tmpdir, "SHORT.adt");
	remove(file);
    }
    if (write_prefs(prefs.defcfg)) MUI_Request(app,win,0,NULL,"OK", "Can't save prefs.");

/* Save to envarc: if defcfg is env: */
    if (!strnicmp(prefs.defcfg, "env:", 4)) {
	char file[256];

	sprintf(file, "envarc:%s", prefs.defcfg + 4);
	if (write_prefs(file)) MUI_Request(app,win,0,NULL,"OK", "Can't save prefs to ENVARC:");
    }

    fail(app, NULL);
}


/*------------- config file format ----------------
# comment
server = <default server>
prevcall = <time of last call>
getdir = <download directory>
tmpdir = <temporary directory>
defsort = <default sort method (integer)>
defview = <default view method (integer)>
uncompress = <uncompress command>
*/

int read_prefs()
{
    FILE *fp;
    char line[256], *tag;
    int length, retval;

    if (fp = fopen(prefs.defcfg, "r")) {
	retval = 0;
	while (fgets(line, 256, fp)) {
	    if (line[0] != '#') {
		length = strlen(line);
		if (line[length-1] == '\n') line[length-1] = '\0';
		for (tag=line; *tag!='=' && *tag!='\0'; tag++);
		tag++;
		for (; *tag==' '; tag++);
		if (*tag == '\0') continue;

		if (!strnicmp(line, "server", 6))
		    strcpy(prefs.server, tag);
		if (!strnicmp(line, "prevcall", 8))
		    sscanf(tag, "%lx", &prefs.lasttime);
		if (!strnicmp(line, "getdir", 6))
		    strcpy(prefs.getdir, tag);
		if (!strnicmp(line, "tmpdir", 6))
		    strcpy(prefs.tmpdir, tag);
		if (!strnicmp(line, "defsort", 7))
		    sscanf(tag, "%lx", &prefs.defsort);
		if (!strnicmp(line, "defview", 7))
		    sscanf(tag, "%lx", &prefs.defview);
		if (!strnicmp(line, "uncompress", 10))
		    strcpy(prefs.uncomp, tag);
	    }
	}
	fclose(fp);
    } else retval = 1;
    prefs.thistime = prefs.lasttime;
    set(sort_but, MUIA_Cycle_Active, prefs.defsort);
    set(view_but, MUIA_Cycle_Active, prefs.defview);
    set(def_sort_but, MUIA_Cycle_Active, prefs.defsort);
    set(def_view_but, MUIA_Cycle_Active, prefs.defview);
    set(def_getdir, MUIA_String_Contents, prefs.getdir);
    set(def_tmpdir, MUIA_String_Contents, prefs.tmpdir);
    set(def_uncomp, MUIA_String_Contents, prefs.uncomp);
    return(retval);
}

int write_prefs(char *file)
{
    FILE *fp;

    if (!(fp = fopen(file, "w"))) return(1);
    fputs("# This is a MUIAdt config file\n", fp);
    fprintf(fp, "server = %s\n", prefs.server);
    fprintf(fp, "prevcall = %lx\n", prefs.thistime);
    fprintf(fp, "getdir = %s\n", prefs.getdir);
    fprintf(fp, "tmpdir = %s\n", prefs.tmpdir);
    fprintf(fp, "defsort = %lx\n", prefs.defsort);
    fprintf(fp, "defview = %lx\n", prefs.defview);
    fprintf(fp, "uncompress = %s\n", prefs.uncomp);
    fclose(fp);
    return(0);
}

void show_new()
{
    LONG pos, numfiles;
    struct FileLineRec *flr;
    char line[256], temp[20], com[256];

    set(newlv, MUIA_List_Quiet, TRUE);
    if (!gotrecent) {
	set(recentlv, MUIA_List_Quiet, TRUE);
	joinpaths(line, prefs.tmpdir, "RECENT.adt.Z");
	set(files_status, MUIA_Text_Contents, "Downloading RECENT list");
	if (!get_file("info/adt/RECENT.adt.Z", line, 0)) {
	    sprintf(com, "%s \"%s\"", prefs.uncomp, line);
	    system(com);
	    line[strlen(line)-2] = '\0';
	    if(get_parse(line, recentlv) == 0) gotrecent=TRUE;
	} else set(files_status, MUIA_Text_Contents, "Error downloading RECENT list");
    }
    if (gotrecent) {
	for(pos=0;;pos++) {
	    DoMethod(recentlv, MUIM_List_GetEntry, pos, &flr);
	    if (!flr) break;
	    if (flr->time > prefs.lasttime) {
		sprintf(line, "%lx@%s@%s;%lx@%s;@%s\n", flr->time, flr->dir, flr->name, flr->intsize, flr->readme, flr->descr);
		DoMethod(newlv, MUIM_List_InsertSingle, line, MUIV_List_Insert_Bottom);
	    }
	}
	DoMethod(newlv, MUIM_List_Sort, NULL);
	clone_tagged(newlv);
	set(newlv, MUIA_List_Quiet, FALSE);
	set(lvpage, MUIA_Group_ActivePage, 3);
	set(recentlv, MUIA_List_Quiet, FALSE);

/*    set(win, MUIA_Window_DefaultObject, newlv); */

	get(newlv, MUIA_List_Entries, &numfiles);
	sprintf(temp, "New files (%d)", numfiles);
	set(files_status, MUIA_Text_Contents, temp);
    }
    else set(newlv, MUIA_List_Quiet, FALSE);
}

void show_recent()
{
    LONG numfiles;
    char temp[20];

    set(recentlv, MUIA_List_Quiet, TRUE);
    if (!gotrecent) {
	char local[256], com[256];
	joinpaths(local, prefs.tmpdir, "RECENT.adt.Z");
	set(files_status, MUIA_Text_Contents, "Downloading RECENT list");
	if (!get_file("info/adt/RECENT.adt.Z", local, 0)) {
	    sprintf(com, "%s \"%s\"", prefs.uncomp, local);
	    system(com);
	    local[strlen(local)-2] = '\0';
	    if(!get_parse(local, recentlv)) gotrecent=TRUE;
	} else set(files_status, MUIA_Text_Contents, "Error downloading RECENT list");
    }
    if (gotrecent) {
	DoMethod(recentlv, MUIM_List_Sort, NULL);
	clone_tagged(recentlv);
	set(recentlv, MUIA_List_Quiet, FALSE);
	set(lvpage, MUIA_Group_ActivePage, 0);

/*    set(win, MUIA_Window_DefaultObject, recentlv); */

	get(recentlv, MUIA_List_Entries, &numfiles);
	sprintf(temp, "Recent files (%d)", numfiles);
	set(files_status, MUIA_Text_Contents, temp);
    }
    else set(recentlv, MUIA_List_Quiet, FALSE);
}

void show_short()
{
    LONG numfiles;
    char temp[20];

    set(shortlv, MUIA_List_Quiet, TRUE);
    if (!gotshort) {
	char local[256], com[256];
	joinpaths(local, prefs.tmpdir, "SHORT.adt.Z");
	set(files_status, MUIA_Text_Contents, "Downloading LONG list");
	if (!get_file("info/adt/SHORT.adt.Z", local, 0)) {
	    sprintf(com, "%s \"%s\"", prefs.uncomp, local);
	    system(com);
	    local[strlen(local)-2] = '\0';
	    if(!get_parse(local, shortlv)) gotshort=TRUE;
	} else set(files_status, MUIA_Text_Contents, "Error downloading LONG list");
    }
    if (gotshort) {
	DoMethod(shortlv, MUIM_List_Sort, NULL);
	clone_tagged(recentlv);
	set(shortlv, MUIA_List_Quiet, FALSE);
	set(lvpage, MUIA_Group_ActivePage, 1);

/*    set(win, MUIA_Window_DefaultObject, shortlv); */

	get(shortlv, MUIA_List_Entries, &numfiles);
	sprintf(temp, "All files (%d)", numfiles);
	set(files_status, MUIA_Text_Contents, temp);
    }
    else set(shortlv, MUIA_List_Quiet, FALSE);
}

void show_tagged()
{
    char temp[40];
    LONG numfiles;

    set(taggedlv, MUIA_List_Quiet, TRUE);
    DoMethod(taggedlv, MUIM_List_Clear, NULL);
    copy_tagged(taggedlv);
    DoMethod(taggedlv, MUIM_List_Sort, NULL);
    set(taggedlv, MUIA_List_Quiet, FALSE);
    set(lvpage, MUIA_Group_ActivePage, 2);

/*    set(win, MUIA_Window_DefaultObject, taggedlv); */

    get(taggedlv, MUIA_List_Entries, &numfiles);
    sprintf(temp, "Tagged files (%d)", numfiles);
    set(files_status, MUIA_Text_Contents, temp);
}

void readme(char *dir, char *name)
{
    char fullpath[256], local[256], *buffer;
    int fh;
    struct stat st;

/* download readme and put it in the readme page */
    joinpaths(fullpath, dir, name);
    joinpaths(local, prefs.tmpdir, name);

    if (!get_file(fullpath, local, 0) && (fh = open(local, O_RDONLY))) {
	stat(local, &st);
	buffer = malloc(st.st_size);

	*buffer = '\0';
	read(fh, buffer, st.st_size);
	set(readtext, MUIA_Floattext_Text, buffer);
	set(mainpage, MUIA_Group_ActivePage, 2);

	close(fh);
	free(buffer);
    }
    remove(local);
}

APTR currentlv()
{
    LONG page;

    get(lvpage, MUIA_Group_ActivePage, &page);
    switch(page) {
	case 0:
	    return(recentlv); break;
	case 1:
	    return(shortlv); break;
	case 2:
	    return(taggedlv); break;
	case 3:
	    return(newlv); break;
    }
}

int get_file(char *dir, char *file, int size)
{
    return(ftp_get(dir, size, file));
}

void clone_tagged(APTR destlv)
{
    APTR curntlv;
    LONG pos=-1;
    struct FileLineRec *srcflr, *destflr;

    curntlv = currentlv();
    DoMethod(destlv, MUIM_List_Select, MUIV_List_Select_All, MUIV_List_Select_Off, NULL);
    for (;;) {
	DoMethod(curntlv, MUIM_List_NextSelected, &pos);
	if (pos == -1) break;
	DoMethod(curntlv, MUIM_List_GetEntry, pos, &srcflr);
	DoMethod(destlv, MUIM_List_GetEntry, pos, &destflr);
	if (destflr && (srcflr->time == destflr->time)) {
	    DoMethod(destlv, MUIM_List_Select, pos, MUIV_List_Select_On, NULL);
	}
    }
}

void copy_tagged(APTR destlv)
{
    APTR curntlv;
    LONG pos=-1;
    struct FileLineRec *flr;
    char line[256];

    curntlv = currentlv();
    for (;;) {
	DoMethod(curntlv, MUIM_List_NextSelected, &pos);
	if (pos == -1) break;
	DoMethod(curntlv, MUIM_List_GetEntry, pos, &flr);
	sprintf(line, "%lx@%s@%s;%lx@%s;@%s\n", flr->time, flr->dir, flr->name, flr->intsize, flr->readme, flr->descr);
	DoMethod(destlv, MUIM_List_InsertSingle, line, MUIV_List_Insert_Bottom);
    }
}

void copy_all(APTR destlv)
{
    APTR curntlv;
    LONG pos;
    struct FileLineRec *flr;
    char line[256];

    curntlv =	currentlv();
    for (pos=0;;pos++){
	DoMethod(curntlv, MUIM_List_GetEntry, pos, &flr);
	if (!flr) break;
	sprintf(line, "%lx@%s@%s;%lx@%s;@%s\n", flr->time, flr->dir, flr->name, flr->intsize, flr->readme, flr->descr);
	DoMethod(destlv, MUIM_List_InsertSingle, line, MUIV_List_Insert_Bottom);
    }
}

int get_parse(char *file, APTR lv)
{
    FILE *fp;
    char temp[40];
    int version=0, err=0;

    DoMethod(lv, MUIM_List_Clear, NULL);
    set(files_status, MUIA_Text_Contents, "Parsing");
    if (!(fp = fopen(file, "r"))) {
	set(files_status, MUIA_Text_Contents, "Error: file disapeared");
	return(1);
    }

    if (fscanf(fp, "adt-v%d\n", &version) != 1) {
	fclose(fp);
	sprintf(temp, "Error parsing %s list", file);
	set(files_status, MUIA_Text_Contents, temp);
	return(1);
    }

/*    switch(version) {
	case 1: */
	    err = adt_parse_v1(fp, lv);
/*	      break;
    } */

    fclose(fp);
    return(err);
}


int adt_parse_v1(FILE *in, APTR lv)
{
    char lnbuf[256];

    while (fgets(lnbuf, 256, in))
	DoMethod(lv, MUIM_List_InsertSingle, lnbuf, MUIV_List_Insert_Bottom);
    return(0);
}

