/* * This source file is Copyright 1995 by Evan Scott. * All rights reserved. * Permission is granted to distribute this file provided no * fees beyond distribution costs are levied. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "evtypes.h" #include "verify.h" #include "tcp.h" #include "site.h" #include "ftp.h" #include "local.h" #include "request.h" #define DECLARE_GLOBALS_HERE 1 #include "globals.h" #include "strings.h" struct DosPacket *fh_listen(void); void fh_ignore(void); boolean launch_tcp_handler(void); boolean launch_local(void); void shutdown_tcp_handler(void); void shutdown_local(void); boolean open_libraries(void); void close_libraries(void); boolean make_gims(void); void free_gims(void); void startup_error(b8 *s); boolean get_anon_login(void); boolean create_volume(void); void destroy_volume(void); boolean launch_status(void); void shutdown_status(void); void setup_strings(void); void cleanup_strings(void); void __saveds start(void) { struct Process *me; struct Message *msg; struct DosPacket *dp; struct MsgPort *reply; struct DateTime dtime; b8 temp[15]; SysBase = *(struct ExecBase **)4; me = (struct Process *)FindTask(0l); ftp_port = &me->pr_MsgPort; WaitPort(ftp_port); /* wait for startup packet */ msg = GetMsg(ftp_port); dp = (struct DosPacket *)msg->mn_Node.ln_Name; reply = dp->dp_Port; dp->dp_Port = ftp_port; ftp_device = (struct DosList *)(dp->dp_Arg3 << 2); ftp_device->dol_Task = ftp_port; /* fill in our message port */ /* get down to initializing everything */ sites = nil; orphaned_locks = nil; if (open_libraries()) { ftpdir_lock = Lock("FTPMountDir:", SHARED_LOCK); if (ftpdir_lock) { UnLock(CurrentDir(ftpdir_lock)); UnLock(SetProgramDir(ftpdir_lock)); /* setup PROGDIR: so we can open the catalog asap */ setup_strings(); mem_tracking_on(); DateStamp(&dtime.dat_Stamp); dtime.dat_StrDate = temp; dtime.dat_StrDay = nil; dtime.dat_StrTime = nil; dtime.dat_Flags = 0; dtime.dat_Format = FORMAT_INT; DateToStr(&dtime); year = atoi(temp); if (year >= 78) year += 1900; else year += 2000; if (get_anon_login()) { if (make_gims()) { if (launch_tcp_handler()) { if (launch_local()) { ftphosts_lock = Lock(strings[MSG_HOSTS], SHARED_LOCK); if (ftphosts_lock) { if (launch_status()) { if (create_volume()) { /* initialization is complete */ dp->dp_Res1 = DOSTRUE; dp->dp_Res2 = 0; PutMsg(reply, dp->dp_Link); dp = fh_listen(); /* only comes back on a DIE */ shutdown_sites(); shutdown_status(); shutdown_local(); shutdown_tcp_handler(); UnLock(ftphosts_lock); UnLock(ftpdir_lock); free_gims(); if (anon_login) deallocate(anon_login, V_cstr); destroy_volume(); check_memory(); close_libraries(); if (dp) { dp->dp_Res1 = DOSTRUE; dp->dp_Res2 = 0; reply = dp->dp_Port; dp->dp_Port = ftp_port; PutMsg(reply, dp->dp_Link); } fh_ignore(); /* never comes back */ } else dp->dp_Res2 = ERROR_NO_FREE_STORE; shutdown_status(); } else dp->dp_Res2 = ERROR_NO_FREE_STORE; UnLock(ftphosts_lock); } else { startup_error(strings[MSG_CANT_FIND_HOSTS]); dp->dp_Res2 = ERROR_DIR_NOT_FOUND; } shutdown_local(); } else dp->dp_Res2 = ERROR_NO_FREE_STORE; shutdown_tcp_handler(); } else dp->dp_Res2 = ERROR_NO_FREE_STORE; free_gims(); } else dp->dp_Res2 = ERROR_NO_FREE_STORE; if (anon_login) deallocate(anon_login, V_cstr); } else dp->dp_Res2 = ERROR_REQUIRED_ARG_MISSING; check_memory(); cleanup_strings(); SetProgramDir(0); CurrentDir(0); UnLock(ftpdir_lock); } else dp->dp_Res2 = ERROR_DIR_NOT_FOUND; close_libraries(); } else dp->dp_Res2 = ERROR_INVALID_RESIDENT_LIBRARY; ftp_device->dol_Task = 0; dp->dp_Res1 = DOSFALSE; Forbid(); /* this is so they can't unloadseg us until we have finished */ PutMsg(reply, dp->dp_Link); return; } /* has to be after the startup function */ #include "verify_code.h" void startup_error(b8 *s) { struct EasyStruct es; es.es_StructSize = sizeof(struct EasyStruct); es.es_Flags = 0; es.es_Title = strings[MSG_FTPM_STARTUP_ERROR]; es.es_GadgetFormat = strings[MSG_OK]; es.es_TextFormat = s; EasyRequest(nil, &es, nil); } boolean launch_tcp_handler(void) { struct Process *child; tcpmessage *tm; unique_name(FindTask(0), ": FTPMount", unique_buffer); startup_sync = CreatePort(unique_buffer, 0); if (startup_sync) { child = CreateNewProcTags( NP_Entry, tcp_handler, NP_Arguments, unique_buffer, NP_Name, strings[MSG_TCP_HANDLER], NP_StackSize, 6000, TAG_END, 0 ); if (child) { Wait(1 << startup_sync->mp_SigBit); tm = (tcpmessage *)GetMsg(startup_sync); if (tm) { verify(tm, V_tcpmessage); if (tm->result) { tcp = tm->data; ReplyMsg(&tm->header); WaitPort(startup_sync); prime = (tcpmessage *)GetMsg(startup_sync); /* ok! off we trundle */ prime->command = TCP_SERVICE; prime->data = strings[MSG_SERVICE]; PutMsg(tcp, &prime->header); WaitPort(startup_sync); GetMsg(startup_sync); if (prime->result) { ftp_port_number = prime->port.w; } else { ftp_port_number = 0; /* fill it in at connect time */ } return true; } ReplyMsg(&tm->header); /* whether child is still alive here??? */ } } DeletePort(startup_sync); } startup_error(strings[MSG_CANT_LAUNCH_TCP]); return false; } void shutdown_tcp_handler(void) { prime->command = TCP_DIE; prime->header.mn_ReplyPort = startup_sync; PutMsg(tcp, &prime->header); Wait(1 << startup_sync->mp_SigBit); /* Wait til the child signals it is dead */ DeletePort(startup_sync); return; } boolean launch_local(void) { struct StandardPacket *sp; struct Process *child; sp = (struct StandardPacket *)allocate_flags(sizeof(*sp), MEMF_PUBLIC, V_StandardPacket); if (!sp) return false; local_msg = &sp->sp_Msg; local_msg->mn_Node.ln_Name = (char *)&sp->sp_Pkt; sp->sp_Pkt.dp_Link = local_msg; sp->sp_Pkt.dp_Type = ACTION_DIE; /* for startup it should ignore this :) */ sp->sp_Pkt.dp_Port = startup_sync; /* this is bad programming ... increases linkage */ child = CreateNewProcTags( NP_Entry, local_handler, NP_Name, strings[MSG_LOCAL_HANDLER], NP_StackSize, 6000, TAG_END, 0 ); if (child) { local_port = &child->pr_MsgPort; PutMsg(local_port, local_msg); WaitPort(startup_sync); GetMsg(startup_sync); if (sp->sp_Pkt.dp_Res1) { return true; } } deallocate(sp, V_StandardPacket); startup_error(strings[MSG_CANT_LAUNCH_LOCAL]); return false; } void shutdown_local(void) { struct StandardPacket *sp; sp = (struct StandardPacket *)local_msg; sp->sp_Pkt.dp_Port = startup_sync; PutMsg(local_port, local_msg); WaitPort(startup_sync); GetMsg(startup_sync); deallocate(sp, V_StandardPacket); return; } boolean open_libraries(void) { IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 36); if (IntuitionBase) { DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 36); if (DOSBase) { GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0); if (GfxBase) { IconBase = OpenLibrary("icon.library", 0); LocaleBase = OpenLibrary("locale.library", 0); return true; } else startup_error("FTPMount cannot open graphics.library"); CloseLibrary((struct Library *)DOSBase); } else startup_error("FTPMount requires V36 dos.library"); CloseLibrary((struct Library *)IntuitionBase); } return false; } void close_libraries(void) { if (LocaleBase) CloseLibrary(LocaleBase); if (IconBase) CloseLibrary(IconBase); CloseLibrary((struct Library *)GfxBase); CloseLibrary((struct Library *)DOSBase); CloseLibrary((struct Library *)IntuitionBase); } boolean make_gims(void) { struct Screen *s; struct DrawInfo *drawinfo; s = LockPubScreen(nil); if (!s) return false; lightpen = 2; darkpen = 1; textpen = 1; fillpen = 3; drawinfo = GetScreenDrawInfo(s); if (drawinfo) { if (drawinfo->dri_NumPens > SHADOWPEN) { lightpen = drawinfo->dri_Pens[SHINEPEN]; darkpen = drawinfo->dri_Pens[SHADOWPEN]; textpen = drawinfo->dri_Pens[TEXTPEN]; fillpen = drawinfo->dri_Pens[FILLPEN]; } FreeScreenDrawInfo(s, drawinfo); } cancel_gim = make_gim(strings[MSG_CANCEL], textpen, lightpen, darkpen, s, IntuitionBase, GfxBase); if (cancel_gim) { abort_gim = make_gim(strings[MSG_ABORT], textpen, lightpen, darkpen, s, IntuitionBase, GfxBase); if (abort_gim) { disconnect_gim = make_gim(strings[MSG_DISCONNECT], textpen, lightpen, darkpen, s, IntuitionBase, GfxBase); if (disconnect_gim) { login_gim = make_gim(strings[MSG_LOGIN], textpen, lightpen, darkpen, s, IntuitionBase, GfxBase); if (login_gim) { UnlockPubScreen(nil, s); return true; } free_gim(disconnect_gim, IntuitionBase, GfxBase); } free_gim(abort_gim, IntuitionBase, GfxBase); } free_gim(cancel_gim, IntuitionBase, GfxBase); } UnlockPubScreen(nil, s); return false; } void free_gims(void) { free_gim(login_gim, IntuitionBase, GfxBase); free_gim(disconnect_gim, IntuitionBase, GfxBase); free_gim(abort_gim, IntuitionBase, GfxBase); free_gim(cancel_gim, IntuitionBase, GfxBase); } #define BUFF_SIZE 100 boolean get_anon_login(void) { b8 user[BUFF_SIZE], host[BUFF_SIZE]; sb32 i, j; struct EasyStruct es; es.es_StructSize = sizeof(struct EasyStruct); es.es_Flags = 0; es.es_Title = strings[MSG_FTPM_STARTUP_ERROR]; es.es_GadgetFormat = strings[MSG_CONTINUE_EXIT]; i = GetVar(strings[MSG_USER], user, BUFF_SIZE, 0); j = GetVar(strings[MSG_HOST], host, BUFF_SIZE, 0); /* four cases here */ if (i >= 0 && j >= 0) { anon_login = (b8 *)allocate(i + j + 2, V_cstr); if (!anon_login) return false; strcpy(anon_login, user); anon_login[i] = '@'; strcpy(anon_login + i + 1, host); } else if (i < 0 && j >= 0) { anon_login = (b8 *)allocate(j + 9, V_cstr); if (!anon_login) return false; strcpy(anon_login, "unknown@"); strcat(anon_login, host); es.es_TextFormat = strings[MSG_USER_NOT_SET]; if (!EasyRequest(nil, &es, 0, anon_login)) { deallocate(anon_login, V_cstr); return false; } } else if (i >= 0 && j < 0) { anon_login = (b8 *)allocate(i + 9, V_cstr); if (!anon_login) return false; strcpy(anon_login, user); strcat(anon_login, "@unknown"); es.es_TextFormat = strings[MSG_HOST_NOT_SET]; if (!EasyRequest(nil, &es, 0, anon_login)) { deallocate(anon_login, V_cstr); return false; } } else { anon_login = (b8 *)allocate(16, V_cstr); if (!anon_login) return false; strcpy(anon_login, "unknown@unknown"); es.es_TextFormat = strings[MSG_USER_HOST_NOT_SET]; if (!EasyRequest(nil, &es, 0, anon_login)) { deallocate(anon_login, V_cstr); return false; } } return true; } boolean create_volume(void) { b32 vlen; ftp_volume = (struct DosList *)allocate_flags(sizeof(struct DosList), MEMF_PUBLIC, V_DosList); if (ftp_volume) { ftp_volume->dol_Type = DLT_VOLUME; ftp_volume->dol_Task = ftp_port; ftp_volume->dol_Lock = 0; DateStamp(&ftp_volume->dol_misc.dol_volume.dol_VolumeDate); ftp_volume->dol_misc.dol_volume.dol_LockList = 0; ftp_volume->dol_misc.dol_volume.dol_DiskType = ID_DOS_DISK; vlen = strlen(strings[MSG_VOLUME]); volume_name = (b8 *)allocate_flags(vlen + 2, MEMF_PUBLIC, V_bstr); if (volume_name) { volume_name[0] = vlen; strcpy(&volume_name[1], strings[MSG_VOLUME]); ftp_volume->dol_Name = (b32)volume_name >> 2; if (AddDosEntry(ftp_volume)) { return true; } deallocate(volume_name, V_bstr); } deallocate(ftp_volume, V_DosList); } return false; } void destroy_volume(void) { struct DosList *dllock; dllock = LockDosList(LDF_VOLUMES | LDF_DELETE | LDF_WRITE); if (RemDosEntry(ftp_volume)) { deallocate(volume_name, V_bstr); deallocate(ftp_volume, V_DosList); } UnLockDosList(LDF_VOLUMES | LDF_DELETE | LDF_WRITE); return; } boolean launch_status(void) { struct Process *child; status_mess = (status_message *)allocate(sizeof(*status_mess), V_status_message); if (!status_mess) return false; status_mess->header.mn_Length = sizeof(*status_mess); status_mess->header.mn_Node.ln_Name = "status startup message"; status_mess->header.mn_Node.ln_Type = NT_MESSAGE; status_mess->header.mn_Node.ln_Pri = 0; ensure(status_mess, V_status_message); status_control = CreatePort(0, 0); if (status_control) { child = CreateNewProcTags( NP_Entry, status_handler, NP_Name, strings[MSG_STATUS_HANDLER], NP_StackSize, 6000, TAG_END, 0 ); if (child) { status_port = &child->pr_MsgPort; status_mess->header.mn_ReplyPort = startup_sync; PutMsg(status_port, &status_mess->header); WaitPort(startup_sync); GetMsg(startup_sync); if (status_mess->command != SM_KILL) { return true; } } DeletePort(status_control); } deallocate(status_mess, V_status_message); startup_error(strings[MSG_CANT_LAUNCH_STATUS]); return false; } void shutdown_status(void) { status_message *sm; status_mess->command = SM_KILL; status_mess->header.mn_ReplyPort = startup_sync; PutMsg(status_port, &status_mess->header); while (1) { Wait ((1 << status_control->mp_SigBit) | (1 << startup_sync->mp_SigBit)); while (sm = (status_message *)GetMsg(status_control)) { verify(sm, V_status_message); ReplyMsg(&sm->header); } if (sm = (status_message *)GetMsg(startup_sync)) { deallocate(status_mess, V_status_message); DeletePort(status_control); return; } } } void setup_strings(void) { int i; my_locale = nil; cat = nil; if (LocaleBase) { my_locale = OpenLocale(0); if (my_locale) { cat = OpenCatalog(my_locale, "FTPMount.catalog", OC_BuiltInLanguage, "english", TAG_END ); } } if (cat) { for (i = 0; i < NUM_MSGS; i++) { strings[i] = GetCatalogStr(cat, i, strings[i]); } } } void cleanup_strings(void) { if (cat) CloseCatalog(cat); if (my_locale) CloseLocale(my_locale); }