home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / FTPMOUNT.LZX / FTPMount-0.7 / Source / request.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-06  |  37.1 KB  |  1,622 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 <intuition/intuition.h>
  13. #include <intuition/sghooks.h>
  14.  
  15. #include <dos/dos.h>
  16. #include <dos/dosextens.h>
  17.  
  18. #include <libraries/commodities.h>
  19. #include <libraries/gadtools.h>
  20.  
  21. #include <proto/exec.h>
  22. #include <proto/graphics.h>
  23. #include <proto/intuition.h>
  24. #include <proto/commodities.h>
  25. #include <proto/gadtools.h>
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30.  
  31. #include "evtypes.h"
  32. #include "verify.h"
  33. #include "ftp.h"
  34. #include "site.h"
  35.  
  36. #include "globals.h"
  37. #include "strings.h"
  38.  
  39. #include "request.h"
  40.  
  41. #define V_IntuiText 18798
  42. #define V_Gadget 18273
  43.  
  44. #define V_rastport 1001
  45. #define V_bitmap 1008
  46.  
  47. struct RastPort *make_rastport(b32 width, b32 height, b32 depth, struct GfxBase *GfxBase)
  48. {
  49.     struct RastPort *rp;
  50.     struct BitMap *bm;
  51.     int i;
  52.     b8 *z;
  53.     
  54.     rp = (struct RastPort *)allocate_flags(sizeof(*rp), MEMF_PUBLIC | MEMF_CLEAR, V_rastport);
  55.     if (!rp) return 0;
  56.     
  57.     bm = (struct BitMap *)allocate_flags(sizeof(*bm), MEMF_PUBLIC | MEMF_CLEAR, V_bitmap);
  58.     if (bm) {        
  59.         InitBitMap(bm, depth, width, height);
  60.         
  61.         bm->Planes[0] = AllocRaster(width, height * depth);
  62.         if (bm->Planes[0]) {
  63.             z = (b8 *)bm->Planes[0];
  64.             for (i = 1; i < depth; i++) {
  65.                 z += bm->BytesPerRow * bm->Rows;
  66.                 bm->Planes[i] = (void *)z;
  67.             }
  68.             InitRastPort(rp);
  69.             
  70.             rp->BitMap = bm;
  71.             rp->Mask = 0xff;
  72.             
  73.             return rp;
  74.         }
  75.         
  76.         deallocate(bm, V_bitmap);
  77.     }
  78.     
  79.     deallocate(rp, V_rastport);
  80.     
  81.     return 0;
  82. }
  83.  
  84. void free_rastport(struct RastPort *rp, struct GfxBase *GfxBase)
  85. {
  86.     FreeRaster(rp->BitMap->Planes[0], rp->BitMap->BytesPerRow * 8, rp->BitMap->Rows * rp->BitMap->Depth);
  87.  
  88.     deallocate(rp->BitMap, V_bitmap);
  89.     deallocate(rp, V_rastport);
  90. }
  91.  
  92. struct IntuiText nulltext = {
  93.     0, 0,
  94.     JAM1,
  95.     0, 0,
  96.     (void *)0,
  97.     "",
  98.     (void *)0
  99. };
  100.  
  101. struct gim *make_gim(b8 *name, b32 textpen, b32 lightpen, b32 darkpen, struct Screen *s, 
  102.             struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  103. {
  104.     struct IntuiText txt;
  105.     int width, height, owidth, oheight;
  106.     struct gim *gim;
  107.     sb32 x, y, Rx, Ry, Rx2, Ry2, R2, new_delta, old_delta;
  108.     
  109.     txt.FrontPen = textpen;
  110.     txt.BackPen = 0;
  111.     txt.DrawMode = JAM2;
  112.     txt.LeftEdge = 0;
  113.     txt.TopEdge = 0;
  114.     txt.ITextFont = s->Font;
  115.     txt.IText = name;
  116.     txt.NextText = nil;
  117.     
  118.     if (s->Font) height = s->Font->ta_YSize;
  119.     else height = 8;
  120.     
  121.     width = IntuiTextLength(&txt);
  122.     
  123.     owidth = width + height;
  124.     oheight = 3 * height / 2;
  125.     
  126.     gim = (struct gim *)allocate(sizeof(*gim), V_gim);
  127.     if (!gim) return nil;
  128.     
  129.     ensure(gim, V_gim);
  130.     
  131.     gim->rp1 = make_rastport(owidth, oheight, 3, GfxBase);
  132.     if (!gim->rp1) {
  133.         deallocate(gim, V_gim);
  134.         return nil;
  135.     }
  136.     
  137.     gim->rp2 = make_rastport(owidth, oheight, 3, GfxBase);
  138.     if (!gim->rp2) {
  139.         free_rastport(gim->rp1, GfxBase);
  140.         deallocate(gim, V_gim);
  141.         return nil;
  142.     }
  143.     
  144.     gim->im1.LeftEdge = 0;
  145.     gim->im1.TopEdge = 0;
  146.     gim->im1.Width = owidth;
  147.     gim->im1.Height = oheight;
  148.     gim->im1.Depth = 3;
  149.     gim->im1.ImageData = (void *)gim->rp1->BitMap->Planes[0];
  150.     
  151.     gim->im1.PlanePick = 7;
  152.     gim->im1.PlaneOnOff = 0;
  153.     gim->im1.NextImage = nil;
  154.     
  155.     gim->im2 = gim->im1;
  156.     gim->im2.ImageData = (void *)gim->rp2->BitMap->Planes[0];
  157.     
  158.     SetRast(gim->rp1, 0);
  159.     SetRast(gim->rp2, 0);
  160.     
  161.     PrintIText(gim->rp1, &txt, height / 2, height / 4);
  162.     PrintIText(gim->rp2, &txt, height / 2 + 1, height / 4 + 1);
  163.     
  164.     Rx = Ry = 2 * height / 3;
  165.     
  166.     Rx2 = Rx * Rx;
  167.     Ry2 = Ry * Ry;
  168.     
  169.     R2 = Rx2 * Ry2;
  170.     
  171.     for (x = 0; x < Rx; x++) {
  172.         y = 0;
  173.         new_delta = abs(R2 - Ry2*x*x - Rx2*y*y);
  174.         do {
  175.             old_delta = new_delta;
  176.             y++;
  177.             new_delta = abs(R2 - Ry2*x*x - Rx2*y*y);
  178.         } while (old_delta > new_delta);
  179.         
  180.         SetAPen(gim->rp1, lightpen);
  181.         
  182.         WritePixel(gim->rp1, Rx - x, Ry - (y - 1));
  183.         WritePixel(gim->rp1, owidth - Rx - 1 + x, Ry - (y - 1));
  184.         
  185.         SetAPen(gim->rp1, darkpen);
  186.         
  187.         WritePixel(gim->rp1, Rx - x, oheight - Ry - 1 + (y - 1));
  188.         WritePixel(gim->rp1, owidth - Rx - 1 + x, oheight - Ry - 1 + (y - 1));
  189.         
  190.         SetAPen(gim->rp2, darkpen);
  191.         
  192.         WritePixel(gim->rp2, Rx - x, Ry - (y - 1));
  193.         WritePixel(gim->rp2, owidth - Rx - 1 + x, Ry - (y - 1));
  194.         
  195.         SetAPen(gim->rp2, lightpen);
  196.         
  197.         WritePixel(gim->rp2, Rx - x, oheight - Ry - 1 + (y - 1));
  198.         WritePixel(gim->rp2, owidth - Rx - 1 + x, oheight - Ry - 1 + (y - 1));
  199.     }
  200.     
  201.     for (y = 0; y < Ry; y++) {
  202.         x = 0;
  203.         new_delta = abs(R2 - Ry2 * x * x - Rx2 * y * y);
  204.         do {
  205.             old_delta = new_delta;
  206.             x++;
  207.             new_delta = abs(R2 - Ry2 * x * x - Rx2 * y * y);
  208.         } while (old_delta > new_delta);
  209.         
  210.         SetAPen(gim->rp1, lightpen);
  211.         
  212.         WritePixel(gim->rp1, Rx - (x - 1), Ry - y);
  213.         WritePixel(gim->rp1, Rx - (x - 1), oheight - Ry - 1 + y);
  214.  
  215.         SetAPen(gim->rp1, darkpen);
  216.  
  217.         WritePixel(gim->rp1, owidth - Rx - 1 + (x - 1), Ry - y);
  218.         WritePixel(gim->rp1, owidth - Rx - 1 + (x - 1), oheight - Ry - 1 + y);
  219.         
  220.         SetAPen(gim->rp2, darkpen);
  221.         
  222.         WritePixel(gim->rp2, Rx - (x - 1), Ry - y);
  223.         WritePixel(gim->rp2, Rx - (x - 1), oheight - Ry - 1 + y);
  224.  
  225.         SetAPen(gim->rp2, lightpen);
  226.  
  227.         WritePixel(gim->rp2, owidth - Rx - 1 + (x - 1), Ry - y);
  228.         WritePixel(gim->rp2, owidth - Rx - 1 + (x - 1), oheight - Ry - 1 + y);
  229.     }
  230.     
  231.     SetAPen(gim->rp1, lightpen);
  232.     
  233.     Move(gim->rp1, Rx, 0);
  234.     Draw(gim->rp1, owidth - Rx - 1, 0);
  235.     
  236.     Move(gim->rp1, 0, Ry);
  237.     Draw(gim->rp1, 0, oheight - Ry - 1);
  238.     
  239.     SetAPen(gim->rp1, darkpen);
  240.     
  241.     Move(gim->rp1, Rx, oheight - 1);
  242.     Draw(gim->rp1, owidth - Rx - 1, oheight - 1);
  243.     
  244.     Move(gim->rp1, owidth - 1, Ry);
  245.     Draw(gim->rp1, owidth - 1, oheight - Ry - 1);
  246.  
  247.     SetAPen(gim->rp2, darkpen);
  248.     
  249.     Move(gim->rp2, Rx, 0);
  250.     Draw(gim->rp2, owidth - Rx - 1, 0);
  251.     
  252.     Move(gim->rp2, 0, Ry);
  253.     Draw(gim->rp2, 0, oheight - Ry - 1);
  254.     
  255.     SetAPen(gim->rp2, lightpen);
  256.     
  257.     Move(gim->rp2, Rx, oheight - 1);
  258.     Draw(gim->rp2, owidth - Rx - 1, oheight - 1);
  259.     
  260.     Move(gim->rp2, owidth - 1, Ry);
  261.     Draw(gim->rp2, owidth - 1, oheight - Ry - 1);
  262.     
  263.     return gim;
  264. }
  265.  
  266. void free_gim(struct gim *gim, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  267. {
  268.     verify(gim, V_gim);
  269.  
  270.     free_rastport(gim->rp1, GfxBase);
  271.     free_rastport(gim->rp2, GfxBase);
  272.     deallocate(gim, V_gim);
  273.     
  274.     return;
  275. }
  276.  
  277. struct Gadget *make_gadget(struct gim *gim)
  278. {
  279.     struct Gadget *g;
  280.     
  281.     if (!gim) return nil;
  282.  
  283.     verify(gim, V_gim);
  284.     
  285.     g = (struct Gadget *)allocate(sizeof(*g), V_Gadget);
  286.     if (!g) return nil;
  287.     
  288.     g->NextGadget = nil;
  289.     g->LeftEdge = 0;
  290.     g->TopEdge = 0;
  291.     g->Width = gim->im1.Width;
  292.     g->Height = gim->im1.Height;
  293.     
  294.     g->Flags = GFLG_GADGHIMAGE | GFLG_GADGIMAGE;
  295.     g->Activation = GACT_RELVERIFY;
  296.     g->GadgetType = GTYP_BOOLGADGET;
  297.     g->GadgetRender = &gim->im1;
  298.     g->SelectRender = &gim->im2;
  299.     g->GadgetText = &nulltext;
  300.     
  301.     g->MutualExclude = 0;
  302.     g->SpecialInfo = nil;
  303.     g->GadgetID = 0;
  304.     g->UserData = nil;
  305.     
  306.     return g;
  307. }
  308.  
  309. void free_gadget(struct Gadget *g)
  310. {
  311.     deallocate(g, V_Gadget);
  312. }
  313.  
  314. struct Window *connect_req(site *sp, b8 *s)
  315. {
  316.     struct Window *w;
  317.     struct IntuitionBase *IntuitionBase;
  318.     struct GfxBase *GfxBase;
  319.     struct Screen *pub_screen;
  320.     b32 screen_modeID;
  321.     struct Rectangle rect;
  322.     struct Gadget *cancel;
  323.     struct IntuiText txt;
  324.     int width, swidth, sheight, fheight;
  325.     b8 *z;
  326.     
  327.     verify(sp, V_site);
  328.     
  329.     GfxBase = sp->GBase;
  330.     IntuitionBase = sp->IBase;
  331.     
  332.     pub_screen = LockPubScreen(nil);
  333.     if (pub_screen) {
  334.         screen_modeID = GetVPModeID(&pub_screen->ViewPort);
  335.         if (screen_modeID != INVALID_ID) {
  336.             if (QueryOverscan(screen_modeID, &rect, OSCAN_TEXT)) {
  337.                 cancel = make_gadget(cancel_gim);
  338.                 if (cancel) {
  339.                     z = (b8 *)allocate(strlen(s) + 19, V_cstr);
  340.                     if (z) {
  341.                         strcpy(z, strings[MSG_CONNECTING_TO]);
  342.                         strcat(z, s);
  343.                         strcat(z, " ...");
  344.                         
  345.                         txt.FrontPen = 1;
  346.                         txt.BackPen = 0;
  347.                         txt.DrawMode = JAM1;
  348.                         txt.LeftEdge = 0;
  349.                         txt.TopEdge = 0;
  350.                         txt.ITextFont = pub_screen->Font;
  351.                         txt.IText = z;
  352.                         txt.NextText = nil;
  353.                         
  354.                         if (pub_screen->Font) fheight = pub_screen->Font->ta_YSize;
  355.                         else fheight = 8;
  356.                         
  357.                         width = IntuiTextLength(&txt) * 4 / 3;
  358.                         
  359.                         txt.LeftEdge = width / 8;
  360.                         txt.TopEdge = fheight / 2;
  361.                         
  362.                         swidth = rect.MaxX - rect.MinX + 1;
  363.                         sheight = rect.MaxY - rect.MinY + 1;
  364.                         
  365.                         if (pub_screen->TopEdge > 0)
  366.                             sheight -= pub_screen->TopEdge;
  367.                         
  368.                         if (sheight > pub_screen->Height) sheight = pub_screen->Height;
  369.                         if (swidth > pub_screen->Width) swidth = pub_screen->Width;
  370.                         
  371.                         if (sheight < fheight * 6) sheight = fheight * 6;
  372.                         if (swidth < width) swidth = width;
  373.                         
  374.                         w = OpenWindowTags(nil,
  375.                             WA_Left,    swidth / 2 - pub_screen->LeftEdge - width / 2,
  376.                             WA_Top,        sheight / 2 - pub_screen->TopEdge - fheight * 3,
  377.                             WA_Width,    width,
  378.                             WA_Height,    fheight * 6,
  379.                             WA_Flags,    WFLG_DEPTHGADGET | WFLG_DRAGBAR |
  380.                                     WFLG_SMART_REFRESH | 
  381.                                     WFLG_NOCAREREFRESH,
  382.                             WA_IDCMP,    IDCMP_GADGETUP,
  383.                             WA_PubScreen,    pub_screen,
  384.                             WA_Title,    strings[MSG_CONNECTING],
  385.                             TAG_END,    0
  386.                         );
  387.                         
  388.                         if (w) {
  389.                             UnlockPubScreen(nil, pub_screen);
  390.                             PrintIText(w->RPort, &txt, 0, w->BorderTop);
  391.                             deallocate(z, V_cstr);
  392.                             w->UserData = (void *)cancel;
  393.                             cancel->LeftEdge = w->Width - w->BorderRight - fheight / 2 - cancel->Width;
  394.                             cancel->TopEdge = w->Height - w->BorderBottom - fheight / 3 - cancel->Height;
  395.                             AddGadget(w, cancel, (b32)0);
  396.                             RefreshGList(cancel, w, nil, 1);
  397.                             
  398.                             return w;
  399.                         }
  400.                         
  401.                         deallocate(z, V_cstr);
  402.                     }
  403.                     
  404.                     free_gadget(cancel);
  405.                 }
  406.             }
  407.         }
  408.         UnlockPubScreen(nil, pub_screen);
  409.     }
  410.     
  411.     return nil;
  412. }
  413.  
  414. void close_req(site *sp, struct Window *w)
  415. {
  416.     struct Gadget *cancel;
  417.     struct Message *msg;
  418.     
  419.     struct IntuitionBase *IntuitionBase;
  420.     
  421.     verify(sp, V_site);
  422.     
  423.     IntuitionBase = sp->IBase;
  424.     
  425.     Forbid();
  426.     while (msg = GetMsg(w->UserPort)) ReplyMsg(msg);
  427.  
  428.     cancel = (struct Gadget *)w->UserData;
  429.     RemoveGadget(w, cancel);
  430.  
  431.     free_gadget(cancel);
  432.     
  433.     CloseWindow(w);
  434.     Permit();
  435. }
  436.  
  437. struct phdata {
  438.     b8 password[MAX_PASS_LENGTH + 1];
  439.     b8 undo[MAX_PASS_LENGTH + 1];
  440. };
  441.  
  442. boolean __saveds __asm password_hook(register __a0 struct Hook *hook, 
  443.                 register __a1 b32 *msg, 
  444.                 register __a2 struct SGWork *sgw)
  445. {
  446.     struct phdata *phd;
  447.     
  448.     phd = hook->h_Data;
  449.     
  450.     if (*msg == SGH_KEY) {
  451.         switch (sgw->EditOp) {
  452.         case EO_REPLACECHAR:
  453.         case EO_INSERTCHAR:
  454.             phd->password[sgw->BufferPos - 1] = sgw->WorkBuffer[sgw->BufferPos - 1];
  455.             sgw->WorkBuffer[sgw->BufferPos - 1] = '*';
  456.             break;
  457.         case EO_MOVECURSOR:
  458.             sgw->Actions &=~ SGA_USE;
  459.             sgw->Actions |= SGA_BEEP;
  460.             break;
  461.         case EO_RESET:
  462.             strcpy(phd->password, phd->undo);
  463.             break;
  464.         }
  465.         if (sgw->BufferPos != sgw->NumChars) {
  466.             sgw->BufferPos = sgw->NumChars;
  467.             sgw->Actions |= SGA_REDISPLAY;
  468.         }
  469.         phd->password[sgw->NumChars] = 0;
  470.         return true;
  471.     } else if (*msg == SGH_CLICK) {
  472.         sgw->BufferPos = sgw->NumChars;
  473.         sgw->Actions |= SGA_REDISPLAY;
  474.         return true;
  475.     } else {
  476.         return false;
  477.     }
  478. }
  479.  
  480. boolean user_pass_request(site *sp, struct Window *canw)
  481. /*
  482.  * open a requester asking for username and password, filled in as appropriate
  483.  * Inputs:
  484.  *    sp    : site pointer
  485.  *    canw    : cancel window (will still be open in the background, and may be used)
  486.  *
  487.  * Result:
  488.  *    false if cancel is selected in either canw or the requester, or a major failure occurred
  489.  *    true if login is selected, or return is pressed in password field
  490.  */
  491. {
  492.     struct Gadget *glist, *gad, *login, *cancel, *userg, *passg;
  493.     struct NewGadget user, pass;
  494.     struct Screen *s;
  495.     void *vi;
  496.     b32 screen_modeID;
  497.     struct Rectangle rect;
  498.     struct Window *w;
  499.     sb32 swidth, sheight, fheight, wheight;
  500.     b32 signals, csig;
  501.     struct IntuiMessage *im;
  502.     struct Hook pass_hook;
  503.     b8 *z;
  504.     struct phdata phd;
  505.  
  506.     struct IntuitionBase *IntuitionBase;
  507.     struct Library *GadToolsBase;
  508.     struct GfxBase *GfxBase;
  509.     
  510.     verify(sp, V_site);
  511.     
  512.     IntuitionBase = sp->IBase;
  513.     GfxBase = sp->GBase;
  514.     GadToolsBase = sp->GTBase;
  515.  
  516.     glist = nil;
  517.     
  518.     pass_hook.h_Entry = (b32 (*)())password_hook;
  519.     pass_hook.h_SubEntry = (b32 (*)())nil;
  520.     pass_hook.h_Data = (void *)&phd;
  521.     
  522.     s = LockPubScreen(nil);
  523.     if (!s) return false;
  524.     
  525.     if (s->Font) fheight = s->Font->ta_YSize;
  526.     else fheight = 8;
  527.     
  528.     if (sp->password) {
  529.         strcpy(phd.password, sp->password);
  530.         strcpy(phd.undo, sp->password);
  531.         
  532.         z = sp->password;
  533.         while (*z) {
  534.             *z++ = '*';
  535.         }
  536.     } else {
  537.         phd.password[0] = 0;
  538.         phd.undo[0] = 0;
  539.     }
  540.     
  541.     wheight = fheight * 8;
  542.     
  543.     vi = GetVisualInfo(s, TAG_END);
  544.     if (vi != nil) {
  545.         screen_modeID = GetVPModeID(&s->ViewPort);
  546.         if (screen_modeID != INVALID_ID) {
  547.             if (QueryOverscan(screen_modeID, &rect, OSCAN_TEXT)) {
  548.                 swidth = rect.MaxX - rect.MinX + 1;
  549.                 sheight = rect.MaxY - rect.MinY + 1;
  550.                 
  551.                 sprintf(sp->read_buffer, strings[MSG_LOGIN_TO], sp->host);
  552.                 
  553.                 w = OpenWindowTags(nil,
  554.                     WA_Left,    swidth / 4 - s->LeftEdge,
  555.                     WA_Top,        sheight / 2 - wheight / 2 - s->TopEdge,
  556.                     WA_Width,    swidth / 2,
  557.                     WA_Height,    wheight,
  558.                     WA_IDCMP,    IDCMP_ACTIVEWINDOW | IDCMP_REFRESHWINDOW | 
  559.                             BUTTONIDCMP | STRINGIDCMP,
  560.                     WA_PubScreen,    s,
  561.                     WA_Activate,    true,
  562.                     WA_DragBar,    true,
  563.                     WA_DepthGadget,    true,
  564.                     WA_Title,    sp->read_buffer,
  565.                     WA_AutoAdjust,    true,
  566.                     TAG_END
  567.                 );
  568.                 if (w) {
  569.                     gad = CreateContext(&glist);
  570.                     if (gad) {
  571.                         user.ng_LeftEdge = w->Width / 4;
  572.                         user.ng_TopEdge = w->BorderTop + fheight / 2;
  573.                         user.ng_Width = (w->Width * 3 / 4) - w->BorderRight - fheight / 2;
  574.                         user.ng_Height = fheight * 3 / 2;
  575.                         user.ng_GadgetText = strings[MSG_USER_NAME];
  576.                         user.ng_TextAttr = s->Font;
  577.                         user.ng_GadgetID = 1;
  578.                         user.ng_Flags = PLACETEXT_LEFT;
  579.                         user.ng_VisualInfo = vi;
  580.                         
  581.                         pass.ng_LeftEdge = w->Width / 4;
  582.                         pass.ng_TopEdge = w->BorderTop + (fheight * 5 / 2);
  583.                         pass.ng_Width = (w->Width * 3 / 4) - w->BorderRight - fheight / 2;
  584.                         pass.ng_Height = fheight * 3 / 2;
  585.                         pass.ng_GadgetText = strings[MSG_PASSWORD_NAME];
  586.                         pass.ng_TextAttr = s->Font;
  587.                         pass.ng_GadgetID = 2;
  588.                         pass.ng_Flags = PLACETEXT_LEFT;
  589.                         pass.ng_VisualInfo = vi;
  590.                         
  591.                         userg = gad = CreateGadget(STRING_KIND, gad, &user,
  592.                             GTST_String,    sp->user,
  593.                             GTST_MaxChars,    MAX_USER_LENGTH,
  594.                             TAG_END
  595.                         );
  596.                         
  597.                         passg = gad = CreateGadget(STRING_KIND, gad, &pass,
  598.                             GTST_String,    sp->password,
  599.                             GTST_MaxChars,    MAX_PASS_LENGTH,
  600.                             GTST_EditHook,    (b32)&pass_hook,
  601.                             TAG_END
  602.                         );
  603.                         
  604.                         if (gad) {
  605.                             login = make_gadget(login_gim);
  606.                             if (login) {
  607.                                 cancel = make_gadget(cancel_gim);
  608.                                 if (cancel) {
  609.                                     login->LeftEdge = fheight / 2 + w->BorderLeft;
  610.                                     login->TopEdge = w->Height - w->BorderBottom - login->Height - fheight / 2;
  611.                                     
  612.                                     cancel->LeftEdge = w->Width - w->BorderRight - cancel->Width - fheight / 2;
  613.                                     cancel->TopEdge = login->TopEdge;
  614.                                     
  615.                                     login->GadgetID = 3;
  616.                                     cancel->GadgetID = 4;
  617.                                     
  618.                                     AddGadget(w, cancel, 100);
  619.                                     AddGadget(w, login, 100);
  620.                             
  621.                                     AddGList(w, glist, 0, 100, nil);
  622.                                     
  623.                                     RefreshGadgets(glist, w, nil);
  624.                                     GT_RefreshWindow(w, nil);
  625.                             
  626.                                     goto listen;
  627.                                 }
  628.                                 free_gadget(login);
  629.                             }
  630.                         }
  631.                         
  632.                         FreeGadgets(glist);
  633.                     }
  634.                     CloseWindow(w);
  635.                 }
  636.             }
  637.         }
  638.         FreeVisualInfo(vi);
  639.     }
  640.     
  641.     UnlockPubScreen(nil, s);
  642.     
  643.     return false;
  644.  
  645. listen:
  646.     csig = 1 << canw->UserPort->mp_SigBit | sp->abort_signals | sp->disconnect_signals;
  647.     signals = (1 << w->UserPort->mp_SigBit) | csig;
  648.  
  649.     while (1) {
  650.         if (Wait(signals) & csig) {
  651.             CloseWindow(w);
  652.  
  653.             FreeGadgets(glist);
  654.  
  655.             free_gadget(cancel);
  656.             free_gadget(login);
  657.  
  658.             FreeVisualInfo(vi);
  659.             UnlockPubScreen(nil, s);
  660.                             
  661.             return false;
  662.         }
  663.         
  664.         while (im = GT_GetIMsg(w->UserPort)) {
  665.             gad = (struct Gadget *)im->IAddress;
  666.             
  667.             switch (im->Class) {
  668.             case IDCMP_ACTIVEWINDOW:
  669.                 if (sp->needs_user) {
  670.                     ActivateGadget(userg, w, nil);
  671.                 } else {
  672.                     ActivateGadget(passg, w, nil);
  673.                 }
  674.                 break;
  675.             case IDCMP_GADGETUP:
  676.                 switch (gad->GadgetID) {
  677.                 case 1:
  678.                     if (im->Code == 0) {
  679.                         ActivateGadget(passg, w, nil);
  680.                     }
  681.                     sp->needs_user = false;
  682.                     break;
  683.                 case 2:
  684.                     if (im->Code != 0) {
  685.                         break;
  686.                     }
  687.                     /* else fall through to Login */
  688.                 case 3:
  689.                     if (sp->user) deallocate(sp->user, V_cstr);
  690.                     if (sp->password) deallocate(sp->password, V_cstr);
  691.                     
  692.                     z = ((struct StringInfo *)userg->SpecialInfo)->Buffer;
  693.                     if (z[0] != '\0') {
  694.                         sp->user = (b8 *)allocate(strlen(z) + 1, V_cstr);
  695.                         if (sp->user) {
  696.                             strcpy(sp->user, z);
  697.                         }
  698.                     } else {
  699.                         sp->user = nil;
  700.                     }
  701.                     
  702.                     z = phd.password;
  703.                     if (z[0] != '\0') {
  704.                         sp->password = (b8 *)allocate(strlen(z) + 1, V_cstr);
  705.                         if (sp->password) {
  706.                             strcpy(sp->password, z);
  707.                         }
  708.                     } else {
  709.                         sp->password = nil;
  710.                     }
  711.                     
  712.                     Forbid();
  713.                     GT_ReplyIMsg(im);
  714.                     
  715.                     CloseWindow(w);
  716.                     Permit();
  717.                     
  718.                     FreeGadgets(glist);
  719.                     free_gadget(cancel);
  720.                     free_gadget(login);
  721.  
  722.                     FreeVisualInfo(vi);
  723.                     UnlockPubScreen(nil, s);
  724.                             
  725.                     return true;
  726.                 case 4:
  727.                     Forbid();
  728.                     GT_ReplyIMsg(im);
  729.                     
  730.                     CloseWindow(w);
  731.                     Permit();
  732.                     
  733.                     FreeGadgets(glist);
  734.                     
  735.                     free_gadget(cancel);
  736.                     free_gadget(login);
  737.  
  738.                     FreeVisualInfo(vi);
  739.                     UnlockPubScreen(nil, s);
  740.                             
  741.                     return false;
  742.                 }
  743.                 break;
  744.             case IDCMP_REFRESHWINDOW:
  745.                 GT_BeginRefresh(w);
  746.                 GT_EndRefresh(w, true);
  747.                 break;
  748.             }
  749.             
  750.             GT_ReplyIMsg(im);
  751.         }
  752.     }
  753. }
  754.  
  755. struct Window *open_main_window(struct List *site_labels, struct IntuitionBase *IntuitionBase, struct Library *GadToolsBase, struct GfxBase *GfxBase)
  756. {
  757.     struct Gadget *glist, *gad;
  758.     struct NewGadget ng;
  759.     struct Screen *s;
  760.     void *vi;
  761.     b32 screen_modeID;
  762.     struct Rectangle rect;
  763.     struct Window *w;
  764.     sb32 swidth, sheight;
  765.     
  766.     glist = nil;
  767.     
  768.     s = LockPubScreen(nil);
  769.     if (!s) return nil;
  770.     
  771.     vi = GetVisualInfo(s, TAG_END);
  772.     if (vi != nil) {
  773.         screen_modeID = GetVPModeID(&s->ViewPort);
  774.         if (screen_modeID != INVALID_ID) {
  775.             if (QueryOverscan(screen_modeID, &rect, OSCAN_TEXT)) {
  776.                 swidth = rect.MaxX - rect.MinX + 1;
  777.                 sheight = rect.MaxY - rect.MinY + 1;
  778.                 
  779.                 w = OpenWindowTags(nil,
  780.                     WA_Left,    swidth / 3 - s->LeftEdge,
  781.                     WA_Top,        sheight / 4 - s->TopEdge,
  782.                     WA_Width,    swidth / 3,
  783.                     WA_Height,    sheight / 2,
  784.                     WA_IDCMP,    IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | LISTVIEWIDCMP,
  785.                     WA_PubScreen,    s,
  786.                     WA_Activate,    true,
  787.                     WA_DragBar,    true,
  788.                     WA_DepthGadget,    true,
  789.                     WA_CloseGadget,    true,
  790.                     WA_Title,    strings[MSG_CURRENT_SITES],
  791.                     WA_AutoAdjust,    true,
  792.                     TAG_END
  793.                 );
  794.                 if (w) {
  795.                     gad = CreateContext(&glist);
  796.                     if (gad) {
  797.                         ng.ng_TextAttr = s->Font;
  798.                         ng.ng_VisualInfo = vi;
  799.                         ng.ng_LeftEdge = w->BorderLeft;
  800.                         ng.ng_TopEdge = w->BorderTop;
  801.                         ng.ng_Width = w->Width - w->BorderLeft - w->BorderRight;
  802.                         ng.ng_Height = w->Height - w->BorderTop - w->BorderBottom;
  803.                         ng.ng_GadgetText = nil;
  804.                         ng.ng_GadgetID = 0;
  805.                         ng.ng_Flags = 0;
  806.                         gad = CreateGadget(LISTVIEW_KIND, gad, &ng, 
  807.                             GTLV_ReadOnly,    false, 
  808.                             GTLV_Labels,    site_labels,
  809.                             TAG_END
  810.                         );
  811.                         if (gad) {
  812.                             AddGList(w, glist, 0, -1, nil);
  813.                             
  814.                             RefreshGadgets(glist, w, nil);
  815.                             GT_RefreshWindow(w, nil);
  816.                             
  817.                             w->UserData = (void *)glist;
  818.                             
  819.                             FreeVisualInfo(vi);
  820.                             UnlockPubScreen(nil, s);
  821.                             
  822.                             return w;
  823.                         }
  824.                         FreeGadgets(glist);
  825.                     }
  826.                     CloseWindow(w);
  827.                 }
  828.             }
  829.         }
  830.         FreeVisualInfo(vi);
  831.     }
  832.     
  833.     UnlockPubScreen(nil, s);
  834.     
  835.     return nil;
  836. }
  837.  
  838. void close_main_window(struct Window *w, struct IntuitionBase *IntuitionBase, struct Library *GadToolsBase)
  839. {
  840.     struct Gadget *glist;
  841.     struct IntuiMessage *im;
  842.     
  843.     Forbid();
  844.     while (im = GT_GetIMsg(w->UserPort)) {
  845.         if (im->Class == IDCMP_REFRESHWINDOW) {
  846.             GT_BeginRefresh(w);
  847.             GT_EndRefresh(w, true);
  848.         }
  849.         GT_ReplyIMsg(im);
  850.     }
  851.     
  852.     glist = (struct Gadget *)w->UserData;
  853.     
  854.     CloseWindow(w);
  855.     FreeGadgets(glist);
  856.     Permit();
  857. }
  858.  
  859. #define V_List 19561
  860. #define V_Node 20079
  861.  
  862. struct List *site_list(void)
  863. {
  864.     struct List *l;
  865.     struct Node *n;
  866.     site *sp;
  867.     
  868.     l = (struct List *)allocate(sizeof(*l), V_List);
  869.     if (!l) return l;
  870.     
  871.     NewList(l);
  872.     
  873.     Forbid();
  874.     sp = sites;
  875.     while (sp) {
  876.         n = (struct Node *)allocate(sizeof(*n), V_Node);
  877.         if (!n) {
  878.             Permit();
  879.             return l;
  880.         }
  881.         
  882.         n->ln_Name = (b8 *)allocate(strlen(sp->name) + 1, V_cstr);
  883.         if (!n->ln_Name) {
  884.             Permit();
  885.             deallocate(n, V_Node);
  886.             return l;
  887.         }
  888.         
  889.         strcpy(n->ln_Name, sp->name);
  890.         
  891.         n->ln_Pri = 0;
  892.         AddTail(l, n);
  893.         sp = sp->next;
  894.     }
  895.     Permit();
  896.     
  897.     return l;
  898. }
  899.  
  900. void free_labels(struct List *l)
  901. {
  902.     struct Node *n;
  903.     
  904.     while (n = RemHead(l)) {
  905.         deallocate(n->ln_Name, V_cstr);
  906.         deallocate(n, V_Node);
  907.     }
  908.     
  909.     deallocate(l, V_List);
  910. }
  911.  
  912. void draw_fill_bar(site *sp, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  913. {
  914.     struct Window *w;
  915.     struct RastPort *rp;
  916.     b32 x1, y1, x2, y2, gap;
  917.     
  918.     verify(sp, V_site);
  919.     
  920.     w = sp->status_window;
  921.     if (!w) return;
  922.     
  923.     rp = w->RPort;
  924.     
  925.     x1 = w->BorderLeft;
  926.     y1 = w->BorderTop;
  927.     
  928.     x2 = w->Width - w->BorderRight - 1;
  929.     y2 = sp->abort_gadget->TopEdge - 1;
  930.     
  931.     gap = (y2 - y1) / 4;
  932.     
  933.     x2 = x1 + (x2 - x1) * 3 / 4;
  934.     
  935.     x1 += gap;
  936.     y1 += gap;
  937.     y2 -= gap;
  938.     
  939.     SetDrMd(rp, JAM2);
  940.     
  941.     SetAPen(rp, lightpen);
  942.     Move(rp, x2, y1);
  943.     Draw(rp, x2, y2);
  944.     Draw(rp, x1, y2);
  945.     SetAPen(rp, darkpen);
  946.     Draw(rp, x1, y1);
  947.     Draw(rp, x2, y1);
  948.     
  949.     SetAPen(rp, fillpen);
  950.     
  951.     x1++;
  952.     y1++;
  953.     y2--;
  954.     x2--;
  955.     
  956.     if (sp->file_list) {
  957.         verify(sp->file_list, V_file_info);
  958.         
  959.         x2 = x1 + ((x2 - x1) * sp->file_list->rpos) / sp->file_list->end;
  960.         RectFill(rp, x1, y1, x2, y2);
  961.     }
  962. }
  963.  
  964. void update_fill_bar(site *sp, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  965. {
  966.     struct Window *w;
  967.     struct RastPort *rp;
  968.     b32 x1, y1, x2, y2, gap;
  969.     struct IntuiText txt;
  970.     b8 buffer[20], *z;
  971.     file_info *fip;
  972.     
  973.     verify(sp, V_site);
  974.     
  975.     w = sp->status_window;
  976.     if (!w) return;
  977.     
  978.     Forbid();
  979.     fip = sp->file_list;
  980.     if (!fip) {
  981.         Permit();
  982.         return;
  983.     }
  984.     verify(fip, V_file_info);
  985.     
  986.     z = fip->fname + strlen(fip->fname) - 1;
  987.     while (z > fip->fname && *z != '/') z--;
  988.     if (*z == '/') z++;
  989.     
  990.     rp = w->RPort;
  991.     
  992.     x1 = w->BorderLeft;
  993.     y1 = w->BorderTop;
  994.     
  995.     x2 = w->Width - w->BorderRight - 1;
  996.     y2 = sp->abort_gadget->TopEdge - 1;
  997.     
  998.     gap = (y2 - y1) / 4;
  999.     
  1000.     x2 = x1 + (x2 - x1) * 3 / 4 - 1;
  1001.     
  1002.     x1 += gap + 1;
  1003.     y1 += gap + 1;
  1004.     y2 -= gap + 1;
  1005.     
  1006.     if (sp->site_state == SS_WRITING || !fip->end) {    /* just print how many k we have transferred */
  1007.         txt.FrontPen = textpen;
  1008.         txt.BackPen = 0;
  1009.         txt.DrawMode = JAM2;
  1010.         txt.LeftEdge = x1;
  1011.         txt.TopEdge = y1;
  1012.         txt.ITextFont = sp->status_window->WScreen->Font;
  1013.         txt.NextText = nil;
  1014.         txt.IText = z;
  1015.         PrintIText(rp, &txt, 0, 0);
  1016.         
  1017.         txt.LeftEdge += IntuiTextLength(&txt);
  1018.         txt.FrontPen = textpen;
  1019.         txt.IText = buffer;
  1020.  
  1021.         buffer[0] = ':';
  1022.         buffer[1] = ' ';
  1023.         x1 = 2;
  1024.         y1 = fip->rpos / 1024;
  1025.         buffer[x1] = '0';
  1026.         while (y1 >= 100000) {
  1027.             buffer[x1]++;
  1028.             y1 -= 100000;
  1029.         }
  1030.         if (buffer[x1] > '0') x1++;
  1031.         buffer[x1] = '0';
  1032.         while (y1 >= 10000) {
  1033.             buffer[x1]++;
  1034.             y1 -= 10000;
  1035.         }
  1036.         if (buffer[x1] > '0' || x1 != 2) x1++;
  1037.         buffer[x1] = '0';
  1038.         while (y1 >= 1000) {
  1039.             buffer[x1]++;
  1040.             y1 -= 1000;
  1041.         }
  1042.         if (buffer[x1] > '0' || x1 != 2) x1++;
  1043.         buffer[x1] = '0';
  1044.         while (y1 >= 100) {
  1045.             buffer[x1]++;
  1046.             y1 -= 100;
  1047.         }
  1048.         if (buffer[x1] > '0' || x1 != 2) x1++;
  1049.         buffer[x1] = '0';
  1050.         while (y1 >= 10) {
  1051.             buffer[x1]++;
  1052.             y1 -= 10;
  1053.         }
  1054.         if (buffer[x1] > '0' || x1 != 2) x1++;
  1055.         buffer[x1++] = y1 + '0';
  1056.         buffer[x1++] = ' ';
  1057.         buffer[x1++] = 'k';
  1058.         buffer[x1++] = ' ';
  1059.         buffer[x1++] = ' ';
  1060.         buffer[x1] = 0;
  1061.  
  1062.         PrintIText(rp, &txt, 0, 0);
  1063.         
  1064.         Permit();
  1065.         
  1066.         return;
  1067.     }
  1068.     
  1069.     /* reading ... can do a filler bar */
  1070.     
  1071.     SetDrMd(rp, JAM2);
  1072.     SetAPen(rp, fillpen);
  1073.  
  1074.     txt.FrontPen = lightpen;
  1075.     txt.BackPen = 0;
  1076.     txt.DrawMode = JAM1;
  1077.     txt.TopEdge = y1;
  1078.     txt.ITextFont = sp->status_window->WScreen->Font;
  1079.     txt.NextText = nil;
  1080.     txt.IText = z;
  1081.     
  1082.     txt.LeftEdge = (x1 + x2) / 2 - IntuiTextLength(&txt) / 2;
  1083.     
  1084.     x2 = x1 + ((x2 - x1) * sp->file_list->rpos) / sp->file_list->end;
  1085.     RectFill(rp, x1, y1, x2, y2);
  1086.  
  1087.     PrintIText(rp, &txt, 0, 0);
  1088.     
  1089.     Permit();
  1090.     
  1091.     return;
  1092. }
  1093.  
  1094. void draw_state(site *sp, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  1095. {
  1096.     struct IntuiText txt;
  1097.     
  1098.     /* gadget states */
  1099.     switch (sp->site_state) {
  1100.     case SS_DISCONNECTED:
  1101.     case SS_DISCONNECTING:
  1102.         if (!(sp->abort_gadget->Flags & GFLG_DISABLED)) {
  1103.             OffGadget(sp->abort_gadget, sp->status_window, nil);
  1104.         }
  1105.         if (!(sp->disconnect_gadget->Flags & GFLG_DISABLED)) {
  1106.             OffGadget(sp->disconnect_gadget, sp->status_window, nil);
  1107.         }
  1108.         break;
  1109.     case SS_CONNECTING:
  1110.     case SS_IDLE:
  1111.     case SS_LOGIN:
  1112.     case SS_ABORTING:
  1113.         if (!(sp->abort_gadget->Flags & GFLG_DISABLED)) {
  1114.             OffGadget(sp->abort_gadget, sp->status_window, nil);
  1115.         }
  1116.         if (sp->disconnect_gadget->Flags & GFLG_DISABLED) {
  1117.             OnGadget(sp->disconnect_gadget, sp->status_window, nil);
  1118.         }
  1119.         break;
  1120.     default:
  1121.         if (sp->abort_gadget->Flags & GFLG_DISABLED) {
  1122.             OnGadget(sp->abort_gadget, sp->status_window, nil);
  1123.         }
  1124.         if (sp->disconnect_gadget->Flags & GFLG_DISABLED) {
  1125.             OnGadget(sp->disconnect_gadget, sp->status_window, nil);
  1126.         }
  1127.         break;
  1128.     }
  1129.     
  1130.     txt.FrontPen = textpen;
  1131.     txt.BackPen = 0;
  1132.     txt.DrawMode = JAM2;
  1133.     txt.LeftEdge = 2;
  1134.     txt.TopEdge = 0;
  1135.     txt.ITextFont = sp->status_window->WScreen->Font;
  1136.     txt.NextText = nil;
  1137.     txt.IText = strings[MSG_STATE_UNKNOWN + sp->site_state];
  1138.     
  1139.     PrintIText(sp->status_window->RPort, &txt, sp->status_window->BorderLeft,
  1140.         sp->abort_gadget->TopEdge + sp->abort_gadget->Height / 4);
  1141.     
  1142.     if (sp->quick) {
  1143.         txt.LeftEdge += IntuiTextLength(&txt);
  1144.         txt.IText = strings[MSG_QUICK_FLAG];
  1145.         PrintIText(sp->status_window->RPort, &txt, sp->status_window->BorderLeft,
  1146.             sp->abort_gadget->TopEdge + sp->abort_gadget->Height / 4);
  1147.     }
  1148.     
  1149.     if (sp->site_state == SS_READING && sp->file_list && sp->file_list->end > 0) {
  1150.         draw_fill_bar(sp, IntuitionBase, GfxBase);
  1151.     }
  1152. }
  1153.  
  1154. void clear_state(site *sp, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  1155. {
  1156.     verify(sp, V_site);
  1157.     truth(sp->status_window != nil);
  1158.  
  1159.     SetAPen(sp->status_window->RPort, 0);
  1160.     SetDrMd(sp->status_window->RPort, JAM1);
  1161.     
  1162.     RectFill(sp->status_window->RPort, sp->status_window->BorderLeft, sp->status_window->BorderTop,
  1163.         sp->abort_gadget->LeftEdge - 1, sp->status_window->Height - sp->status_window->BorderBottom - 1);
  1164.     
  1165.     RectFill(sp->status_window->RPort, sp->abort_gadget->LeftEdge, sp->status_window->BorderTop,
  1166.         sp->status_window->Width - sp->status_window->BorderRight - 1, 
  1167.         sp->abort_gadget->TopEdge - 1);
  1168. }
  1169.  
  1170. void open_status_window(site *sp, struct MsgPort *wport, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  1171. {
  1172.     struct Screen *s;
  1173.     struct Rectangle rect;
  1174.     b32 screen_modeID;
  1175.     struct Gadget *aborg, *disg;
  1176.     b16 swidth, sheight, fheight;
  1177.     struct Window *w;
  1178.  
  1179.     verify(sp, V_site);
  1180.     
  1181.     if (sp->status_window) {
  1182.         WindowToFront(sp->status_window);
  1183.         ActivateWindow(sp->status_window);
  1184.         return;
  1185.     }
  1186.     
  1187.     s = LockPubScreen(nil);
  1188.     if (!s) return;
  1189.     
  1190.     if (s->Font) fheight = s->Font->ta_YSize;
  1191.     else fheight = 8;
  1192.     
  1193.     screen_modeID = GetVPModeID(&s->ViewPort);
  1194.     if (screen_modeID != INVALID_ID) {
  1195.         if (QueryOverscan(screen_modeID, &rect, OSCAN_TEXT)) {
  1196.             aborg = make_gadget(abort_gim);
  1197.             if (aborg) {
  1198.                 aborg->GadgetID = 1;
  1199.                 disg = make_gadget(disconnect_gim);
  1200.                 if (disg) {
  1201.                     disg->GadgetID = 2;
  1202.                     swidth = rect.MaxX - rect.MinX + 1;
  1203.                     sheight = rect.MaxY - rect.MinY + 1;
  1204.                     
  1205.                     w = OpenWindowTags(nil,
  1206.                         WA_Left,    swidth / 4 - s->LeftEdge,
  1207.                         WA_Top,        sheight / 3 - s->TopEdge,
  1208.                         WA_Width,    swidth / 2,
  1209.                         WA_Height,    fheight * 4 + disg->Height,
  1210.                         WA_Flags,    WFLG_DEPTHGADGET | WFLG_DRAGBAR |
  1211.                                 WFLG_SMART_REFRESH | 
  1212.                                 WFLG_CLOSEGADGET |
  1213.                                 WFLG_NOCAREREFRESH,
  1214.                         WA_IDCMP,    0,
  1215.                         WA_PubScreen,    s,
  1216.                         WA_Title,    sp->name,
  1217.                         TAG_END,    0
  1218.                     );
  1219.                     if (w) {
  1220.                         UnlockPubScreen(nil, s);
  1221.                         w->UserPort = wport;
  1222.                         ModifyIDCMP(w, IDCMP_CLOSEWINDOW | IDCMP_GADGETUP);
  1223.                         
  1224.                         aborg->NextGadget = disg;
  1225.                         disg->NextGadget = nil;
  1226.                         
  1227.                         sp->abort_gadget = aborg;
  1228.                         sp->disconnect_gadget = disg;
  1229.                         
  1230.                         disg->LeftEdge = w->Width - w->BorderRight - disg->Width - fheight / 2;
  1231.                         disg->TopEdge = w->Height - w->BorderBottom - disg->Height - fheight / 3;
  1232.                         
  1233.                         aborg->TopEdge = disg->TopEdge;
  1234.                         aborg->LeftEdge = disg->LeftEdge - aborg->Width - fheight / 2;
  1235.                         
  1236.                         AddGList(w, aborg, (b32)-1, 2, nil);
  1237.                         RefreshGadgets(aborg, w, nil);
  1238.                         
  1239.                         sp->status_window = w;
  1240.                         w->UserData = (void *)sp;
  1241.                         
  1242.                         draw_state(sp, IntuitionBase, GfxBase);
  1243.                         
  1244.                         return;
  1245.                     }
  1246.                     free_gadget(disg);
  1247.                 }
  1248.                 free_gadget(aborg);
  1249.             }
  1250.         }
  1251.     }
  1252.     
  1253.     UnlockPubScreen(nil, s);
  1254.     return;
  1255. }
  1256.  
  1257. void close_status_window(site *sp, struct MsgPort *wport, struct IntuitionBase *IntuitionBase)
  1258. {
  1259.     struct IntuiMessage *im;
  1260.     struct Node *succ;
  1261.     struct Window *w;
  1262.     
  1263.     verify(sp, V_site);
  1264.     
  1265.     w = sp->status_window;
  1266.     
  1267.     if (!w) return;
  1268.     
  1269.     Forbid();
  1270.     im = (struct IntuiMessage *)wport->mp_MsgList.lh_Head;
  1271.     while (succ = im->ExecMessage.mn_Node.ln_Succ) {
  1272.         if (im->IDCMPWindow == w) {
  1273.             Remove((struct Node *)im);
  1274.             ReplyMsg((struct Message *)im);
  1275.         }
  1276.         im = (struct IntuiMessage *)succ;
  1277.     }
  1278.     
  1279.     w->UserPort = nil;
  1280.     ModifyIDCMP(w, 0);
  1281.     Permit();
  1282.     
  1283.     CloseWindow(w);
  1284.     
  1285.     free_gadget(sp->abort_gadget);
  1286.     free_gadget(sp->disconnect_gadget);
  1287.     
  1288.     sp->status_window = nil;
  1289.     
  1290.     return;
  1291. }
  1292.  
  1293. void __saveds status_handler(void)
  1294. {
  1295.     struct Process *me;
  1296.     struct MsgPort *rank, *sync, *myport, *cxport, *winport;
  1297.     status_message *reserve, *startup, *sm;
  1298.     struct Library *GadToolsBase, *CxBase;
  1299.     struct IntuitionBase *IntuitionBase;
  1300.     struct GfxBase *GfxBase;
  1301.     CxObj *broker, *filter, *sender, *translate;
  1302.     CxMsg *cxmsg;
  1303.     b32 signals;
  1304.     b32 msgid, msgtype;
  1305.     struct Window *mainw;
  1306.     struct NewBroker nb;
  1307.     struct List *site_labels;
  1308.     struct IntuiMessage *imsg;
  1309.     struct Node *n;
  1310.     site *sp;
  1311.     
  1312.     mainw = nil;
  1313.     site_labels = nil;
  1314.     
  1315.     me = (struct Process *)FindTask(0l);
  1316.     myport = &me->pr_MsgPort;
  1317.     
  1318.     WaitPort(myport);
  1319.     startup = (status_message *)GetMsg(myport);
  1320.     
  1321.     mem_tracking_on();
  1322.     
  1323.     IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 36);
  1324.     if (IntuitionBase) {
  1325.         GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 36);
  1326.         if (GfxBase) {
  1327.             GadToolsBase = OpenLibrary("gadtools.library", 0);
  1328.             if (GadToolsBase) {
  1329.                 CxBase = OpenLibrary("commodities.library", 0);
  1330.                 if (CxBase) {
  1331.                     rank = CreatePort(0, 0);
  1332.                     if (rank) {
  1333.                         sync = CreatePort(0, 0);
  1334.                         if (sync) {
  1335.                             cxport = CreatePort(0, 0);
  1336.                             if (cxport) {
  1337.                                 winport = CreatePort(0, 0);
  1338.                                 if (winport) {
  1339.                                     reserve = (status_message *)allocate_flags(sizeof(*reserve), MEMF_PUBLIC, V_status_message);
  1340.                                     if (reserve) {
  1341.                                         ensure(reserve, V_status_message);
  1342.     
  1343.                                         reserve->header.mn_Length = sizeof(*reserve);
  1344.                                         reserve->header.mn_ReplyPort = sync;
  1345.                                         reserve->header.mn_Node.ln_Name = "ftpstatus reserve message";
  1346.                                         reserve->header.mn_Node.ln_Type = NT_MESSAGE;
  1347.                                         reserve->header.mn_Node.ln_Pri = 0;
  1348.                                 
  1349.                                         nb.nb_Version = NB_VERSION;
  1350.                                         nb.nb_Name = strings[MSG_BROKER_NAME];
  1351.                                         nb.nb_Title = "FTPMount v" VERSION "." REVISION;
  1352.                                         nb.nb_Descr = strings[MSG_BROKER_DESCR];
  1353.                                         nb.nb_Unique = NBU_DUPLICATE;
  1354.                                         nb.nb_Flags = COF_SHOW_HIDE;
  1355.                                         nb.nb_Pri = 0;
  1356.                                         nb.nb_Port = cxport;
  1357.                                         nb.nb_ReservedChannel = 0;
  1358.                 
  1359.                                         broker = CxBroker(&nb, nil);
  1360.                                         if (broker) {
  1361.                                             /* this hotkey stuff taken directly from RKM example */
  1362.                                             if (filter = CxFilter(strings[MSG_HOTKEY])) {
  1363.                                                 /* if we can't add the hotkey stuff, don't fail */
  1364.                                                 if (sender = CxSender(cxport, 1)) {
  1365.                                                     if (translate = (CxTranslate(nil))) {
  1366.                                                         AttachCxObj(broker, filter);
  1367.                                                         AttachCxObj(filter, sender);
  1368.                                                         AttachCxObj(filter, translate);
  1369.                                                     }
  1370.                                                 }
  1371.                                             }
  1372.                                             ActivateCxObj(broker, 1l);
  1373.                                     
  1374.                                             startup->command = 0;
  1375.                                             ReplyMsg(&startup->header);
  1376.                                             goto begin_listening;
  1377.                                         }
  1378.                                         deallocate(reserve, V_status_message);
  1379.                                     }
  1380.                                     DeletePort(winport);
  1381.                                 }
  1382.                                 DeletePort(cxport);
  1383.                             }
  1384.                             DeletePort(sync);
  1385.                         }
  1386.                         DeletePort(rank);
  1387.                     }
  1388.                     CloseLibrary(CxBase);
  1389.                 }
  1390.                 CloseLibrary(GadToolsBase);
  1391.             }
  1392.             CloseLibrary((struct Library *)GfxBase);
  1393.         }
  1394.         CloseLibrary((struct Library *)IntuitionBase);
  1395.     }
  1396.     
  1397.     startup->command = SM_KILL;
  1398.     Forbid();
  1399.     ReplyMsg(&startup->header);
  1400.     return;
  1401.  
  1402. begin_listening:
  1403.     signals = (1 << myport->mp_SigBit) | (1 << cxport->mp_SigBit) | (1 << winport->mp_SigBit);
  1404.  
  1405.     while (1) {
  1406.         Wait(signals);
  1407.         
  1408.         while (cxmsg = (CxMsg *)GetMsg(cxport)) {
  1409.             msgid = CxMsgID(cxmsg);
  1410.             msgtype = CxMsgType(cxmsg);
  1411.             
  1412.             ReplyMsg((struct Message *)cxmsg);
  1413.             
  1414.             switch (msgtype) {
  1415.             case CXM_IEVENT:    /* copied from CXCMD_APPEAR below */
  1416.                 if (mainw != nil) {
  1417.                     close_main_window(mainw, IntuitionBase, GadToolsBase);
  1418.                     mainw = nil;
  1419.                     free_labels(site_labels);
  1420.                 }
  1421.                 
  1422.                 site_labels = site_list();
  1423.                 mainw = open_main_window(site_labels, IntuitionBase, GadToolsBase, GfxBase);
  1424.                 signals = (1 << cxport->mp_SigBit) |
  1425.                         (1 << myport->mp_SigBit) |
  1426.                         (1 << winport->mp_SigBit);
  1427.                 if (mainw != nil) {
  1428.                     signals |= (1 << mainw->UserPort->mp_SigBit);
  1429.                 }
  1430.                 
  1431.                 break;
  1432.             case CXM_COMMAND:
  1433.                 switch (msgid) {
  1434.                 case CXCMD_DISABLE:
  1435.                     reserve->command = SM_SUSPEND;
  1436.                     PutMsg(status_control, &reserve->header);
  1437.                     WaitPort(sync); GetMsg(sync);
  1438.                     
  1439.                     ActivateCxObj(broker, 0l);
  1440.                     break;
  1441.                 case CXCMD_ENABLE:
  1442.                     reserve->command = SM_RESUME;
  1443.                     PutMsg(status_control, &reserve->header);
  1444.                     WaitPort(sync); GetMsg(sync);
  1445.                     
  1446.                     ActivateCxObj(broker, 1l);
  1447.                     break;
  1448.                 case CXCMD_KILL:
  1449.                     reserve->command = SM_KILL;
  1450.                     PutMsg(status_control, &reserve->header);
  1451.                     WaitPort(sync); GetMsg(sync);
  1452.                     
  1453.                     break;
  1454.                 case CXCMD_APPEAR:
  1455.                     if (mainw != nil) {
  1456.                         close_main_window(mainw, IntuitionBase, GadToolsBase);
  1457.                         mainw = nil;
  1458.                         free_labels(site_labels);
  1459.                     }
  1460.                     
  1461.                     site_labels = site_list();
  1462.                     mainw = open_main_window(site_labels, IntuitionBase, GadToolsBase, GfxBase);
  1463.                     signals = (1 << cxport->mp_SigBit) |
  1464.                             (1 << myport->mp_SigBit) |
  1465.                             (1 << winport->mp_SigBit);
  1466.                     if (mainw != nil) {
  1467.                         signals |= (1 << mainw->UserPort->mp_SigBit);
  1468.                     }
  1469.                     
  1470.                     break;
  1471.                 case CXCMD_DISAPPEAR:
  1472.                     if (mainw != nil) {
  1473.                         close_main_window(mainw, IntuitionBase, GadToolsBase);
  1474.                         mainw = nil;
  1475.                         free_labels(site_labels);
  1476.                         
  1477.                         signals = (1 << cxport->mp_SigBit) |
  1478.                                 (1 << myport->mp_SigBit) |
  1479.                                 (1 << winport->mp_SigBit);
  1480.                     }
  1481.                     break;
  1482.                 }
  1483.             }
  1484.         }
  1485.         
  1486.         while (mainw && (imsg = GT_GetIMsg(mainw->UserPort))) {
  1487.             switch (imsg->Class) {
  1488.             case IDCMP_CLOSEWINDOW:
  1489.                 GT_ReplyIMsg(imsg);
  1490.                 close_main_window(mainw, IntuitionBase, GadToolsBase);
  1491.                 mainw = nil;
  1492.                 free_labels(site_labels);
  1493.                 
  1494.                 signals = (1 << cxport->mp_SigBit) |
  1495.                         (1 << myport->mp_SigBit) |
  1496.                         (1 << winport->mp_SigBit);
  1497.                 continue;
  1498.             case IDCMP_REFRESHWINDOW:
  1499.                 GT_BeginRefresh(mainw);
  1500.                 GT_EndRefresh(mainw, true);
  1501.                 break;
  1502.             case IDCMP_GADGETUP:
  1503.                 msgid = imsg->Code;
  1504.                 GT_ReplyIMsg(imsg);
  1505.                 close_main_window(mainw, IntuitionBase, GadToolsBase);
  1506.                 mainw = nil;
  1507.                 
  1508.                 n = site_labels->lh_Head;
  1509.                 while (msgid-- && (n->ln_Succ)) {
  1510.                     n = n->ln_Succ;
  1511.                 }
  1512.                 
  1513.                 if (n->ln_Succ) {
  1514.                     sp = sites;
  1515.                     while (sp) {
  1516.                         if (strcmp(sp->name, n->ln_Name) == 0) {
  1517.                             break;
  1518.                         }
  1519.                         sp = sp->next;
  1520.                     }
  1521.                     
  1522.                     if (sp) {
  1523.                         open_status_window(sp, winport, IntuitionBase, GfxBase);
  1524.                     }
  1525.                 }
  1526.                 
  1527.                 free_labels(site_labels);
  1528.                 
  1529.                 signals = (1 << cxport->mp_SigBit) |
  1530.                         (1 << myport->mp_SigBit) |
  1531.                         (1 << winport->mp_SigBit);
  1532.                 continue;
  1533.             default:
  1534.                 break;
  1535.             }
  1536.             GT_ReplyIMsg(imsg);
  1537.         }
  1538.         
  1539.         while (imsg = (struct IntuiMessage *)GetMsg(winport)) {
  1540.             sp = (site *)imsg->IDCMPWindow->UserData;
  1541.             verify(sp, V_site);
  1542.             
  1543.             switch (imsg->Class) {
  1544.             case IDCMP_CLOSEWINDOW:
  1545.                 ReplyMsg((struct Message *)imsg);
  1546.                 close_status_window(sp, winport, IntuitionBase);
  1547.                 continue;
  1548.             case IDCMP_GADGETUP:
  1549.                 if (((struct Gadget *)imsg->IAddress)->GadgetID == 1) {
  1550.                     /* abort */
  1551.                     Signal(sp->port->mp_SigTask, sp->abort_signals);
  1552.                 } else {
  1553.                     /* disconnect */
  1554.                     Signal(sp->port->mp_SigTask, sp->disconnect_signals);
  1555.                 }
  1556.                 break;
  1557.             }
  1558.         
  1559.             ReplyMsg((struct Message *)imsg);
  1560.         }
  1561.         
  1562.         while (sm = (status_message *)GetMsg(myport)) {
  1563.             verify(sm, V_status_message);
  1564.             
  1565.             switch (sm->command) {
  1566.             case SM_KILL:
  1567.                 if (mainw != nil) {
  1568.                     close_main_window(mainw, IntuitionBase, GadToolsBase);
  1569.                     free_labels(site_labels);
  1570.                 }
  1571.                 
  1572.                 Forbid();
  1573.                 while (cxmsg = (CxMsg *)GetMsg(cxport)) {
  1574.                     ReplyMsg((struct Message *)cxmsg);
  1575.                 }
  1576.                 
  1577.                 DeleteCxObjAll(broker);
  1578.                 Permit();
  1579.                 
  1580.                 deallocate(reserve, V_status_message);
  1581.                 
  1582.                 DeletePort(winport);
  1583.                 DeletePort(cxport);
  1584.                 DeletePort(sync);
  1585.                 DeletePort(rank);
  1586.                 
  1587.                 check_memory();
  1588.  
  1589.                 CloseLibrary(CxBase);
  1590.                 CloseLibrary(GadToolsBase);
  1591.                 CloseLibrary((struct Library *)GfxBase);
  1592.                 CloseLibrary((struct Library *)IntuitionBase);
  1593.                 
  1594.                 Forbid();
  1595.                 ReplyMsg(&sm->header);
  1596.                 return;
  1597.             case SM_NEW_SITE:
  1598.                 if (sm->data) {
  1599.                     open_status_window(sm->this_site, winport, IntuitionBase, GfxBase);
  1600.                 }
  1601.                 break;
  1602.             case SM_DEAD_SITE:
  1603.                 close_status_window(sm->this_site, winport, IntuitionBase);
  1604.                 break;
  1605.             case SM_STATE_CHANGE:
  1606.                 if (sm->this_site->status_window) {
  1607.                     clear_state(sm->this_site, IntuitionBase, GfxBase);
  1608.                     draw_state(sm->this_site, IntuitionBase, GfxBase);
  1609.                 }
  1610.                 break;
  1611.             case SM_PROGRESS:
  1612.                 if (sm->this_site->status_window) {
  1613.                     update_fill_bar(sm->this_site, IntuitionBase, GfxBase);
  1614.                 }
  1615.                 break;
  1616.             }
  1617.             ReplyMsg(&sm->header);
  1618.         }
  1619.     }
  1620. }
  1621.  
  1622.