home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / FTPMOUNT.LZX / FTPMount-0.7 / Source / site.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-06  |  48.7 KB  |  2,194 lines

  1. /*
  2.  * This source file is Copyright 1995 by Evan Scott.
  3.  * All rights reserved.
  4.  * Permission is granted to distribute this file provided no
  5.  * fees beyond distribution costs are levied.
  6.  */
  7.  
  8. #include <exec/types.h>
  9. #include <exec/memory.h>
  10. #include <exec/alerts.h>
  11.  
  12. #include <devices/timer.h>
  13.  
  14. #include <dos/dos.h>
  15. #include <dos/dosextens.h>
  16. #include <dos/dostags.h>
  17.  
  18. #include <workbench/workbench.h>
  19.  
  20. #include <proto/exec.h>
  21. #include <proto/dos.h>
  22. #include <proto/intuition.h>
  23. #include <proto/icon.h>
  24. #include <proto/gadtools.h>
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29.  
  30. #include "evtypes.h"
  31. #include "verify.h"
  32. #include "tcp.h"
  33.  
  34. #include "site.h"
  35. #include "ftp.h"
  36. #include "split.h"
  37. #include "ftpinfo.h"
  38. #include "connect.h"
  39. #include "request.h"
  40.  
  41. #include "globals.h"
  42. #include "strings.h"
  43.  
  44. struct MsgPort *get_site(b8 *s)
  45. {
  46.     site *sp;
  47.     struct Process *child;
  48.     struct StandardPacket *std_pkt;
  49.     struct DiskObject *dobj;
  50.     BPTR ocd;
  51.     b8 *tmp;
  52.     
  53.     sp = sites;
  54.     while (sp) {
  55.         if (stricmp(sp->name, s) == 0) return sp->port;
  56.         sp = sp->next;
  57.     }
  58.     
  59.     sp = (site *)allocate(sizeof(*sp) + strlen(s) + 1, V_site);
  60.     if (!sp) return nil;
  61.     
  62.     ensure(sp, V_site);
  63.     
  64.     /* first sort out default login information */
  65.     
  66.     sp->user = nil;
  67.     sp->password = nil;
  68.     
  69.     sp->needs_user = false;
  70.     sp->needs_password = false;
  71.     
  72.     sp->root = nil;
  73.     sp->user = nil;
  74.     sp->password = nil;
  75.     sp->host = nil;
  76.     
  77.     sp->open_status = false;
  78.     sp->quick = true;
  79.     sp->case_sensitive = false;
  80.     
  81.     tmp = s;
  82.     while (*tmp && *tmp != '@') tmp++;
  83.     
  84.     if (*tmp == '@') {
  85.         sp->host = (b8 *)allocate(strlen(tmp + 1) + 1, V_cstr);
  86.         if (sp->host) {
  87.             strcpy(sp->host, tmp + 1);
  88.         }
  89.         
  90.         sp->needs_user = true;
  91.         sp->needs_password = true;
  92.         
  93.         if (tmp != s) {
  94.             sp->user = (b8 *)allocate(tmp - s + 1, V_cstr);
  95.             if (sp->user) {
  96.                 strncpy(sp->user, s, tmp - s);
  97.                 sp->user[tmp - s] = 0;
  98.                 sp->needs_user = false;
  99.             }
  100.         }
  101.     } else {
  102.         sp->host = (b8 *)allocate(strlen(s) + 1, V_cstr);
  103.         if (sp->host) {
  104.             strcpy(sp->host, s);
  105.         }
  106.     }
  107.     
  108.     /* now try to get info from icon */
  109.     
  110.     if (IconBase) {
  111.         ocd = CurrentDir(ftphosts_lock);
  112.         dobj = GetDiskObject(s);
  113.         CurrentDir(ocd);
  114.     } else {
  115.         dobj = nil;
  116.     }
  117.     
  118.     if (dobj) {
  119.         /*
  120.          * HOST overrides the "title", whereas USER doesn't ... 
  121.          * is this inconsistent or is it valid?
  122.          */
  123.         if (!sp->user) {
  124.             tmp = FindToolType(dobj->do_ToolTypes, strings[MSG_USER_TT]);
  125.             if (tmp) {
  126.                 sp->user = (b8 *)allocate(strlen(tmp) + 1, V_cstr);
  127.                 if (sp->user) {
  128.                     strcpy(sp->user, tmp);
  129.                     sp->needs_user = false;
  130.                 }
  131.             }
  132.         }
  133.         
  134.         tmp = FindToolType(dobj->do_ToolTypes, strings[MSG_PASSWORD_TT]);
  135.         if (tmp) {
  136.             sp->password = (b8 *)allocate(strlen(tmp) + 1, V_cstr);
  137.             if (sp->password) {
  138.                 strcpy(sp->password, tmp);
  139.                 sp->needs_password = false;
  140.             }
  141.         }
  142.         
  143.         tmp = FindToolType(dobj->do_ToolTypes, strings[MSG_STATUS_TT]);
  144.         if (tmp) {
  145.             if (stricmp(tmp, strings[MSG_OFF]) != 0 &&
  146.                     stricmp(tmp, strings[MSG_FALSE]) != 0) {
  147.                 sp->open_status = true;
  148.             }
  149.         }
  150.  
  151.         tmp = FindToolType(dobj->do_ToolTypes, strings[MSG_QUICK_TT]);
  152.         if (tmp) {
  153.             if (stricmp(tmp, strings[MSG_OFF]) == 0 ||
  154.                     stricmp(tmp, strings[MSG_FALSE]) == 0) {
  155.                 sp->quick = false;
  156.             } else {
  157.                 sp->quick = true;
  158.             }
  159.         }
  160.         
  161.         tmp = FindToolType(dobj->do_ToolTypes, strings[MSG_SLOW_TT]);
  162.         if (tmp) {
  163.             if (stricmp(tmp, strings[MSG_OFF]) != 0 &&
  164.                     stricmp(tmp, strings[MSG_FALSE]) != 0) {
  165.                 sp->quick = false;
  166.             } else {
  167.                 sp->quick = true;
  168.             }
  169.         }
  170.         
  171.         tmp = FindToolType(dobj->do_ToolTypes, strings[MSG_CASE_TT]);
  172.         if (tmp) {
  173.             if (stricmp(tmp, strings[MSG_OFF]) != 0 &&
  174.                     stricmp(tmp, strings[MSG_FALSE]) != 0) {
  175.                 sp->case_sensitive = true;
  176.             }
  177.         }
  178.         
  179.         tmp = FindToolType(dobj->do_ToolTypes, strings[MSG_HOST_TT]);
  180.         if (tmp) {
  181.             if (sp->host) deallocate(sp->host, V_cstr);
  182.             sp->host = allocate(strlen(tmp) + 1, V_cstr);
  183.             if (sp->host) {
  184.                 strcpy(sp->host, tmp);
  185.             }
  186.         }
  187.         
  188.         tmp = FindToolType(dobj->do_ToolTypes, strings[MSG_ROOT_TT]);
  189.         if (tmp) {
  190.             sp->root = allocate(strlen(tmp) + 1, V_cstr);
  191.             if (sp->root) {
  192.                 strcpy(sp->root, tmp);
  193.             }
  194.         }
  195.         
  196.         FreeDiskObject(dobj);
  197.     }
  198.     
  199.     if (!sp->host) {
  200.         if (sp->user) deallocate(sp->user, V_cstr);
  201.         if (sp->password) deallocate(sp->password, V_cstr);
  202.         if (sp->root) deallocate(sp->root, V_cstr);
  203.         
  204.         deallocate(sp, V_site);
  205.         
  206.         return nil;
  207.     }
  208.     
  209.     std_pkt = (struct StandardPacket *)allocate(sizeof(*std_pkt), V_StandardPacket);
  210.     if (!std_pkt) {
  211.         deallocate(sp->host, V_cstr);
  212.         
  213.         if (sp->user) deallocate(sp->user, V_cstr);
  214.         if (sp->password) deallocate(sp->password, V_cstr);
  215.         if (sp->root) deallocate(sp->root, V_cstr);
  216.         
  217.         deallocate(sp, V_site);
  218.         
  219.         return nil;
  220.     }
  221.     
  222.     std_pkt->sp_Msg.mn_Node.ln_Name = (void *)&std_pkt->sp_Pkt;
  223.     std_pkt->sp_Pkt.dp_Link = &std_pkt->sp_Msg;
  224.     
  225.     std_pkt->sp_Pkt.dp_Type = ACTION_DIE;    /* ignored when used at startup */
  226.     std_pkt->sp_Pkt.dp_Arg1 = (b32)sp;
  227.     std_pkt->sp_Pkt.dp_Port = startup_sync;
  228.     
  229.     strcpy(sp->name, s);
  230.     
  231.     sp->lock_list = nil;
  232.     sp->file_list = nil;
  233.     
  234.     sp->infos = nil;
  235.  
  236.     sp->control = nil;
  237.     sp->intr = nil;
  238.  
  239.     sp->cwd = nil;
  240.     
  241.     sp->connected = false;
  242.     sp->read_banners = false;
  243.     sp->unix_paths = true;
  244.     
  245.     sp->cfile = nil;
  246.     sp->cfile_type = 0;
  247.     
  248.     sp->abort_signals = sp->disconnect_signals = 0;
  249.     sp->site_state = SS_DISCONNECTED;
  250.     
  251.     sp->status_window = nil;
  252.     
  253.     child = CreateNewProcTags(
  254.         NP_Entry,    site_handler,
  255.         NP_Name,    sp->name,
  256.         NP_StackSize,    6000,
  257.         TAG_END,    0
  258.     );
  259.     
  260.     if (!child) {
  261.         deallocate(sp->host, V_cstr);
  262.         
  263.         if (sp->user) deallocate(sp->user, V_cstr);
  264.         if (sp->password) deallocate(sp->password, V_cstr);
  265.         if (sp->root) deallocate(sp->root, V_cstr);
  266.         
  267.         deallocate(std_pkt, V_StandardPacket);
  268.         deallocate(sp, V_site);
  269.         return nil;
  270.     }
  271.     
  272.     sp->port = &child->pr_MsgPort;
  273.     
  274.     PutMsg(sp->port, &std_pkt->sp_Msg);
  275.     WaitPort(startup_sync); GetMsg(startup_sync);
  276.     
  277.     if (std_pkt->sp_Pkt.dp_Res1) {
  278.         sp->death_packet = std_pkt;
  279.         
  280.         sp->next = sites;
  281.         sites = sp;
  282.         
  283.         return sp->port;
  284.     } else {
  285.         deallocate(sp->host, V_cstr);
  286.         
  287.         if (sp->user) deallocate(sp->user, V_cstr);
  288.         if (sp->password) deallocate(sp->password, V_cstr);
  289.         if (sp->root) deallocate(sp->root, V_cstr);
  290.         
  291.         deallocate(std_pkt, V_StandardPacket);
  292.         deallocate(sp, V_site);
  293.         
  294.         return nil;
  295.     }
  296. }
  297.  
  298. void remove_site(site *sp)
  299. {
  300.     site **sps;
  301.     
  302.     verify(sp, V_site);
  303.     
  304.     sps = &sites;
  305.     while (*sps && *sps != sp) {
  306.         sps = &(*sps)->next;
  307.     }
  308.     
  309.     if (*sps) {
  310.         *sps = sp->next;
  311.         
  312.         if (sp->host) deallocate(sp->host, V_cstr);
  313.         if (sp->root) deallocate(sp->root, V_cstr);
  314.         
  315.         deallocate(sp->death_packet, V_StandardPacket);
  316.         deallocate(sp, V_site);
  317.     }
  318.     
  319.     return;
  320. }
  321.  
  322. void shutdown_sites(void)
  323. {
  324.     site *sp, *spn;
  325.     struct DosPacket *dp;
  326.     lock *l;
  327.     
  328.     sp = sites;
  329.     while (sp) {
  330.         verify(sp, V_site);
  331.     
  332.         spn = sp->next;
  333.         
  334.         dp = &sp->death_packet->sp_Pkt;
  335.         dp->dp_Type = ACTION_DIE;
  336.         dp->dp_Port = startup_sync;
  337.         
  338.         PutMsg(sp->port, dp->dp_Link);
  339.         WaitPort(startup_sync); GetMsg(startup_sync);
  340.         
  341.         l = (lock *)dp->dp_Res2;
  342.         while (l) {
  343.             adopt(l, V_lock);
  344.             l = l->next;
  345.         }
  346.         
  347.         if (sp->host) deallocate(sp->host, V_cstr);
  348.         if (sp->root) deallocate(sp->root, V_cstr);
  349.         
  350.         deallocate(sp->death_packet, V_StandardPacket);
  351.         deallocate(sp, V_site);
  352.         sp = spn;
  353.     }
  354.     
  355.     sites = nil;
  356. }
  357.  
  358. void suspend_sites(void)
  359. {
  360.     site *sp;
  361.     struct DosPacket *dp;
  362.     
  363.     sp = sites;
  364.     while (sp) {
  365.         verify(sp, V_site);
  366.     
  367.         dp = &sp->death_packet->sp_Pkt;
  368.         dp->dp_Type = action_SUSPEND;
  369.         dp->dp_Port = startup_sync;
  370.         
  371.         PutMsg(sp->port, dp->dp_Link);
  372.         WaitPort(startup_sync); GetMsg(startup_sync);
  373.         
  374.         sp = sp->next;
  375.     }
  376. }
  377.  
  378. struct info_header *get_dir(site *sp, b8 *name)
  379. {
  380.     struct info_header *ih;
  381.     
  382.     verify(sp, V_site);
  383.     truth(name != nil);
  384.     
  385.     ih = find_info_header(sp, name);
  386.     if (ih) return ih;
  387.     
  388.     /* oh kay */
  389.     
  390.     if (sp->cfile) {
  391.         verify(sp->file_list, V_file_info);
  392.         
  393.         if (sp->file_list->closed) {
  394.             close_file(sp, true);
  395.         } else {
  396.             return nil;
  397.         }
  398.     }
  399.     
  400.     if (!change_dir(sp, name)) return nil;
  401.     
  402.     ih = new_info_header(sp, name);
  403.     if (!ih) return nil;    /* just out of memory ... but wth */
  404.     
  405.     get_list(sp, ih);
  406.     
  407.     return ih;
  408. }
  409.  
  410. ftpinfo *get_info(site *ftp_site, b8 *name)
  411. {
  412.     b8 *s;
  413.     struct info_header *ih;
  414.     
  415.     verify(ftp_site, V_site);
  416.     truth(name != nil);
  417.     
  418.     /* get parent dir name */
  419.         
  420.     s = name + strlen(name) - 1;
  421.     while (s >= name && *s != '/') s--;
  422.     
  423.     if (s >= name) {
  424.         *s = 0;
  425.         ih = get_dir(ftp_site, name);
  426.         *s++ = '/';
  427.     } else {
  428.         s = name;
  429.         ih = get_dir(ftp_site, "");
  430.     }
  431.     
  432.     if (!ih) return nil;
  433.     
  434.     return find_info(ih, s);
  435. }
  436.  
  437. void flush_info(site *ftp_site, b8 *name)
  438. {
  439.     b8 *s;
  440.     struct info_header *ih;
  441.     
  442.     verify(ftp_site, V_site);
  443.     truth(name != nil);
  444.     
  445.     /* get parent dir name */
  446.         
  447.     s = name + strlen(name) - 1;
  448.     while (s >= name && *s != '/') s--;
  449.     
  450.     if (s >= name) {
  451.         *s = 0;
  452.         ih = find_info_header(ftp_site, name);
  453.         *s++ = '/';
  454.     } else {
  455.         s = name;
  456.         ih = find_info_header(ftp_site, "");
  457.     }
  458.     
  459.     if (ih) {
  460.         free_info_header(ih);
  461.     }
  462.     
  463.     return;
  464. }
  465.  
  466. status_message *get_sm(site *sp)
  467. {
  468.     status_message *sm;
  469.     
  470.     verify(sp, V_site);
  471.     
  472.     if (sm = (status_message *)GetMsg(sp->rank)) return sm;
  473.     
  474.     sm = (status_message *)allocate(sizeof(*sm), V_status_message);
  475.     if (!sm) return nil;
  476.     
  477.     ensure(sm, V_status_message);
  478.     
  479.     sm->header.mn_ReplyPort = sp->rank;
  480.     sm->header.mn_Length = sizeof(*sm);
  481.     sm->header.mn_Node.ln_Type = NT_MESSAGE;
  482.     sm->header.mn_Node.ln_Name = "site status message";
  483.     sm->header.mn_Node.ln_Pri = 0;
  484.     
  485.     sm->this_site = sp;
  486.     
  487.     return sm;
  488. }
  489.  
  490. void state_change(site *sp, b16 state)
  491. {
  492.     status_message *sm;
  493.     
  494.     verify(sp, V_site);
  495.     
  496.     if (sp->site_state == state) return;
  497.  
  498.     sp->site_state = state;
  499.     
  500.     sm = get_sm(sp);
  501.     if (sm) {
  502.         sm->command = SM_STATE_CHANGE;
  503.         PutMsg(status_port, &sm->header);
  504.     }
  505. }
  506.  
  507. void __saveds site_handler(void)
  508. {
  509.     struct Process *me;
  510.     struct Message *msg;
  511.     struct DosPacket *dp;
  512.     struct MsgPort *local, *reply, *sync, *timeport, *rank;
  513.     struct StandardPacket *idle_packet;
  514.     struct timerequest *timer;
  515.     status_message *sm, *tsm;
  516.     lock *new_lock, *slock, **locks;
  517.     site *ftp_site;
  518.     b32 signals;
  519.     int idlecount, n;
  520.     split sd, sd2;
  521.     b8 *s;
  522.     struct info_header *ih;
  523.     ftpinfo *fi;
  524.     file_info *fip;
  525.     struct FileHandle *fh;
  526.     struct FileInfoBlock *fib;
  527.     b32 o1, o2, o3;
  528.     
  529.     me = (struct Process *)FindTask(0);
  530.     
  531.     local = &me->pr_MsgPort;
  532.  
  533.     WaitPort(local);
  534.     msg = GetMsg(local);
  535.     
  536.     dp = (struct DosPacket *)msg->mn_Node.ln_Name;
  537.     
  538.     reply = dp->dp_Port;
  539.     dp->dp_Port = local;
  540.     
  541.     ftp_site = (site *)dp->dp_Arg1;
  542.     
  543.     verify(ftp_site, V_site);
  544.     
  545.     local->mp_Node.ln_Name = ftp_site->name;
  546.     
  547.     idlecount = 0;
  548.     
  549.     mem_tracking_on();
  550.     
  551.     ftp_site->IBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 36);
  552.     if (ftp_site->IBase) {
  553.         ftp_site->GTBase = OpenLibrary("gadtools.library", 0);
  554.         if (ftp_site->GTBase) {
  555.             ftp_site->GBase = (struct GfxBase *)OpenLibrary("graphics.library", 36);
  556.             if (ftp_site->GBase) {
  557.                 sync = CreatePort(0, 0);
  558.                 if (sync) {
  559.                     ftp_site->sync = sync;
  560.                 
  561.                     timeport = CreatePort(0, 0);
  562.                     if (timeport) {
  563.                         timer = (struct timerequest *)CreateExtIO(timeport, sizeof(*timer));
  564.                         if (timer) {
  565.                             idle_packet = (struct StandardPacket *)allocate(sizeof(*idle_packet), V_StandardPacket);
  566.                             if (idle_packet) {
  567.                                 idle_packet->sp_Msg.mn_Node.ln_Name =
  568.                                     (void *)&idle_packet->sp_Pkt;
  569.                                 idle_packet->sp_Pkt.dp_Link = &idle_packet->sp_Msg;
  570.                                 idle_packet->sp_Pkt.dp_Type = action_IDLE;
  571.                                 idle_packet->sp_Pkt.dp_Arg1 = (b32)ftp_site;
  572.                         
  573.                                 prime->header.mn_ReplyPort = sync;
  574.                                 prime->command = TCP_NEWMESSAGE;
  575.                                 PutMsg(tcp, &prime->header);
  576.                                 WaitPort(sync); GetMsg(sync);
  577.                                 if (prime->result) {
  578.                                     ftp_site->control = prime->data;
  579.                                 
  580.                                     PutMsg(tcp, &prime->header);
  581.                                     WaitPort(sync); GetMsg(sync);
  582.                                     if (prime->result) {
  583.                                         ftp_site->intr = prime->data;
  584.                                         ftp_site->intr->interrupt = ftp_site->control;
  585.                                         ftp_site->intr->header.mn_ReplyPort = sync;
  586.                                         ftp_site->intr->command = TCP_INTERRUPT;
  587.  
  588.                                         if (OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)timer, 0) == 0) {
  589.                                             sm = (status_message *)allocate(sizeof(*sm), V_status_message);
  590.                                             if (sm) {
  591.                                                 rank = CreatePort(0, 0);
  592.                                                 if (rank) {
  593.                                                     ftp_site->rank = rank;
  594.                                                     goto begin;
  595.                                                 } else dp->dp_Res2 = ERROR_NO_FREE_STORE;
  596.                                                 deallocate(sm, V_status_message);
  597.                                             } else dp->dp_Res2 = ERROR_NO_FREE_STORE;
  598.                                             CloseDevice((struct IORequest *)timer);
  599.                                         } else dp->dp_Res2 = ERROR_DEVICE_NOT_MOUNTED;
  600.                                         ftp_site->intr->command = TCP_DISPOSE;
  601.                                         PutMsg(tcp, &ftp_site->intr->header);
  602.                                     } else dp->dp_Res2 = ERROR_NO_FREE_STORE;
  603.                                     ftp_site->control->command = TCP_DISPOSE;
  604.                                     PutMsg(tcp, &ftp_site->control->header);
  605.                                 } else dp->dp_Res2 = ERROR_NO_FREE_STORE;
  606.                                 deallocate(idle_packet, V_StandardPacket);
  607.                             } else dp->dp_Res2 = ERROR_NO_FREE_STORE;
  608.                             DeleteExtIO((struct IORequest *)timer);
  609.                         } else dp->dp_Res2 = ERROR_NO_FREE_STORE;
  610.                         DeletePort(timeport);
  611.                     } else dp->dp_Res2 = ERROR_NO_FREE_STORE;
  612.                     DeletePort(sync);
  613.                 } else dp->dp_Res2 = ERROR_NO_FREE_STORE;
  614.                 CloseLibrary((struct Library *)ftp_site->GBase);
  615.             } else dp->dp_Res2 = ERROR_INVALID_RESIDENT_LIBRARY;
  616.             CloseLibrary(ftp_site->GTBase);
  617.         } else dp->dp_Res2 = ERROR_INVALID_RESIDENT_LIBRARY;
  618.         CloseLibrary((struct Library *)ftp_site->IBase);
  619.     } else dp->dp_Res2 = ERROR_INVALID_RESIDENT_LIBRARY;
  620.     
  621.     dp->dp_Res1 = DOSFALSE;
  622.     
  623.     check_memory();
  624.     
  625.     Forbid();
  626.     PutMsg(reply, dp->dp_Link);
  627.     return;
  628.  
  629. begin:
  630.     timer->tr_node.io_Command = TR_ADDREQUEST;
  631.     timer->tr_time.tv_secs = IDLE_INTERVAL;
  632.     timer->tr_time.tv_micro = 0;
  633.     SendIO((struct IORequest *)timer);
  634.     
  635.     ensure(sm, V_status_message);
  636.     
  637.     sm->header.mn_ReplyPort = sync;
  638.     sm->header.mn_Length = sizeof(*sm);
  639.     sm->header.mn_Node.ln_Type = NT_MESSAGE;
  640.     sm->header.mn_Node.ln_Pri = 0;
  641.     sm->header.mn_Node.ln_Name = "site status message";
  642.     
  643.     sm->command = SM_NEW_SITE;
  644.     sm->data = ftp_site->open_status;
  645.     sm->this_site = ftp_site;
  646.     
  647.     PutMsg(status_port, &sm->header);
  648.     WaitPort(sync); GetMsg(sync);
  649.     
  650.     ftp_site->abort_signals = (1 << AllocSignal(-1));
  651.     ftp_site->disconnect_signals = (1 << AllocSignal(-1));
  652.                         
  653.     dp->dp_Res1 = DOSTRUE;
  654.     dp->dp_Res2 = 0;
  655.     
  656.     PutMsg(reply, dp->dp_Link);    /* send it back to signal we are away */
  657.     
  658.     signals = (1 << local->mp_SigBit) | (1 << timeport->mp_SigBit) | (ftp_site->disconnect_signals);
  659.     
  660.     while (1) {
  661.         if (ftp_site->connected) {
  662.             if (!ftp_site->cfile) {
  663.                 state_change(ftp_site, SS_IDLE);
  664.             }
  665.         } else {
  666.             state_change(ftp_site, SS_DISCONNECTED);
  667.         }
  668.  
  669.         if (Wait(signals) & ftp_site->disconnect_signals) {
  670.             disconnect(ftp_site);
  671.         }
  672.         
  673.         if (GetMsg(timeport)) {
  674.             timer->tr_node.io_Command = TR_ADDREQUEST;
  675.             timer->tr_time.tv_secs = IDLE_INTERVAL;
  676.             timer->tr_time.tv_micro = 0;
  677.             
  678.             idlecount++;
  679.             
  680.             SendIO((struct IORequest *)timer);
  681.             
  682.             if (ftp_site->lock_list == nil && ftp_site->file_list == nil) {
  683.                 if (ftp_site->connected) {
  684.                     if (idlecount > NO_LOCK_CONN_IDLE) {
  685.                         idle_packet->sp_Pkt.dp_Port = sync;
  686.                         PutMsg(ftp_port, &idle_packet->sp_Msg);
  687.                         WaitPort(sync); GetMsg(sync);
  688.                     }
  689.                 } else if (!ftp_site->connected) {
  690.                     if (idlecount > NO_LOCK_NO_CONN_IDLE) {
  691.                         idle_packet->sp_Pkt.dp_Port = sync;
  692.                         PutMsg(ftp_port, &idle_packet->sp_Msg);
  693.                         WaitPort(sync); GetMsg(sync);
  694.                     }
  695.                 }
  696.             }
  697.         }
  698.         
  699.         while (msg = GetMsg(local)) {
  700.             idlecount = 0;
  701.             
  702.             dp = (struct DosPacket *)msg->mn_Node.ln_Name;
  703.             
  704.             reply = dp->dp_Port;
  705.             
  706.             switch (dp->dp_Type) {
  707.             case action_IDLE_DEATH:
  708.                 if (ftp_site->file_list && ftp_site->file_list->closed) {
  709.                     close_file(ftp_site, true);
  710.                 }
  711.                 if (ftp_site->lock_list || ftp_site->file_list) {
  712.                     dp->dp_Res1 = DOSFALSE;
  713.                     dp->dp_Res2 = 0;
  714.                     
  715.                     break;
  716.                 }
  717.                 /* fall through to DIE */
  718.             case ACTION_DIE:
  719.                 state_change(ftp_site, SS_DISCONNECTING);
  720.                 
  721.                 slock = ftp_site->lock_list;
  722.                 while (slock) {
  723.                     new_lock = slock->next;
  724.                     disown(slock, V_lock);
  725.                     slock = new_lock;
  726.                 }
  727.                 
  728.                 deallocate(idle_packet, V_StandardPacket);
  729.                 
  730.                 AbortIO((struct IORequest *)timer);
  731.                 WaitPort(timeport); GetMsg(timeport);
  732.                 
  733.                 CloseDevice((struct IORequest *)timer);
  734.                 
  735.                 if (ftp_site->connected) {
  736.                     ftp_site->control->command = TCP_CLOSE;
  737.                     PutMsg(tcp, &ftp_site->control->header);
  738.                     WaitPort(sync); GetMsg(sync);
  739.                     
  740.                     ftp_site->connected = false;
  741.                 }
  742.                 
  743.                 ftp_site->control->command = TCP_DISPOSE;
  744.                 PutMsg(tcp, &ftp_site->control->header);
  745.                 
  746.                 ftp_site->intr->command = TCP_DISPOSE;
  747.                 PutMsg(tcp, &ftp_site->intr->header);
  748.                 
  749.                 sm->command = SM_DEAD_SITE;
  750.                 
  751.                 PutMsg(status_port, &sm->header);
  752.                 WaitPort(sync); GetMsg(sync);
  753.                 
  754.                 while (tsm = (status_message *)GetMsg(rank)) {
  755.                     verify(tsm, V_status_message);
  756.                     deallocate(tsm, V_status_message);
  757.                 }
  758.                 
  759.                 DeletePort(rank);
  760.                 deallocate(sm, V_status_message);
  761.  
  762.                 DeleteExtIO((struct IORequest *)timer);
  763.                 DeletePort(timeport);
  764.                 DeletePort(sync);
  765.                 
  766.                 CloseLibrary((struct Library *)ftp_site->GBase);
  767.                 CloseLibrary(ftp_site->GTBase);
  768.                 CloseLibrary((struct Library *)ftp_site->IBase);
  769.                 
  770.                 while (ftp_site->infos) free_info_header(ftp_site->infos);
  771.                 
  772.                 if (ftp_site->cwd) deallocate(ftp_site->cwd, V_cstr);
  773.                 if (ftp_site->root) {
  774.                     /* this one might have been allocated from main task ... but */
  775.                     deallocate(ftp_site->root, V_cstr);
  776.                     ftp_site->root = nil;
  777.                 }
  778.                 
  779.                 /* again, these may have been allocated in either the main task or
  780.                    the site task ... too complicated to work it out ... this works for now */
  781.                    
  782.                 if (ftp_site->user) deallocate(ftp_site->user, V_cstr);
  783.                 if (ftp_site->password) deallocate(ftp_site->password, V_cstr);
  784.     
  785.                 dp->dp_Res1 = DOSTRUE;
  786.                 dp->dp_Res2 = (b32)(ftp_site->lock_list);    /* so they can adopt the locks */
  787.                 
  788.                 check_memory();
  789.     
  790.                 Forbid();
  791.                 PutMsg(reply, dp->dp_Link);
  792.                 return;
  793.             case ACTION_LOCATE_OBJECT:
  794.                 if (!split_data((lock *)(dp->dp_Arg1 << 2), (b8 *)(dp->dp_Arg2 << 2), &sd)) {
  795.                     dp->dp_Res1 = 0;
  796.                     dp->dp_Res2 = ERROR_NO_FREE_STORE;
  797.                     
  798.                     break;
  799.                 }
  800.                 
  801.                 if (!ftp_site->connected) {
  802.                     init_connect(ftp_site);
  803.                     
  804.                     if (!ftp_site->connected) {
  805.                         dp->dp_Res1 = 0;
  806.                         dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  807.                         
  808.                         end_split(&sd);
  809.                         break;
  810.                     }
  811.                 }
  812.                 
  813.                 if (!sd.path || sd.path[0] == 0) {
  814.                     /* the root ... this is ok */
  815.                     if (dp->dp_Arg3 == EXCLUSIVE_LOCK) {
  816.                         dp->dp_Res1 = 0;
  817.                         /* can't exclusive lock root */
  818.                         dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  819.                         break;
  820.                     }
  821.                     
  822.                     new_lock = (lock *)allocate(sizeof(*new_lock) + 1, V_lock);
  823.                     if (!new_lock) {
  824.                         dp->dp_Res1 = 0;
  825.                         dp->dp_Res2 = ERROR_NO_FREE_STORE;
  826.                         
  827.                         break;
  828.                     }
  829.                     
  830.                     ensure(new_lock, V_lock);
  831.                     
  832.                     new_lock->next = ftp_site->lock_list;
  833.                     ftp_site->lock_list = new_lock;
  834.                     
  835.                     new_lock->port = local;
  836.                     new_lock->rfsl = 0;
  837.                     new_lock->lastkey = 0;
  838.                     new_lock->fname[0] = 0;
  839.                     
  840.                     new_lock->fl.fl_Link = 0;
  841.                     new_lock->fl.fl_Key = 0;
  842.                     new_lock->fl.fl_Access = SHARED_LOCK;
  843.                     new_lock->fl.fl_Task = ftp_port;
  844.                     new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
  845.                     
  846.                     dp->dp_Res1 = (b32)new_lock >> 2;
  847.                     dp->dp_Res2 = 0;
  848.                 } else {
  849.                     new_lock = (lock *)allocate(sizeof(*new_lock) + strlen(sd.path) + 1, V_lock);
  850.                     if (!new_lock) {
  851.                         dp->dp_Res1 = 0;
  852.                         dp->dp_Res2 = ERROR_NO_FREE_STORE;
  853.                         break;
  854.                     }
  855.                     
  856.                     ensure(new_lock, V_lock);
  857.                     
  858.                     strcpy(new_lock->fname, sd.path);
  859.  
  860.                     new_lock->port = local;
  861.                     new_lock->rfsl = 0;
  862.                     new_lock->lastkey = 0;
  863.                     
  864.                     new_lock->fl.fl_Link = 0;
  865.                     new_lock->fl.fl_Key = 0;
  866.                     new_lock->fl.fl_Access = SHARED_LOCK;
  867.                     new_lock->fl.fl_Task = ftp_port;
  868.                     new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
  869.                     
  870.                     /* search for a conflicting lock */
  871.                     
  872.                     slock = ftp_site->lock_list;
  873.                     while (slock) {
  874.                         if (strcmp(sd.path, slock->fname) == 0) {
  875.                             if (dp->dp_Arg3 == EXCLUSIVE_LOCK || slock->fl.fl_Access == EXCLUSIVE_LOCK) {
  876.                                 dp->dp_Res1 = 0;
  877.                                 dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  878.                                 
  879.                                 deallocate(new_lock, V_lock);
  880.                                 end_split(&sd);
  881.                                 
  882.                                 goto reply_msg;
  883.                             }
  884.                             
  885.                             /* ok, this one is guaranteed to work */
  886.                             
  887.                             new_lock->next = ftp_site->lock_list;
  888.                             ftp_site->lock_list = new_lock;
  889.                             
  890.                             dp->dp_Res1 = (b32)new_lock >> 2;
  891.                             dp->dp_Res2 = 0;
  892.                             
  893.                             end_split(&sd);
  894.                             
  895.                             goto reply_msg;
  896.                         }
  897.                         slock = slock->next;
  898.                     }
  899.                     
  900.                     /* ok, it doesn't conflict ... check if it actually exists */
  901.                     
  902.                     fi = get_info(ftp_site, sd.path);
  903.                     if (!fi) {
  904.                         deallocate(new_lock, V_lock);
  905.                         end_split(&sd);
  906.                         
  907.                         dp->dp_Res1 = 0;
  908.                         if (ftp_site->cfile)
  909.                             dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  910.                         else
  911.                             dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  912.                         goto reply_msg;
  913.                     }
  914.                     
  915.                     /* well, we found it! */
  916.                     
  917.                     new_lock->next = ftp_site->lock_list;
  918.                     ftp_site->lock_list = new_lock;
  919.                     
  920.                     dp->dp_Res1 = (b32)new_lock >> 2;
  921.                     dp->dp_Res2 = 0;
  922.                 }
  923.                 
  924.                 end_split(&sd);
  925.                 break;
  926.             case ACTION_FREE_LOCK:
  927.                 slock = (lock *)(dp->dp_Arg1 << 2);                
  928.                 
  929.                 if (!slock) {
  930.                     dp->dp_Res1 = DOSTRUE;
  931.                     dp->dp_Res2 = 0;
  932.                     break;
  933.                 }
  934.                 
  935.                 verify(slock, V_lock);
  936.                 
  937.                 locks = &ftp_site->lock_list;
  938.                 while (*locks && *locks != slock) {
  939.                     locks = &(*locks)->next;
  940.                 }
  941.                 
  942.                 if (!*locks) {
  943.                     dp->dp_Res1 = DOSFALSE;
  944.                     dp->dp_Res2 = ERROR_INVALID_LOCK;
  945.                 } else {
  946.                     *locks = slock->next;
  947.                     deallocate(slock, V_lock);
  948.                     
  949.                     dp->dp_Res1 = DOSTRUE;
  950.                     dp->dp_Res2 = 0;
  951.                 }
  952.                 
  953.                 break;
  954.             case ACTION_DELETE_OBJECT:
  955.                 if (!split_data((lock *)(dp->dp_Arg1 << 2), (b8 *)(dp->dp_Arg2 << 2), &sd)) {
  956.                     dp->dp_Res1 = DOSFALSE;
  957.                     dp->dp_Res2 = ERROR_NO_FREE_STORE;
  958.                     
  959.                     break;
  960.                 }
  961.                 
  962.                 if (ftp_site->file_list) {
  963.                     if (ftp_site->file_list->closed) {
  964.                         close_file(ftp_site, true);
  965.                     } else {
  966.                         dp->dp_Res1 = DOSFALSE;
  967.                         dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  968.                         
  969.                         end_split(&sd);
  970.                         
  971.                         goto reply_msg;
  972.                     }
  973.                 }
  974.                 
  975.                 /* search for a conflicting lock */
  976.                 
  977.                 slock = ftp_site->lock_list;
  978.                 while (slock) {
  979.                     if (strcmp(sd.path, slock->fname) == 0) {
  980.                         dp->dp_Res1 = 0;
  981.                         dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  982.                         
  983.                         end_split(&sd);
  984.                         
  985.                         goto reply_msg;
  986.                     }
  987.                     slock = slock->next;
  988.                 }
  989.                 
  990.                 fi = get_info(ftp_site, sd.path);
  991.                 if (fi && fi->flags & MYFLAG_DIR) {
  992.                     dp->dp_Res2 = delete_directory(ftp_site, sd.path);
  993.                 } else {
  994.                     dp->dp_Res2 = delete_file(ftp_site, sd.path);
  995.                 }
  996.                 
  997.                 if (dp->dp_Res2) {
  998.                     dp->dp_Res1 = DOSFALSE;
  999.                 } else {
  1000.                     if (fi) fi->flags |= MYFLAG_DELETED;
  1001.                     dp->dp_Res1 = DOSTRUE;
  1002.                 }
  1003.                 
  1004.                 end_split(&sd);
  1005.                 
  1006.                 break;
  1007.             case ACTION_RENAME_OBJECT:
  1008.                 if (!split_data((lock *)(dp->dp_Arg1 << 2), (b8 *)(dp->dp_Arg2 << 2), &sd)) {
  1009.                     dp->dp_Res1 = DOSFALSE;
  1010.                     dp->dp_Res2 = ERROR_NO_FREE_STORE;
  1011.                     
  1012.                     break;
  1013.                 }
  1014.                 
  1015.                 if (!split_data((lock *)(dp->dp_Arg3 << 2), (b8 *)(dp->dp_Arg4 << 2), &sd2)) {
  1016.                     dp->dp_Res1 = DOSFALSE;
  1017.                     dp->dp_Res2 = ERROR_NO_FREE_STORE;
  1018.                     
  1019.                     end_split(&sd);
  1020.                     
  1021.                     break;
  1022.                 }
  1023.                 
  1024.                 fi = get_info(ftp_site, sd.path);
  1025.                 
  1026.                 dp->dp_Res2 = rename_object(ftp_site, sd.path, sd2.path);
  1027.                 
  1028.                 if (dp->dp_Res2) {
  1029.                     dp->dp_Res1 = DOSFALSE;
  1030.                 } else {
  1031.                     if (fi) fi->flags |= MYFLAG_DELETED;
  1032.                     flush_info(ftp_site, sd2.path);
  1033.                     dp->dp_Res1 = DOSTRUE;
  1034.                 }
  1035.                 
  1036.                 end_split(&sd);
  1037.                 end_split(&sd2);
  1038.                 
  1039.                 break;
  1040.             case ACTION_COPY_DIR:
  1041.                 slock = (lock *)(dp->dp_Arg1 << 2);
  1042.                 if (!slock) {
  1043.                     dp->dp_Res1 = 0;
  1044.                     dp->dp_Res2 = 0;
  1045.                     break;
  1046.                 }
  1047.                 
  1048.                 verify(slock, V_lock);
  1049.                 
  1050.                 if (slock->fl.fl_Access == EXCLUSIVE_LOCK) {
  1051.                     dp->dp_Res1 = 0;
  1052.                     dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  1053.                     break;
  1054.                 }
  1055.                 
  1056.                 new_lock = (lock *)allocate(sizeof(*new_lock) + strlen(slock->fname) + 1, V_lock);
  1057.                 if (!new_lock) {
  1058.                     dp->dp_Res1 = 0;
  1059.                     dp->dp_Res2 = ERROR_NO_FREE_STORE;
  1060.                     break;
  1061.                 }
  1062.                 
  1063.                 *new_lock = *slock;
  1064.                 strcpy(new_lock->fname, slock->fname);
  1065.                 
  1066.                 new_lock->next = slock->next;
  1067.                 slock->next = new_lock;
  1068.                 
  1069.                 dp->dp_Res1 = (b32)new_lock >> 2;
  1070.                 dp->dp_Res2 = 0;
  1071.                 break;
  1072.             case ACTION_CREATE_DIR:
  1073.                 if (!split_data((lock *)(dp->dp_Arg1 << 2), (b8 *)(dp->dp_Arg2 << 2), &sd)) {
  1074.                     dp->dp_Res1 = 0;
  1075.                     dp->dp_Res2 = ERROR_NO_FREE_STORE;
  1076.                     
  1077.                     break;
  1078.                 }
  1079.                 
  1080.                 if (ftp_site->file_list) {
  1081.                     if (ftp_site->file_list->closed) {
  1082.                         close_file(ftp_site, true);
  1083.                     } else {
  1084.                         dp->dp_Res1 = 0;
  1085.                         dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  1086.                         
  1087.                         end_split(&sd);
  1088.                         
  1089.                         goto reply_msg;
  1090.                     }
  1091.                 }
  1092.                 
  1093.                 new_lock = (lock *)allocate(sizeof(*new_lock) + strlen(sd.path) + 1, V_lock);
  1094.                 if (!new_lock) {
  1095.                     dp->dp_Res1 = 0;
  1096.                     dp->dp_Res2 = ERROR_NO_FREE_STORE;
  1097.                     
  1098.                     end_split(&sd);
  1099.                     
  1100.                     break;
  1101.                 }
  1102.                 
  1103.                 dp->dp_Res2 = make_directory(ftp_site, sd.path);
  1104.                 flush_info(ftp_site, sd.path);
  1105.                 
  1106.                 if (dp->dp_Res2) {
  1107.                     dp->dp_Res1 = 0;
  1108.                     
  1109.                     deallocate(new_lock, V_lock);
  1110.                 } else {
  1111.                     dp->dp_Res1 = (b32)new_lock >> 2;
  1112.                     
  1113.                     ensure(new_lock, V_lock);
  1114.  
  1115.                     new_lock->next = ftp_site->lock_list;
  1116.                     ftp_site->lock_list = new_lock;
  1117.                     
  1118.                     strcpy(new_lock->fname, sd.path);
  1119.  
  1120.                     new_lock->port = local;
  1121.                     new_lock->rfsl = 0;
  1122.                     new_lock->lastkey = 0;
  1123.                     
  1124.                     new_lock->fl.fl_Link = 0;
  1125.                     new_lock->fl.fl_Key = 0;
  1126.                     new_lock->fl.fl_Access = SHARED_LOCK;
  1127.                     new_lock->fl.fl_Task = ftp_port;
  1128.                     new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
  1129.                 }
  1130.                 
  1131.                 end_split(&sd);
  1132.                 
  1133.                 break;
  1134.             case ACTION_EXAMINE_OBJECT:
  1135.                 slock = (lock *)(dp->dp_Arg1 << 2);
  1136.                 fib = (struct FileInfoBlock *)(dp->dp_Arg2 << 2);
  1137.                 
  1138.                 verify(slock, V_lock);
  1139.                 truth(fib != nil);
  1140.                 
  1141.                 if (slock->fname[0] == 0) {
  1142.                     /* root of this site */
  1143.                     fib->fib_DiskKey = 0;
  1144.                     fib->fib_DirEntryType = ST_USERDIR;
  1145.                     fib->fib_EntryType = ST_USERDIR;
  1146.                     
  1147.                     strcpy(&fib->fib_FileName[1], ftp_site->name);
  1148.                     fib->fib_FileName[0] = strlen(ftp_site->name);
  1149.                     
  1150.                     fib->fib_Protection = 0xf;
  1151.                     fib->fib_Size = 0;
  1152.                     fib->fib_NumBlocks = 0;
  1153.                     fib->fib_Date = ftp_volume->dol_misc.dol_volume.dol_VolumeDate;
  1154.                     fib->fib_Comment[0] = 0;
  1155.                     
  1156.                     dp->dp_Res1 = DOSTRUE;
  1157.                     dp->dp_Res2 = 0;
  1158.                     
  1159.                     break;
  1160.                 }
  1161.                 
  1162.                 s = slock->fname + strlen(slock->fname) - 1;
  1163.                 while (s > slock->fname && *s != '/') s--;
  1164.                 
  1165.                 if (s == slock->fname) {
  1166.                     ih = get_dir(ftp_site, "");
  1167.                 } else {
  1168.                     *s = 0;
  1169.                     ih = get_dir(ftp_site, slock->fname);
  1170.                     *s++ = '/';
  1171.                 }
  1172.                 
  1173.                 if (!ih) {
  1174.                     dp->dp_Res1 = DOSFALSE;
  1175.                     if (ftp_site->cfile)
  1176.                         dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  1177.                     else
  1178.                         dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1179.                         /* general "connection buggered" */
  1180.                     break;
  1181.                 }
  1182.                 
  1183.                 fi = find_info(ih, s);
  1184.                 if (!fi) {
  1185.                     dp->dp_Res1 = DOSFALSE;
  1186.                     dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1187.                     break;
  1188.                 }
  1189.                 
  1190.                 if (fi->flags & MYFLAG_DIR) {
  1191.                     fib->fib_DirEntryType = ST_USERDIR;
  1192.                 } else {
  1193.                     fib->fib_DirEntryType = ST_FILE;
  1194.                 }
  1195.                 
  1196.                 fib->fib_EntryType = fib->fib_DirEntryType;
  1197.                 fib->fib_DiskKey = 0;
  1198.                 slock->lastkey = 0;
  1199.                 fib->fib_FileName[0] = strlen(fi->name);
  1200.                 strcpy(&fib->fib_FileName[1], fi->name);
  1201.                 
  1202.                 fib->fib_Protection = fi->flags & 0xff;
  1203.                 fib->fib_Size = fi->size;
  1204.                 fib->fib_NumBlocks = fi->blocks;
  1205.                 fib->fib_Date = fi->modified;
  1206.                 fib->fib_Comment[0] = 0;
  1207.                 
  1208.                 dp->dp_Res1 = DOSTRUE;
  1209.                 dp->dp_Res2 = 0;
  1210.                 break;
  1211.             case ACTION_EXAMINE_NEXT:
  1212.                 slock = (lock *)(dp->dp_Arg1 << 2);
  1213.                 fib = (struct FileInfoBlock *)(dp->dp_Arg2 << 2);
  1214.                 
  1215.                 verify(slock, V_lock);
  1216.                 truth(fib != nil);
  1217.                 
  1218.                 ih = get_dir(ftp_site, slock->fname);
  1219.                 if (!ih) {
  1220.                     dp->dp_Res1 = DOSFALSE;
  1221.                     if (ftp_site->cfile)
  1222.                         dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  1223.                     else
  1224.                         dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1225.                     break;
  1226.                 }
  1227.                 
  1228.                 // n = fib->fib_DiskKey;
  1229.                 n = slock->lastkey;
  1230.                 
  1231.                 slock->lastkey++;
  1232.                 
  1233.                 fi = ih->infos;
  1234.                 while (fi && n) {
  1235.                     fi = fi->next;
  1236.                     n--;
  1237.                 }
  1238.                 
  1239.                 while (fi && fi->flags & MYFLAG_DELETED) {
  1240.                     fi = fi->next;
  1241.                     slock->lastkey++;
  1242.                 }
  1243.                 
  1244.                 fib->fib_DiskKey = slock->lastkey;
  1245.  
  1246.                 if (!fi) {
  1247.                     slock->lastkey = 0;
  1248.                     fib->fib_DiskKey = 0;
  1249.                     dp->dp_Res1 = DOSFALSE;
  1250.                     dp->dp_Res2 = ERROR_NO_MORE_ENTRIES;
  1251.                     break;
  1252.                 }
  1253.                 
  1254.                 if (fi->flags & MYFLAG_DIR) {
  1255.                     fib->fib_DirEntryType = ST_USERDIR;
  1256.                 } else {
  1257.                     fib->fib_DirEntryType = ST_FILE;
  1258.                 }
  1259.                 
  1260.                 fib->fib_EntryType = fib->fib_DirEntryType;
  1261.                 fib->fib_FileName[0] = strlen(fi->name);
  1262.                 strcpy(&fib->fib_FileName[1], fi->name);
  1263.                 
  1264.                 fib->fib_Protection = fi->flags & 0xff;
  1265.                 fib->fib_Size = fi->size;
  1266.                 fib->fib_NumBlocks = fi->blocks;
  1267.                 fib->fib_Date = fi->modified;
  1268.                 fib->fib_Comment[0] = 0;
  1269.                 
  1270.                 dp->dp_Res1 = DOSTRUE;
  1271.                 dp->dp_Res2 = 0;
  1272.                 
  1273.                 break;
  1274.             case ACTION_PARENT:
  1275.                 slock = (lock *)(dp->dp_Arg1 << 2);
  1276.                 if (!slock) {
  1277.                     dp->dp_Res1 = 0;
  1278.                     dp->dp_Res2 = 0;
  1279.                     break;
  1280.                 }
  1281.                 
  1282.                 if (slock->fname[0] == 0) {
  1283.                     /* need root of FTP: (the slimy way) */
  1284.                     dp->dp_Port = ftp_site->sync;
  1285.                     dp->dp_Type = ACTION_LOCATE_OBJECT;
  1286.                     
  1287.                     o1 = dp->dp_Arg1;
  1288.                     o2 = dp->dp_Arg2;
  1289.                     o3 = dp->dp_Arg3;
  1290.                     dp->dp_Arg1 = 0;
  1291.                     dp->dp_Arg2 = (b32)(&("\0\0\0\0"[3])) >> 2;
  1292.                     dp->dp_Arg3 = SHARED_LOCK;
  1293.                     
  1294.                     PutMsg(local_port, dp->dp_Link);
  1295.                     WaitPort(ftp_site->sync); GetMsg(ftp_site->sync);
  1296.                     
  1297.                     dp->dp_Arg1 = o1;
  1298.                     dp->dp_Arg2 = o2;
  1299.                     dp->dp_Arg3 = o3;
  1300.                     dp->dp_Type = ACTION_PARENT;
  1301.                     break;
  1302.                 }
  1303.                 
  1304.                 s = slock->fname + strlen(slock->fname) - 1;
  1305.                 while (s > slock->fname && *s != '/') s--;
  1306.                 
  1307.                 if (s == slock->fname) {
  1308.                     new_lock = (lock *)allocate(sizeof(*new_lock) + 1, V_lock);
  1309.                     if (!new_lock) {
  1310.                         dp->dp_Res1 = 0;
  1311.                         dp->dp_Res2 = ERROR_NO_FREE_STORE;
  1312.                         
  1313.                         break;
  1314.                     }
  1315.                     
  1316.                     ensure(new_lock, V_lock);
  1317.                     
  1318.                     new_lock->next = ftp_site->lock_list;
  1319.                     ftp_site->lock_list = new_lock;
  1320.                     
  1321.                     new_lock->port = local;
  1322.                     new_lock->rfsl = 0;
  1323.                     new_lock->fname[0] = 0;
  1324.                     
  1325.                     new_lock->fl.fl_Link = 0;
  1326.                     new_lock->fl.fl_Key = 0;
  1327.                     new_lock->fl.fl_Access = SHARED_LOCK;
  1328.                     new_lock->fl.fl_Task = ftp_port;
  1329.                     new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
  1330.                     
  1331.                     dp->dp_Res1 = (b32)new_lock >> 2;
  1332.                     dp->dp_Res2 = 0;
  1333.                 } else {
  1334.                     *s = 0;
  1335.                     
  1336.                     new_lock = (lock *)allocate(sizeof(*new_lock) + strlen(slock->fname) + 1, V_lock);
  1337.                     if (!new_lock) {
  1338.                         *s = '/';
  1339.                         
  1340.                         dp->dp_Res1 = 0;
  1341.                         dp->dp_Res2 = ERROR_NO_FREE_STORE;
  1342.                         break;
  1343.                     }
  1344.                     
  1345.                     ensure(new_lock, V_lock);
  1346.                     
  1347.                     strcpy(new_lock->fname, slock->fname);
  1348.                     
  1349.                     *s = '/';
  1350.  
  1351.                     new_lock->port = local;
  1352.                     new_lock->rfsl = 0;
  1353.                     
  1354.                     new_lock->fl.fl_Link = 0;
  1355.                     new_lock->fl.fl_Key = 0;
  1356.                     new_lock->fl.fl_Access = SHARED_LOCK;
  1357.                     new_lock->fl.fl_Task = ftp_port;
  1358.                     new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
  1359.                     
  1360.                     /* search for a conflicting lock */
  1361.                     
  1362.                     slock = ftp_site->lock_list;
  1363.                     while (slock) {
  1364.                         if (strcmp(new_lock->fname, slock->fname) == 0) {
  1365.                             if (slock->fl.fl_Access == EXCLUSIVE_LOCK) {
  1366.                                 dp->dp_Res1 = 0;
  1367.                                 dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  1368.                                 
  1369.                                 deallocate(new_lock, V_lock);
  1370.                                 goto reply_msg;
  1371.                             }
  1372.                             
  1373.                             /* ok, this one is guaranteed to work */
  1374.                             
  1375.                             new_lock->next = ftp_site->lock_list;
  1376.                             ftp_site->lock_list = new_lock;
  1377.                             
  1378.                             dp->dp_Res1 = (b32)new_lock >> 2;
  1379.                             dp->dp_Res2 = 0;
  1380.                             
  1381.                             goto reply_msg;
  1382.                         }
  1383.                         slock = slock->next;
  1384.                     }
  1385.                     
  1386.                     /* ok, it doesn't conflict ... it must exist*/
  1387.                     
  1388.                     new_lock->next = ftp_site->lock_list;
  1389.                     ftp_site->lock_list = new_lock;
  1390.                     
  1391.                     dp->dp_Res1 = (b32)new_lock >> 2;
  1392.                     dp->dp_Res2 = 0;
  1393.                 }
  1394.                 break;
  1395.             case ACTION_SAME_LOCK:
  1396.                 slock = (lock *)(dp->dp_Arg1 << 2);
  1397.                 new_lock = (lock *)(dp->dp_Arg2 << 2);
  1398.                 
  1399.                 verify(slock, V_lock);
  1400.                 verify(new_lock, V_lock);
  1401.                 
  1402.                 if (strcmp(slock->fname, new_lock->fname) == 0) {
  1403.                     dp->dp_Res1 = DOSTRUE;
  1404.                     dp->dp_Res2 = 0;
  1405.                 } else {
  1406.                     dp->dp_Res1 = DOSFALSE;
  1407.                     dp->dp_Res2 = 0;
  1408.                 }
  1409.                 break;
  1410.             case ACTION_READ:
  1411.                 fip = (file_info *)dp->dp_Arg1;
  1412.                 verify(fip, V_file_info);
  1413.                 
  1414.                 if (!ftp_site->connected || ftp_site->cfile == nil) {
  1415.                     dp->dp_Res1 = 0;
  1416.                     dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1417.                     break;
  1418.                 }
  1419.                 
  1420.                 if (ftp_site->cfile_type != ACTION_FINDINPUT) {
  1421.                     dp->dp_Res1 = 0;
  1422.                     dp->dp_Res2 = ERROR_READ_PROTECTED;
  1423.                     break;
  1424.                 }
  1425.                 
  1426.                 if (fip->seek_end) {    /* artificially at end */
  1427.                     dp->dp_Res1 = 0;
  1428.                     dp->dp_Res2 = 0;
  1429.                     break;
  1430.                 }
  1431.                 
  1432.                 state_change(ftp_site, SS_READING);
  1433.                 
  1434.                 o1 = dp->dp_Arg3;
  1435.                 s = (b8 *)dp->dp_Arg2;
  1436.                 
  1437.                 if (o1 == 0) {
  1438.                     dp->dp_Res1 = 0;
  1439.                     dp->dp_Res2 = 0;
  1440.                     break;
  1441.                 }
  1442.                 
  1443.                 if (fip->vpos < FIRST_BLOCK_SIZE && fip->vpos < fip->rpos) {
  1444.                     o2 = o1;
  1445.                     if (o2 > FIRST_BLOCK_SIZE - fip->vpos) o2 = FIRST_BLOCK_SIZE - fip->vpos;
  1446.                     if (o2 > fip->rpos - fip->vpos) o2 = fip->rpos - fip->vpos;
  1447.                     
  1448.                     memcpy(s, &fip->first_block[fip->vpos], o2);
  1449.                     
  1450.                     fip->vpos += o2;
  1451.                     
  1452.                     if (o2 == o1) {
  1453.                         dp->dp_Res1 = o1;
  1454.                         dp->dp_Res2 = 0;
  1455.                     
  1456.                         break;
  1457.                     } else {
  1458.                         s += o2;
  1459.                         o1 -= o2;
  1460.                     }
  1461.                 }
  1462.                 
  1463.                 if (fip->vpos != fip->rpos) {
  1464.                     dp->dp_Res1 = -1;
  1465.                     dp->dp_Res2 = ERROR_SEEK_ERROR;
  1466.                     break;
  1467.                 }
  1468.                 
  1469.                 while (o1) {
  1470.                     if (o1 > MAX_READ_SIZE) {
  1471.                         o2 = MAX_READ_SIZE;
  1472.                         o1 -= o2;
  1473.                     } else {
  1474.                         o2 = o1;
  1475.                         o1 = 0;
  1476.                     }
  1477.                     switch (read_file(ftp_site, s, &o2)) {
  1478.                     case NO_ERROR:
  1479.                         s += o2;
  1480.                         break;
  1481.                     case ERROR_EOF:
  1482.                         s += o2;
  1483.                         dp->dp_Res1 = s - (b8 *)dp->dp_Arg2;
  1484.                         dp->dp_Res2 = 0;
  1485.                         o1 = 0;
  1486.                         fip->eof = true;
  1487.                         break;
  1488.                     default:
  1489.                         dp->dp_Res1 = -1;
  1490.                         dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1491.                         o1 = 0;
  1492.                         break;
  1493.                     }
  1494.                     fip->rpos += o2;
  1495.                     fip->vpos = fip->rpos;
  1496.                     tsm = get_sm(ftp_site);
  1497.                     if (tsm) {
  1498.                         tsm->command = SM_PROGRESS;
  1499.                         PutMsg(status_port, &tsm->header);
  1500.                     }
  1501.                 }
  1502.                 
  1503.                 dp->dp_Res1 = s - (b8 *)dp->dp_Arg2;
  1504.                 dp->dp_Res2 = 0;
  1505.                 
  1506.                 break;
  1507.             case ACTION_WRITE:
  1508.                 fip = (file_info *)dp->dp_Arg1;
  1509.                 verify(fip, V_file_info);
  1510.                 
  1511.                 if (!ftp_site->connected || ftp_site->cfile == nil) {
  1512.                     dp->dp_Res1 = 0;
  1513.                     dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1514.                     break;
  1515.                 }
  1516.                 
  1517.                 if (ftp_site->cfile_type != ACTION_FINDOUTPUT) {
  1518.                     dp->dp_Res1 = 0;
  1519.                     dp->dp_Res2 = ERROR_WRITE_PROTECTED;
  1520.                     break;
  1521.                 }
  1522.                 
  1523.                 state_change(ftp_site, SS_WRITING);
  1524.  
  1525.                 o1 = dp->dp_Arg3;
  1526.                 s = (b8 *)dp->dp_Arg2;
  1527.                 
  1528.                 if (o1 == 0) {
  1529.                     dp->dp_Res1 = 0;
  1530.                     dp->dp_Res2 = 0;
  1531.                     break;
  1532.                 }
  1533.                 
  1534.                 if (fip->vpos != fip->rpos) {
  1535.                     dp->dp_Res1 = -1;
  1536.                     dp->dp_Res2 = ERROR_SEEK_ERROR;
  1537.                     break;
  1538.                 }
  1539.                 
  1540.                 while (o1) {
  1541.                     if (o1 > MAX_READ_SIZE) {
  1542.                         o2 = MAX_READ_SIZE;
  1543.                         o1 -= o2;
  1544.                     } else {
  1545.                         o2 = o1;
  1546.                         o1 = 0;
  1547.                     }
  1548.                     switch (write_file(ftp_site, s, &o2)) {
  1549.                     case NO_ERROR:
  1550.                         s += o2;
  1551.                         break;
  1552.                     case ERROR_EOF:
  1553.                         s += o2;
  1554.                         dp->dp_Res1 = s - (b8 *)dp->dp_Arg2;
  1555.                         dp->dp_Res2 = 0;
  1556.                         o1 = 0;
  1557.                         fip->eof = true;
  1558.                         break;
  1559.                     default:
  1560.                         dp->dp_Res1 = -1;
  1561.                         dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1562.                         o1 = 0;
  1563.                         break;
  1564.                     }
  1565.                     fip->rpos += o2;
  1566.                     fip->vpos = fip->rpos;
  1567.                     tsm = get_sm(ftp_site);
  1568.                     if (tsm) {
  1569.                         tsm->command = SM_PROGRESS;
  1570.                         PutMsg(status_port, &tsm->header);
  1571.                     }
  1572.                 }
  1573.                 
  1574.                 dp->dp_Res1 = s - (b8 *)dp->dp_Arg2;
  1575.                 dp->dp_Res2 = 0;
  1576.  
  1577.                 break;
  1578.             case ACTION_FINDINPUT:
  1579.             case ACTION_FINDOUTPUT:
  1580.                 if (!split_data((lock *)(dp->dp_Arg2 << 2),
  1581.                             (b8 *)(dp->dp_Arg3 << 2), &sd)) {
  1582.                     dp->dp_Res1 = DOSFALSE;
  1583.                     dp->dp_Res2 = ERROR_NO_FREE_STORE;
  1584.                     break;
  1585.                 }
  1586.                 
  1587.                 if (!ftp_site->connected) 
  1588.                     init_connect(ftp_site);
  1589.                 
  1590.                 if (!ftp_site->connected) {
  1591.                     dp->dp_Res1 = DOSFALSE;
  1592.                     dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1593.                     
  1594.                     end_split(&sd);
  1595.                     break;
  1596.                 }
  1597.                 
  1598.                 if (ftp_site->cfile) {
  1599.                     fip = ftp_site->file_list;
  1600.                     verify(fip, V_file_info);
  1601.                     
  1602.                     if (fip->closed) {
  1603.                         if (strcmp(sd.path, fip->fname) == 0 &&
  1604.                                 dp->dp_Type == ACTION_FINDINPUT) {
  1605.                             /* "reopen" this file */
  1606.                             fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
  1607.                 
  1608.                             truth(fh != nil);
  1609.                 
  1610.                             fh->fh_Type = ftp_port;
  1611.                             fh->fh_Args = (b32)fip;
  1612.                 
  1613.                             fip->closed = false;
  1614.                             fip->vpos = 0;
  1615.                             fip->seek_end = false;
  1616.                             
  1617.                             dp->dp_Res1 = DOSTRUE;
  1618.                             dp->dp_Res2 = 0;
  1619.                             
  1620.                             end_split(&sd);
  1621.                             break;
  1622.                         }
  1623.                         
  1624.                         close_file(ftp_site, true);
  1625.                     } else {
  1626.                         /* only one file at a time!  :( */
  1627.                         dp->dp_Res1 = DOSFALSE;
  1628.                         dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  1629.                     
  1630.                         end_split(&sd);
  1631.                         break;
  1632.                     }
  1633.                 }
  1634.                 
  1635.                 /* search for a conflicting lock */
  1636.                     
  1637.                 slock = ftp_site->lock_list;
  1638.                 while (slock) {
  1639.                     if (strcmp(sd.path, slock->fname) == 0) {
  1640.                         if (dp->dp_Type == ACTION_FINDOUTPUT || slock->fl.fl_Access == EXCLUSIVE_LOCK) {
  1641.                             dp->dp_Res1 = 0;
  1642.                             dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  1643.                             
  1644.                             end_split(&sd);
  1645.                             
  1646.                             goto reply_msg;
  1647.                         }
  1648.                     }
  1649.                     slock = slock->next;
  1650.                 }
  1651.                 
  1652.                 /* make sure we have information on this file BEFORE we start */
  1653.                 
  1654.                 if (dp->dp_Type == ACTION_FINDINPUT) {
  1655.                     fi = get_info(ftp_site, sd.path);
  1656.                 //    if (!fi) {
  1657.                 //        dp->dp_Res1 = 0;
  1658.                 //        dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1659.                 //        
  1660.                 //        end_split(&sd);
  1661.                 //    
  1662.                 //        break;
  1663.                 //    }
  1664.                 } else {
  1665.                     fi = nil;
  1666.                 }
  1667.                 
  1668.                 if (dp->dp_Type == ACTION_FINDINPUT) {
  1669.                     if (fi) {
  1670.                         dp->dp_Res2 = open_file(ftp_site, sd.path, false, fi->name);
  1671.                     } else {
  1672.                         dp->dp_Res2 = open_file(ftp_site, sd.path, false, nil);
  1673.                     }
  1674.                 } else {
  1675.                     dp->dp_Res2 = open_file(ftp_site, sd.path, true, nil);
  1676.                     flush_info(ftp_site, sd.path);
  1677.                 }
  1678.                 
  1679.                 if (dp->dp_Res2 != 0) {
  1680.                     end_split(&sd);
  1681.                     
  1682.                     dp->dp_Res1 = 0;
  1683.                     break;
  1684.                 }
  1685.                 
  1686.                 fip = ftp_site->file_list;
  1687.                 
  1688.                 if (fi) {
  1689.                     fip->end = fi->size;
  1690.                 } else {
  1691.                     fip->end = 0;
  1692.                 }
  1693.  
  1694.                 fip->port = local;
  1695.                 fip->type = ftp_site->cfile_type = dp->dp_Type;
  1696.                 
  1697.                 end_split(&sd);
  1698.                 
  1699.                 fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
  1700.                 
  1701.                 truth(fh != nil);
  1702.                 
  1703.                 fh->fh_Type = ftp_port;
  1704.                 fh->fh_Args = (b32)fip;
  1705.                 
  1706.                 if (dp->dp_Type == ACTION_FINDINPUT) {
  1707.                     o1 = FIRST_BLOCK_SIZE;
  1708.                     switch (read_file(ftp_site, fip->first_block, &o1)) {
  1709.                     case ERROR_EOF:
  1710.                         fip->eof = true;
  1711.                     case NO_ERROR:
  1712.                         fip->rpos = o1;
  1713.                         
  1714.                         dp->dp_Res1 = DOSTRUE;
  1715.                         dp->dp_Res2 = 0;
  1716.                         
  1717.                         break;
  1718.                     default:
  1719.                         close_file(ftp_site, true);
  1720.                         
  1721.                         dp->dp_Res1 = DOSFALSE;
  1722.                         dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1723.                         
  1724.                         break;
  1725.                     }
  1726.                 } else {
  1727.                     dp->dp_Res1= DOSTRUE;
  1728.                     dp->dp_Res2 = 0;
  1729.                 }
  1730.  
  1731.                 break;
  1732.             case ACTION_END:
  1733.                 fip = (file_info *)dp->dp_Arg1;
  1734.                 
  1735.                 verify(fip, V_file_info);
  1736.                 
  1737.                 if (fip->type == ACTION_FINDINPUT && fip->rpos <= FIRST_BLOCK_SIZE) {
  1738.                     fip->closed = true;
  1739.                 } else {
  1740.                     close_file(ftp_site, true);
  1741.                 }
  1742.                 
  1743.                 dp->dp_Res1 = DOSTRUE;
  1744.                 dp->dp_Res2 = 0;
  1745.                 
  1746.                 break;
  1747.             case ACTION_SEEK:
  1748.                 fip = (file_info *)dp->dp_Arg1;
  1749.                 verify(fip, V_file_info);
  1750.                 
  1751.                 if (dp->dp_Arg3 == OFFSET_END && dp->dp_Arg2 == 0) {
  1752.                     /* go to the end of the file ... really we are :) */
  1753.                     
  1754.                     if (fip->seek_end) {
  1755.                         dp->dp_Res1 = fip->end;
  1756.                         dp->dp_Res2 = 0;
  1757.                         break;
  1758.                     }
  1759.                     
  1760.                     if (fip->type == ACTION_FINDINPUT)
  1761.                         fip->seek_end = true;
  1762.                     
  1763.                     dp->dp_Res1 = fip->vpos;
  1764.                     dp->dp_Res2 = 0;
  1765.                     
  1766.                     break;
  1767.                 }
  1768.                 
  1769.                 if (dp->dp_Arg3 == OFFSET_BEGINNING) {
  1770.                     o1 = dp->dp_Arg2;
  1771.                 } else if (dp->dp_Arg3 == OFFSET_END) {
  1772.                     o1 = fip->end + dp->dp_Arg2;
  1773.                 } else if (dp->dp_Arg3 == OFFSET_CURRENT) {
  1774.                     o1 = fip->vpos + dp->dp_Arg2;
  1775.                 }
  1776.                 
  1777.                 if (o1 == fip->vpos) {
  1778.                     /* not actually moving */
  1779.                     
  1780.                     if (fip->seek_end) {
  1781.                         dp->dp_Res1 = fip->end;
  1782.                         dp->dp_Res2 = 0;
  1783.                         
  1784.                         fip->seek_end = false;
  1785.                     } else {
  1786.                         dp->dp_Res1 = fip->vpos;
  1787.                         dp->dp_Res2 = 0;
  1788.                     }
  1789.                     break;
  1790.                 }
  1791.                 
  1792.                 if (o1 == fip->rpos) {
  1793.                     /* not _really_ moving */
  1794.                     
  1795.                     if (fip->seek_end) {
  1796.                         dp->dp_Res1 = fip->end;
  1797.                         dp->dp_Res2 = 0;
  1798.                         
  1799.                         fip->seek_end = false;
  1800.                     } else {
  1801.                         dp->dp_Res1 = fip->vpos;
  1802.                         dp->dp_Res2 = 0;
  1803.                     }
  1804.                     
  1805.                     fip->vpos = fip->rpos;
  1806.                     break;
  1807.                 }
  1808.  
  1809.                 if (o1 < fip->rpos && o1 < FIRST_BLOCK_SIZE) {
  1810.                     /* seeking into our stored first block */
  1811.                     if (fip->seek_end) {
  1812.                         dp->dp_Res1 = fip->end;
  1813.                         dp->dp_Res2 = 0;
  1814.                         
  1815.                         fip->seek_end = false;
  1816.                     } else {
  1817.                         dp->dp_Res1 = fip->vpos;
  1818.                         dp->dp_Res2 = 0;
  1819.                     }
  1820.                     fip->vpos = o1;
  1821.                     break;
  1822.                 }
  1823.                 
  1824.                 show_string("SEEK:");
  1825.                 show_int(dp->dp_Arg2);
  1826.                 show_int(dp->dp_Arg3);
  1827.                 dp->dp_Res1 = DOSFALSE;
  1828.                 dp->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  1829.                 break;
  1830.             case ACTION_FH_FROM_LOCK:
  1831.                 fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
  1832.                 slock = (lock *)(dp->dp_Arg2 << 2);
  1833.                 
  1834.                 truth(fh != nil);
  1835.                 verify(slock, V_lock);
  1836.                 
  1837.                 if (!ftp_site->connected) 
  1838.                     init_connect(ftp_site);
  1839.                 
  1840.                 if (!ftp_site->connected) {
  1841.                     dp->dp_Res1 = DOSFALSE;
  1842.                     dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1843.                     
  1844.                     break;
  1845.                 }
  1846.                 
  1847.                 if (ftp_site->cfile) {
  1848.                     fip = ftp_site->file_list;
  1849.                     verify(fip, V_file_info);
  1850.                     
  1851.                     if (fip->closed) {
  1852.                         if (strcmp(slock->fname, fip->fname) == 0 &&
  1853.                                 slock->fl.fl_Access == SHARED_LOCK) {
  1854.                             /* "reopen" this file */
  1855.                 
  1856.                             fh->fh_Type = ftp_port;
  1857.                             fh->fh_Args = (b32)fip;
  1858.                 
  1859.                             fip->closed = false;
  1860.                             fip->vpos = 0;
  1861.                             fip->seek_end = false;
  1862.                             
  1863.                             dp->dp_Res1 = DOSTRUE;
  1864.                             dp->dp_Res2 = 0;
  1865.  
  1866.                             break;
  1867.                         }
  1868.                         
  1869.                         close_file(ftp_site, true);
  1870.                     } else {
  1871.                         /* only one file at a time!  :( */
  1872.                         dp->dp_Res1 = DOSFALSE;
  1873.                         dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  1874.                         break;
  1875.                     }
  1876.                 }
  1877.                 
  1878.                 if (slock->fl.fl_Access == SHARED_LOCK) {
  1879.                     fi = get_info(ftp_site, slock->fname);
  1880.                 } else {
  1881.                     fi = nil;
  1882.                 }
  1883.                 
  1884.                 if (slock->fl.fl_Access == SHARED_LOCK) {
  1885.                     if (fi) {
  1886.                         dp->dp_Res2 = open_file(ftp_site, slock->fname, false, fi->name);
  1887.                     } else {
  1888.                         dp->dp_Res2 = open_file(ftp_site, slock->fname, false, nil);
  1889.                     }
  1890.                 } else {
  1891.                     dp->dp_Res2 = open_file(ftp_site, slock->fname, true, nil);
  1892.                     flush_info(ftp_site, slock->fname);
  1893.                 }
  1894.                 
  1895.                 if (dp->dp_Res2 != 0) {
  1896.                     dp->dp_Res1 = 0;
  1897.                     break;
  1898.                 }
  1899.                 
  1900.                 fip = ftp_site->file_list;
  1901.                 
  1902.                 if (fi) {
  1903.                     fip->end = fi->size;
  1904.                 } else {
  1905.                     fip->end = 0;
  1906.                 }
  1907.  
  1908.                 fip->port = local;
  1909.                 
  1910.                 if (slock->fl.fl_Access == SHARED_LOCK) {
  1911.                     fip->type = ftp_site->cfile_type = ACTION_FINDINPUT;
  1912.                 } else {
  1913.                     fip->type = ftp_site->cfile_type = ACTION_FINDOUTPUT;
  1914.                 }
  1915.                 
  1916.                 fh->fh_Type = ftp_port;
  1917.                 fh->fh_Args = (b32)fip;
  1918.                 
  1919.                 if (slock->fl.fl_Access == SHARED_LOCK) {
  1920.                     o1 = FIRST_BLOCK_SIZE;
  1921.                     switch (read_file(ftp_site, fip->first_block, &o1)) {
  1922.                     case ERROR_EOF:
  1923.                         fip->eof = true;
  1924.                     case NO_ERROR:
  1925.                         fip->rpos = o1;
  1926.                         
  1927.                         dp->dp_Res1 = DOSTRUE;
  1928.                         dp->dp_Res2 = 0;
  1929.                         
  1930.                         break;
  1931.                     default:
  1932.                         close_file(ftp_site, true);
  1933.                         
  1934.                         dp->dp_Res1 = DOSFALSE;
  1935.                         dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1936.                         
  1937.                         break;
  1938.                     }
  1939.                 } else {
  1940.                     dp->dp_Res1= DOSTRUE;
  1941.                     dp->dp_Res2 = 0;
  1942.                 }
  1943.                 
  1944.                 if (dp->dp_Res1) {
  1945.                     /* close the lock */
  1946.                     ensure(slock, 0);
  1947.                     
  1948.                     locks = &ftp_site->lock_list;
  1949.                     while (*locks && *locks != slock) {
  1950.                         locks = &(*locks)->next;
  1951.                     }
  1952.                 
  1953.                     if (*locks) {
  1954.                         *locks = slock->next;
  1955.                         deallocate(slock, V_lock);
  1956.                     }
  1957.                 }
  1958.  
  1959.                 break;
  1960.             case ACTION_COPY_DIR_FH:
  1961.                 fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
  1962.                 if (!fh) {
  1963.                     dp->dp_Res1 = 0;
  1964.                     dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  1965.                     break;
  1966.                 }
  1967.                 
  1968.                 fip = (file_info *)fh->fh_Args;
  1969.                 
  1970.                 verify(fip, V_file_info);
  1971.                 
  1972.                 if (fip->type == ACTION_FINDOUTPUT) {
  1973.                     dp->dp_Res1 = 0;
  1974.                     dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  1975.                     break;
  1976.                 }
  1977.                 
  1978.                 new_lock = (lock *)allocate(sizeof(*new_lock) + strlen(fip->fname) + 1, V_lock);
  1979.                 if (!new_lock) {
  1980.                     dp->dp_Res1 = 0;
  1981.                     dp->dp_Res2 = ERROR_NO_FREE_STORE;
  1982.                     break;
  1983.                 }
  1984.                 
  1985.                 new_lock->port = local;
  1986.                 new_lock->rfsl = 0;
  1987.                 new_lock->lastkey = 0;
  1988.                 
  1989.                 new_lock->fl.fl_Link = 0;
  1990.                 new_lock->fl.fl_Key = 0;
  1991.                 new_lock->fl.fl_Access = SHARED_LOCK;
  1992.                 new_lock->fl.fl_Task = ftp_port;
  1993.                 new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
  1994.                     
  1995.                 strcpy(new_lock->fname, fip->fname);
  1996.                 
  1997.                 new_lock->next = ftp_site->lock_list;
  1998.                 ftp_site->lock_list = new_lock;
  1999.                 
  2000.                 dp->dp_Res1 = (b32)new_lock >> 2;
  2001.                 dp->dp_Res2 = 0;
  2002.                 
  2003.                 break;
  2004.             case ACTION_PARENT_FH:
  2005.                 fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
  2006.                 if (!fh) {
  2007.                     dp->dp_Res1 = 0;
  2008.                     dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  2009.                     break;
  2010.                 }
  2011.                 
  2012.                 fip = (file_info *)fh->fh_Args;
  2013.                 
  2014.                 verify(fip, V_file_info);
  2015.                 
  2016.                 s = fip->fname + strlen(fip->fname) - 1;
  2017.                 while (s > fip->fname && *s != '/') s--;
  2018.                 
  2019.                 if (s == fip->fname) {
  2020.                     new_lock = (lock *)allocate(sizeof(*new_lock) + 1, V_lock);
  2021.                     if (!new_lock) {
  2022.                         dp->dp_Res1 = 0;
  2023.                         dp->dp_Res2 = ERROR_NO_FREE_STORE;
  2024.                         
  2025.                         break;
  2026.                     }
  2027.                     
  2028.                     ensure(new_lock, V_lock);
  2029.                     
  2030.                     new_lock->next = ftp_site->lock_list;
  2031.                     ftp_site->lock_list = new_lock;
  2032.                     
  2033.                     new_lock->port = local;
  2034.                     new_lock->rfsl = 0;
  2035.                     new_lock->fname[0] = 0;
  2036.                     
  2037.                     new_lock->fl.fl_Link = 0;
  2038.                     new_lock->fl.fl_Key = 0;
  2039.                     new_lock->fl.fl_Access = SHARED_LOCK;
  2040.                     new_lock->fl.fl_Task = ftp_port;
  2041.                     new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
  2042.                     
  2043.                     dp->dp_Res1 = (b32)new_lock >> 2;
  2044.                     dp->dp_Res2 = 0;
  2045.                 } else {
  2046.                     *s = 0;
  2047.                     
  2048.                     new_lock = (lock *)allocate(sizeof(*new_lock) + strlen(fip->fname) + 1, V_lock);
  2049.                     if (!new_lock) {
  2050.                         *s = '/';
  2051.                         
  2052.                         dp->dp_Res1 = 0;
  2053.                         dp->dp_Res2 = ERROR_NO_FREE_STORE;
  2054.                         break;
  2055.                     }
  2056.                     
  2057.                     ensure(new_lock, V_lock);
  2058.                     
  2059.                     strcpy(new_lock->fname, fip->fname);
  2060.                     
  2061.                     *s = '/';
  2062.  
  2063.                     new_lock->port = local;
  2064.                     new_lock->rfsl = 0;
  2065.                     
  2066.                     new_lock->fl.fl_Link = 0;
  2067.                     new_lock->fl.fl_Key = 0;
  2068.                     new_lock->fl.fl_Access = SHARED_LOCK;
  2069.                     new_lock->fl.fl_Task = ftp_port;
  2070.                     new_lock->fl.fl_Volume = (b32)ftp_volume >> 2;
  2071.                     
  2072.                     /* search for a conflicting lock */
  2073.                     
  2074.                     slock = ftp_site->lock_list;
  2075.                     while (slock) {
  2076.                         if (strcmp(new_lock->fname, slock->fname) == 0) {
  2077.                             if (slock->fl.fl_Access == EXCLUSIVE_LOCK) {
  2078.                                 dp->dp_Res1 = 0;
  2079.                                 dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  2080.                                 
  2081.                                 deallocate(new_lock, V_lock);
  2082.                                 goto reply_msg;
  2083.                             }
  2084.                             
  2085.                             /* ok, this one is guaranteed to work */
  2086.                             
  2087.                             new_lock->next = ftp_site->lock_list;
  2088.                             ftp_site->lock_list = new_lock;
  2089.                             
  2090.                             dp->dp_Res1 = (b32)new_lock >> 2;
  2091.                             dp->dp_Res2 = 0;
  2092.                             
  2093.                             goto reply_msg;
  2094.                         }
  2095.                         slock = slock->next;
  2096.                     }
  2097.                     
  2098.                     /* ok, it doesn't conflict ... it must exist*/
  2099.                     
  2100.                     new_lock->next = ftp_site->lock_list;
  2101.                     ftp_site->lock_list = new_lock;
  2102.                     
  2103.                     dp->dp_Res1 = (b32)new_lock >> 2;
  2104.                     dp->dp_Res2 = 0;
  2105.                 }
  2106.                 break;
  2107.             case ACTION_EXAMINE_FH:
  2108.                 fh = (struct FileHandle *)(dp->dp_Arg1 << 2);
  2109.                 fip = (file_info *)fh->fh_Args;
  2110.                 
  2111.                 verify(fip, V_file_info);
  2112.                 
  2113.                 fib = (struct FileInfoBlock *)(dp->dp_Arg2 << 2);
  2114.                 
  2115.                 truth(fib != nil);
  2116.                 
  2117.                 s = fip->fname + strlen(fip->fname) - 1;
  2118.                 while (s > fip->fname && *s != '/') s--;
  2119.                 
  2120.                 if (s == fip->fname) {
  2121.                     ih = get_dir(ftp_site, "");
  2122.                 } else {
  2123.                     *s = 0;
  2124.                     ih = get_dir(ftp_site, fip->fname);
  2125.                     *s++ = '/';
  2126.                 }
  2127.                 
  2128.                 if (!ih) {
  2129.                     dp->dp_Res1 = DOSFALSE;
  2130.                     if (ftp_site->cfile)
  2131.                         dp->dp_Res2 = ERROR_OBJECT_IN_USE;
  2132.                     else
  2133.                         dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  2134.                         /* general "connection buggered" */
  2135.                     break;
  2136.                 }
  2137.                 
  2138.                 fi = find_info(ih, s);
  2139.                 if (!fi) {
  2140.                     dp->dp_Res1 = DOSFALSE;
  2141.                     dp->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  2142.                     break;
  2143.                 }
  2144.                 
  2145.                 if (fi->flags & MYFLAG_DIR) {
  2146.                     fib->fib_DirEntryType = ST_USERDIR;
  2147.                 } else {
  2148.                     fib->fib_DirEntryType = ST_FILE;
  2149.                 }
  2150.                 
  2151.                 fib->fib_EntryType = fib->fib_DirEntryType;
  2152.                 fib->fib_DiskKey = 0;
  2153.                 fib->fib_FileName[0] = strlen(fi->name);
  2154.                 strcpy(&fib->fib_FileName[1], fi->name);
  2155.                 
  2156.                 fib->fib_Protection = fi->flags & 0xff;
  2157.                 fib->fib_Size = fi->size;
  2158.                 fib->fib_NumBlocks = fi->blocks;
  2159.                 fib->fib_Date = fi->modified;
  2160.                 fib->fib_Comment[0] = 0;
  2161.                 
  2162.                 dp->dp_Res1 = DOSTRUE;
  2163.                 dp->dp_Res2 = 0;
  2164.                 break;
  2165.             case action_SUSPEND:
  2166.                 if (ftp_site->connected) {
  2167.                     disconnect(ftp_site);
  2168.                 }
  2169.                 
  2170.                 dp->dp_Res1 = DOSTRUE;
  2171.                 dp->dp_Res2 = 0;
  2172.                 
  2173.                 dp->dp_Port = ftp_port;
  2174.                 PutMsg(reply, dp->dp_Link);
  2175.                 
  2176.                 idle_packet->sp_Pkt.dp_Port = sync;
  2177.                 PutMsg(ftp_port, &idle_packet->sp_Msg);
  2178.                 WaitPort(sync); GetMsg(sync);
  2179.  
  2180.                 continue;
  2181.             default:
  2182.                 show_int(dp->dp_Type);
  2183.                 dp->dp_Res1 = DOSFALSE;
  2184.                 dp->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  2185.                 break;
  2186.             }
  2187.             
  2188. reply_msg:
  2189.             dp->dp_Port = ftp_port;
  2190.             PutMsg(reply, dp->dp_Link);
  2191.         }
  2192.     }
  2193. }
  2194.