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