home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga Shareware Floppies / ma64.dms / ma64.adf / FTPMount-1.0 / Source / request.c < prev    next >
C/C++ Source or Header  |  1995-12-10  |  38KB  |  1,624 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.     ScreenToFront(s);
  526.     
  527.     if (s->Font) fheight = s->Font->ta_YSize;
  528.     else fheight = 8;
  529.     
  530.     if (sp->password) {
  531.         strcpy(phd.password, sp->password);
  532.         strcpy(phd.undo, sp->password);
  533.         
  534.         z = sp->password;
  535.         while (*z) {
  536.             *z++ = '*';
  537.         }
  538.     } else {
  539.         phd.password[0] = 0;
  540.         phd.undo[0] = 0;
  541.     }
  542.     
  543.     wheight = fheight * 8;
  544.     
  545.     vi = GetVisualInfo(s, TAG_END);
  546.     if (vi != nil) {
  547.         screen_modeID = GetVPModeID(&s->ViewPort);
  548.         if (screen_modeID != INVALID_ID) {
  549.             if (QueryOverscan(screen_modeID, &rect, OSCAN_TEXT)) {
  550.                 swidth = rect.MaxX - rect.MinX + 1;
  551.                 sheight = rect.MaxY - rect.MinY + 1;
  552.                 
  553.                 sprintf(sp->read_buffer, strings[MSG_LOGIN_TO], sp->host);
  554.                 
  555.                 w = OpenWindowTags(nil,
  556.                     WA_Left,    swidth / 4 - s->LeftEdge,
  557.                     WA_Top,        sheight / 2 - wheight / 2 - s->TopEdge,
  558.                     WA_Width,    swidth / 2,
  559.                     WA_Height,    wheight,
  560.                     WA_IDCMP,    IDCMP_ACTIVEWINDOW | IDCMP_REFRESHWINDOW | 
  561.                             BUTTONIDCMP | STRINGIDCMP,
  562.                     WA_PubScreen,    s,
  563.                     WA_Activate,    true,
  564.                     WA_DragBar,    true,
  565.                     WA_DepthGadget,    true,
  566.                     WA_Title,    sp->read_buffer,
  567.                     WA_AutoAdjust,    true,
  568.                     TAG_END
  569.                 );
  570.                 if (w) {
  571.                     gad = CreateContext(&glist);
  572.                     if (gad) {
  573.                         user.ng_LeftEdge = w->Width / 4;
  574.                         user.ng_TopEdge = w->BorderTop + fheight / 2;
  575.                         user.ng_Width = (w->Width * 3 / 4) - w->BorderRight - fheight / 2;
  576.                         user.ng_Height = fheight * 3 / 2;
  577.                         user.ng_GadgetText = strings[MSG_USER_NAME];
  578.                         user.ng_TextAttr = s->Font;
  579.                         user.ng_GadgetID = 1;
  580.                         user.ng_Flags = PLACETEXT_LEFT;
  581.                         user.ng_VisualInfo = vi;
  582.                         
  583.                         pass.ng_LeftEdge = w->Width / 4;
  584.                         pass.ng_TopEdge = w->BorderTop + (fheight * 5 / 2);
  585.                         pass.ng_Width = (w->Width * 3 / 4) - w->BorderRight - fheight / 2;
  586.                         pass.ng_Height = fheight * 3 / 2;
  587.                         pass.ng_GadgetText = strings[MSG_PASSWORD_NAME];
  588.                         pass.ng_TextAttr = s->Font;
  589.                         pass.ng_GadgetID = 2;
  590.                         pass.ng_Flags = PLACETEXT_LEFT;
  591.                         pass.ng_VisualInfo = vi;
  592.                         
  593.                         userg = gad = CreateGadget(STRING_KIND, gad, &user,
  594.                             GTST_String,    sp->user,
  595.                             GTST_MaxChars,    MAX_USER_LENGTH,
  596.                             TAG_END
  597.                         );
  598.                         
  599.                         passg = gad = CreateGadget(STRING_KIND, gad, &pass,
  600.                             GTST_String,    sp->password,
  601.                             GTST_MaxChars,    MAX_PASS_LENGTH,
  602.                             GTST_EditHook,    (b32)&pass_hook,
  603.                             TAG_END
  604.                         );
  605.                         
  606.                         if (gad) {
  607.                             login = make_gadget(login_gim);
  608.                             if (login) {
  609.                                 cancel = make_gadget(cancel_gim);
  610.                                 if (cancel) {
  611.                                     login->LeftEdge = fheight / 2 + w->BorderLeft;
  612.                                     login->TopEdge = w->Height - w->BorderBottom - login->Height - fheight / 2;
  613.                                     
  614.                                     cancel->LeftEdge = w->Width - w->BorderRight - cancel->Width - fheight / 2;
  615.                                     cancel->TopEdge = login->TopEdge;
  616.                                     
  617.                                     login->GadgetID = 3;
  618.                                     cancel->GadgetID = 4;
  619.                                     
  620.                                     AddGadget(w, cancel, 100);
  621.                                     AddGadget(w, login, 100);
  622.                             
  623.                                     AddGList(w, glist, 0, 100, nil);
  624.                                     
  625.                                     RefreshGadgets(glist, w, nil);
  626.                                     GT_RefreshWindow(w, nil);
  627.                             
  628.                                     goto listen;
  629.                                 }
  630.                                 free_gadget(login);
  631.                             }
  632.                         }
  633.                         
  634.                         FreeGadgets(glist);
  635.                     }
  636.                     CloseWindow(w);
  637.                 }
  638.             }
  639.         }
  640.         FreeVisualInfo(vi);
  641.     }
  642.     
  643.     UnlockPubScreen(nil, s);
  644.     
  645.     return false;
  646.  
  647. listen:
  648.     csig = 1 << canw->UserPort->mp_SigBit | sp->abort_signals | sp->disconnect_signals;
  649.     signals = (1 << w->UserPort->mp_SigBit) | csig;
  650.  
  651.     while (1) {
  652.         if (Wait(signals) & csig) {
  653.             CloseWindow(w);
  654.  
  655.             FreeGadgets(glist);
  656.  
  657.             free_gadget(cancel);
  658.             free_gadget(login);
  659.  
  660.             FreeVisualInfo(vi);
  661.             UnlockPubScreen(nil, s);
  662.                             
  663.             return false;
  664.         }
  665.         
  666.         while (im = GT_GetIMsg(w->UserPort)) {
  667.             gad = (struct Gadget *)im->IAddress;
  668.             
  669.             switch (im->Class) {
  670.             case IDCMP_ACTIVEWINDOW:
  671.                 if (sp->needs_user) {
  672.                     ActivateGadget(userg, w, nil);
  673.                 } else {
  674.                     ActivateGadget(passg, w, nil);
  675.                 }
  676.                 break;
  677.             case IDCMP_GADGETUP:
  678.                 switch (gad->GadgetID) {
  679.                 case 1:
  680.                     if (im->Code == 0) {
  681.                         ActivateGadget(passg, w, nil);
  682.                     }
  683.                     sp->needs_user = false;
  684.                     break;
  685.                 case 2:
  686.                     if (im->Code != 0) {
  687.                         break;
  688.                     }
  689.                     /* else fall through to Login */
  690.                 case 3:
  691.                     if (sp->user) deallocate(sp->user, V_cstr);
  692.                     if (sp->password) deallocate(sp->password, V_cstr);
  693.                     
  694.                     z = ((struct StringInfo *)userg->SpecialInfo)->Buffer;
  695.                     if (z[0] != '\0') {
  696.                         sp->user = (b8 *)allocate(strlen(z) + 1, V_cstr);
  697.                         if (sp->user) {
  698.                             strcpy(sp->user, z);
  699.                         }
  700.                     } else {
  701.                         sp->user = nil;
  702.                     }
  703.                     
  704.                     z = phd.password;
  705.                     if (z[0] != '\0') {
  706.                         sp->password = (b8 *)allocate(strlen(z) + 1, V_cstr);
  707.                         if (sp->password) {
  708.                             strcpy(sp->password, z);
  709.                         }
  710.                     } else {
  711.                         sp->password = nil;
  712.                     }
  713.                     
  714.                     Forbid();
  715.                     GT_ReplyIMsg(im);
  716.                     
  717.                     CloseWindow(w);
  718.                     Permit();
  719.                     
  720.                     FreeGadgets(glist);
  721.                     free_gadget(cancel);
  722.                     free_gadget(login);
  723.  
  724.                     FreeVisualInfo(vi);
  725.                     UnlockPubScreen(nil, s);
  726.                             
  727.                     return true;
  728.                 case 4:
  729.                     Forbid();
  730.                     GT_ReplyIMsg(im);
  731.                     
  732.                     CloseWindow(w);
  733.                     Permit();
  734.                     
  735.                     FreeGadgets(glist);
  736.                     
  737.                     free_gadget(cancel);
  738.                     free_gadget(login);
  739.  
  740.                     FreeVisualInfo(vi);
  741.                     UnlockPubScreen(nil, s);
  742.                             
  743.                     return false;
  744.                 }
  745.                 break;
  746.             case IDCMP_REFRESHWINDOW:
  747.                 GT_BeginRefresh(w);
  748.                 GT_EndRefresh(w, true);
  749.                 break;
  750.             }
  751.             
  752.             GT_ReplyIMsg(im);
  753.         }
  754.     }
  755. }
  756.  
  757. struct Window *open_main_window(struct List *site_labels, struct IntuitionBase *IntuitionBase, struct Library *GadToolsBase, struct GfxBase *GfxBase)
  758. {
  759.     struct Gadget *glist, *gad;
  760.     struct NewGadget ng;
  761.     struct Screen *s;
  762.     void *vi;
  763.     b32 screen_modeID;
  764.     struct Rectangle rect;
  765.     struct Window *w;
  766.     sb32 swidth, sheight;
  767.     
  768.     glist = nil;
  769.     
  770.     s = LockPubScreen(nil);
  771.     if (!s) return nil;
  772.     
  773.     vi = GetVisualInfo(s, TAG_END);
  774.     if (vi != nil) {
  775.         screen_modeID = GetVPModeID(&s->ViewPort);
  776.         if (screen_modeID != INVALID_ID) {
  777.             if (QueryOverscan(screen_modeID, &rect, OSCAN_TEXT)) {
  778.                 swidth = rect.MaxX - rect.MinX + 1;
  779.                 sheight = rect.MaxY - rect.MinY + 1;
  780.                 
  781.                 w = OpenWindowTags(nil,
  782.                     WA_Left,    swidth / 3 - s->LeftEdge,
  783.                     WA_Top,        sheight / 4 - s->TopEdge,
  784.                     WA_Width,    swidth / 3,
  785.                     WA_Height,    sheight / 2,
  786.                     WA_IDCMP,    IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | LISTVIEWIDCMP,
  787.                     WA_PubScreen,    s,
  788.                     WA_Activate,    true,
  789.                     WA_DragBar,    true,
  790.                     WA_DepthGadget,    true,
  791.                     WA_CloseGadget,    true,
  792.                     WA_Title,    strings[MSG_CURRENT_SITES],
  793.                     WA_AutoAdjust,    true,
  794.                     TAG_END
  795.                 );
  796.                 if (w) {
  797.                     gad = CreateContext(&glist);
  798.                     if (gad) {
  799.                         ng.ng_TextAttr = s->Font;
  800.                         ng.ng_VisualInfo = vi;
  801.                         ng.ng_LeftEdge = w->BorderLeft;
  802.                         ng.ng_TopEdge = w->BorderTop;
  803.                         ng.ng_Width = w->Width - w->BorderLeft - w->BorderRight;
  804.                         ng.ng_Height = w->Height - w->BorderTop - w->BorderBottom;
  805.                         ng.ng_GadgetText = nil;
  806.                         ng.ng_GadgetID = 0;
  807.                         ng.ng_Flags = 0;
  808.                         gad = CreateGadget(LISTVIEW_KIND, gad, &ng, 
  809.                             GTLV_ReadOnly,    false, 
  810.                             GTLV_Labels,    site_labels,
  811.                             TAG_END
  812.                         );
  813.                         if (gad) {
  814.                             AddGList(w, glist, 0, -1, nil);
  815.                             
  816.                             RefreshGadgets(glist, w, nil);
  817.                             GT_RefreshWindow(w, nil);
  818.                             
  819.                             w->UserData = (void *)glist;
  820.                             
  821.                             FreeVisualInfo(vi);
  822.                             UnlockPubScreen(nil, s);
  823.                             
  824.                             return w;
  825.                         }
  826.                         FreeGadgets(glist);
  827.                     }
  828.                     CloseWindow(w);
  829.                 }
  830.             }
  831.         }
  832.         FreeVisualInfo(vi);
  833.     }
  834.     
  835.     UnlockPubScreen(nil, s);
  836.     
  837.     return nil;
  838. }
  839.  
  840. void close_main_window(struct Window *w, struct IntuitionBase *IntuitionBase, struct Library *GadToolsBase)
  841. {
  842.     struct Gadget *glist;
  843.     struct IntuiMessage *im;
  844.     
  845.     Forbid();
  846.     while (im = GT_GetIMsg(w->UserPort)) {
  847.         if (im->Class == IDCMP_REFRESHWINDOW) {
  848.             GT_BeginRefresh(w);
  849.             GT_EndRefresh(w, true);
  850.         }
  851.         GT_ReplyIMsg(im);
  852.     }
  853.     
  854.     glist = (struct Gadget *)w->UserData;
  855.     
  856.     CloseWindow(w);
  857.     FreeGadgets(glist);
  858.     Permit();
  859. }
  860.  
  861. #define V_List 19561
  862. #define V_Node 20079
  863.  
  864. struct List *site_list(void)
  865. {
  866.     struct List *l;
  867.     struct Node *n;
  868.     site *sp;
  869.     
  870.     l = (struct List *)allocate(sizeof(*l), V_List);
  871.     if (!l) return l;
  872.     
  873.     NewList(l);
  874.     
  875.     Forbid();
  876.     sp = sites;
  877.     while (sp) {
  878.         n = (struct Node *)allocate(sizeof(*n), V_Node);
  879.         if (!n) {
  880.             Permit();
  881.             return l;
  882.         }
  883.         
  884.         n->ln_Name = (b8 *)allocate(strlen(sp->name) + 1, V_cstr);
  885.         if (!n->ln_Name) {
  886.             Permit();
  887.             deallocate(n, V_Node);
  888.             return l;
  889.         }
  890.         
  891.         strcpy(n->ln_Name, sp->name);
  892.         
  893.         n->ln_Pri = 0;
  894.         AddTail(l, n);
  895.         sp = sp->next;
  896.     }
  897.     Permit();
  898.     
  899.     return l;
  900. }
  901.  
  902. void free_labels(struct List *l)
  903. {
  904.     struct Node *n;
  905.     
  906.     while (n = RemHead(l)) {
  907.         deallocate(n->ln_Name, V_cstr);
  908.         deallocate(n, V_Node);
  909.     }
  910.     
  911.     deallocate(l, V_List);
  912. }
  913.  
  914. void draw_fill_bar(site *sp, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  915. {
  916.     struct Window *w;
  917.     struct RastPort *rp;
  918.     b32 x1, y1, x2, y2, gap;
  919.     
  920.     verify(sp, V_site);
  921.     
  922.     w = sp->status_window;
  923.     if (!w) return;
  924.     
  925.     rp = w->RPort;
  926.     
  927.     x1 = w->BorderLeft;
  928.     y1 = w->BorderTop;
  929.     
  930.     x2 = w->Width - w->BorderRight - 1;
  931.     y2 = sp->abort_gadget->TopEdge - 1;
  932.     
  933.     gap = (y2 - y1) / 4;
  934.     
  935.     x2 = x1 + (x2 - x1) * 3 / 4;
  936.     
  937.     x1 += gap;
  938.     y1 += gap;
  939.     y2 -= gap;
  940.     
  941.     SetDrMd(rp, JAM2);
  942.     
  943.     SetAPen(rp, lightpen);
  944.     Move(rp, x2, y1);
  945.     Draw(rp, x2, y2);
  946.     Draw(rp, x1, y2);
  947.     SetAPen(rp, darkpen);
  948.     Draw(rp, x1, y1);
  949.     Draw(rp, x2, y1);
  950.     
  951.     SetAPen(rp, fillpen);
  952.     
  953.     x1++;
  954.     y1++;
  955.     y2--;
  956.     x2--;
  957.     
  958.     if (sp->file_list) {
  959.         verify(sp->file_list, V_file_info);
  960.         
  961.         x2 = x1 + ((x2 - x1) * sp->file_list->rpos) / sp->file_list->end;
  962.         RectFill(rp, x1, y1, x2, y2);
  963.     }
  964. }
  965.  
  966. void update_fill_bar(site *sp, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  967. {
  968.     struct Window *w;
  969.     struct RastPort *rp;
  970.     b32 x1, y1, x2, y2, gap;
  971.     struct IntuiText txt;
  972.     b8 buffer[20], *z;
  973.     file_info *fip;
  974.     
  975.     verify(sp, V_site);
  976.     
  977.     w = sp->status_window;
  978.     if (!w) return;
  979.     
  980.     Forbid();
  981.     fip = sp->file_list;
  982.     if (!fip) {
  983.         Permit();
  984.         return;
  985.     }
  986.     verify(fip, V_file_info);
  987.     
  988.     z = fip->fname + strlen(fip->fname) - 1;
  989.     while (z > fip->fname && *z != '/') z--;
  990.     if (*z == '/') z++;
  991.     
  992.     rp = w->RPort;
  993.     
  994.     x1 = w->BorderLeft;
  995.     y1 = w->BorderTop;
  996.     
  997.     x2 = w->Width - w->BorderRight - 1;
  998.     y2 = sp->abort_gadget->TopEdge - 1;
  999.     
  1000.     gap = (y2 - y1) / 4;
  1001.     
  1002.     x2 = x1 + (x2 - x1) * 3 / 4 - 1;
  1003.     
  1004.     x1 += gap + 1;
  1005.     y1 += gap + 1;
  1006.     y2 -= gap + 1;
  1007.     
  1008.     if (sp->site_state == SS_WRITING || !fip->end) {    /* just print how many k we have transferred */
  1009.         txt.FrontPen = textpen;
  1010.         txt.BackPen = 0;
  1011.         txt.DrawMode = JAM2;
  1012.         txt.LeftEdge = x1;
  1013.         txt.TopEdge = y1;
  1014.         txt.ITextFont = sp->status_window->WScreen->Font;
  1015.         txt.NextText = nil;
  1016.         txt.IText = z;
  1017.         PrintIText(rp, &txt, 0, 0);
  1018.         
  1019.         txt.LeftEdge += IntuiTextLength(&txt);
  1020.         txt.FrontPen = textpen;
  1021.         txt.IText = buffer;
  1022.  
  1023.         buffer[0] = ':';
  1024.         buffer[1] = ' ';
  1025.         x1 = 2;
  1026.         y1 = fip->rpos / 1024;
  1027.         buffer[x1] = '0';
  1028.         while (y1 >= 100000) {
  1029.             buffer[x1]++;
  1030.             y1 -= 100000;
  1031.         }
  1032.         if (buffer[x1] > '0') x1++;
  1033.         buffer[x1] = '0';
  1034.         while (y1 >= 10000) {
  1035.             buffer[x1]++;
  1036.             y1 -= 10000;
  1037.         }
  1038.         if (buffer[x1] > '0' || x1 != 2) x1++;
  1039.         buffer[x1] = '0';
  1040.         while (y1 >= 1000) {
  1041.             buffer[x1]++;
  1042.             y1 -= 1000;
  1043.         }
  1044.         if (buffer[x1] > '0' || x1 != 2) x1++;
  1045.         buffer[x1] = '0';
  1046.         while (y1 >= 100) {
  1047.             buffer[x1]++;
  1048.             y1 -= 100;
  1049.         }
  1050.         if (buffer[x1] > '0' || x1 != 2) x1++;
  1051.         buffer[x1] = '0';
  1052.         while (y1 >= 10) {
  1053.             buffer[x1]++;
  1054.             y1 -= 10;
  1055.         }
  1056.         if (buffer[x1] > '0' || x1 != 2) x1++;
  1057.         buffer[x1++] = y1 + '0';
  1058.         buffer[x1++] = ' ';
  1059.         buffer[x1++] = 'k';
  1060.         buffer[x1++] = ' ';
  1061.         buffer[x1++] = ' ';
  1062.         buffer[x1] = 0;
  1063.  
  1064.         PrintIText(rp, &txt, 0, 0);
  1065.         
  1066.         Permit();
  1067.         
  1068.         return;
  1069.     }
  1070.     
  1071.     /* reading ... can do a filler bar */
  1072.     
  1073.     SetDrMd(rp, JAM2);
  1074.     SetAPen(rp, fillpen);
  1075.  
  1076.     txt.FrontPen = lightpen;
  1077.     txt.BackPen = 0;
  1078.     txt.DrawMode = JAM1;
  1079.     txt.TopEdge = y1;
  1080.     txt.ITextFont = sp->status_window->WScreen->Font;
  1081.     txt.NextText = nil;
  1082.     txt.IText = z;
  1083.     
  1084.     txt.LeftEdge = (x1 + x2) / 2 - IntuiTextLength(&txt) / 2;
  1085.     
  1086.     x2 = x1 + ((x2 - x1) * sp->file_list->rpos) / sp->file_list->end;
  1087.     RectFill(rp, x1, y1, x2, y2);
  1088.  
  1089.     PrintIText(rp, &txt, 0, 0);
  1090.     
  1091.     Permit();
  1092.     
  1093.     return;
  1094. }
  1095.  
  1096. void draw_state(site *sp, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  1097. {
  1098.     struct IntuiText txt;
  1099.     
  1100.     /* gadget states */
  1101.     switch (sp->site_state) {
  1102.     case SS_DISCONNECTED:
  1103.     case SS_DISCONNECTING:
  1104.         if (!(sp->abort_gadget->Flags & GFLG_DISABLED)) {
  1105.             OffGadget(sp->abort_gadget, sp->status_window, nil);
  1106.         }
  1107.         if (!(sp->disconnect_gadget->Flags & GFLG_DISABLED)) {
  1108.             OffGadget(sp->disconnect_gadget, sp->status_window, nil);
  1109.         }
  1110.         break;
  1111.     case SS_CONNECTING:
  1112.     case SS_IDLE:
  1113.     case SS_LOGIN:
  1114.     case SS_ABORTING:
  1115.         if (!(sp->abort_gadget->Flags & GFLG_DISABLED)) {
  1116.             OffGadget(sp->abort_gadget, sp->status_window, nil);
  1117.         }
  1118.         if (sp->disconnect_gadget->Flags & GFLG_DISABLED) {
  1119.             OnGadget(sp->disconnect_gadget, sp->status_window, nil);
  1120.         }
  1121.         break;
  1122.     default:
  1123.         if (sp->abort_gadget->Flags & GFLG_DISABLED) {
  1124.             OnGadget(sp->abort_gadget, sp->status_window, nil);
  1125.         }
  1126.         if (sp->disconnect_gadget->Flags & GFLG_DISABLED) {
  1127.             OnGadget(sp->disconnect_gadget, sp->status_window, nil);
  1128.         }
  1129.         break;
  1130.     }
  1131.     
  1132.     txt.FrontPen = textpen;
  1133.     txt.BackPen = 0;
  1134.     txt.DrawMode = JAM2;
  1135.     txt.LeftEdge = 2;
  1136.     txt.TopEdge = 0;
  1137.     txt.ITextFont = sp->status_window->WScreen->Font;
  1138.     txt.NextText = nil;
  1139.     txt.IText = strings[MSG_STATE_UNKNOWN + sp->site_state];
  1140.     
  1141.     PrintIText(sp->status_window->RPort, &txt, sp->status_window->BorderLeft,
  1142.         sp->abort_gadget->TopEdge + sp->abort_gadget->Height / 4);
  1143.     
  1144.     if (sp->quick) {
  1145.         txt.LeftEdge += IntuiTextLength(&txt);
  1146.         txt.IText = strings[MSG_QUICK_FLAG];
  1147.         PrintIText(sp->status_window->RPort, &txt, sp->status_window->BorderLeft,
  1148.             sp->abort_gadget->TopEdge + sp->abort_gadget->Height / 4);
  1149.     }
  1150.     
  1151.     if (sp->site_state == SS_READING && sp->file_list && sp->file_list->end > 0) {
  1152.         draw_fill_bar(sp, IntuitionBase, GfxBase);
  1153.     }
  1154. }
  1155.  
  1156. void clear_state(site *sp, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  1157. {
  1158.     verify(sp, V_site);
  1159.     truth(sp->status_window != nil);
  1160.  
  1161.     SetAPen(sp->status_window->RPort, 0);
  1162.     SetDrMd(sp->status_window->RPort, JAM1);
  1163.     
  1164.     RectFill(sp->status_window->RPort, sp->status_window->BorderLeft, sp->status_window->BorderTop,
  1165.         sp->abort_gadget->LeftEdge - 1, sp->status_window->Height - sp->status_window->BorderBottom - 1);
  1166.     
  1167.     RectFill(sp->status_window->RPort, sp->abort_gadget->LeftEdge, sp->status_window->BorderTop,
  1168.         sp->status_window->Width - sp->status_window->BorderRight - 1, 
  1169.         sp->abort_gadget->TopEdge - 1);
  1170. }
  1171.  
  1172. void open_status_window(site *sp, struct MsgPort *wport, struct IntuitionBase *IntuitionBase, struct GfxBase *GfxBase)
  1173. {
  1174.     struct Screen *s;
  1175.     struct Rectangle rect;
  1176.     b32 screen_modeID;
  1177.     struct Gadget *aborg, *disg;
  1178.     b16 swidth, sheight, fheight;
  1179.     struct Window *w;
  1180.  
  1181.     verify(sp, V_site);
  1182.     
  1183.     if (sp->status_window) {
  1184.         WindowToFront(sp->status_window);
  1185.         ActivateWindow(sp->status_window);
  1186.         return;
  1187.     }
  1188.     
  1189.     s = LockPubScreen(nil);
  1190.     if (!s) return;
  1191.     
  1192.     if (s->Font) fheight = s->Font->ta_YSize;
  1193.     else fheight = 8;
  1194.     
  1195.     screen_modeID = GetVPModeID(&s->ViewPort);
  1196.     if (screen_modeID != INVALID_ID) {
  1197.         if (QueryOverscan(screen_modeID, &rect, OSCAN_TEXT)) {
  1198.             aborg = make_gadget(abort_gim);
  1199.             if (aborg) {
  1200.                 aborg->GadgetID = 1;
  1201.                 disg = make_gadget(disconnect_gim);
  1202.                 if (disg) {
  1203.                     disg->GadgetID = 2;
  1204.                     swidth = rect.MaxX - rect.MinX + 1;
  1205.                     sheight = rect.MaxY - rect.MinY + 1;
  1206.                     
  1207.                     w = OpenWindowTags(nil,
  1208.                         WA_Left,    swidth / 4 - s->LeftEdge,
  1209.                         WA_Top,        sheight / 3 - s->TopEdge,
  1210.                         WA_Width,    swidth / 2,
  1211.                         WA_Height,    fheight * 4 + disg->Height,
  1212.                         WA_Flags,    WFLG_DEPTHGADGET | WFLG_DRAGBAR |
  1213.                                 WFLG_SMART_REFRESH | 
  1214.                                 WFLG_CLOSEGADGET |
  1215.                                 WFLG_NOCAREREFRESH,
  1216.                         WA_IDCMP,    0,
  1217.                         WA_PubScreen,    s,
  1218.                         WA_Title,    sp->name,
  1219.                         TAG_END,    0
  1220.                     );
  1221.                     if (w) {
  1222.                         UnlockPubScreen(nil, s);
  1223.                         w->UserPort = wport;
  1224.                         ModifyIDCMP(w, IDCMP_CLOSEWINDOW | IDCMP_GADGETUP);
  1225.                         
  1226.                         aborg->NextGadget = disg;
  1227.                         disg->NextGadget = nil;
  1228.                         
  1229.                         sp->abort_gadget = aborg;
  1230.                         sp->disconnect_gadget = disg;
  1231.                         
  1232.                         disg->LeftEdge = w->Width - w->BorderRight - disg->Width - fheight / 2;
  1233.                         disg->TopEdge = w->Height - w->BorderBottom - disg->Height - fheight / 3;
  1234.                         
  1235.                         aborg->TopEdge = disg->TopEdge;
  1236.                         aborg->LeftEdge = disg->LeftEdge - aborg->Width - fheight / 2;
  1237.                         
  1238.                         AddGList(w, aborg, (b32)-1, 2, nil);
  1239.                         RefreshGadgets(aborg, w, nil);
  1240.                         
  1241.                         sp->status_window = w;
  1242.                         w->UserData = (void *)sp;
  1243.                         
  1244.                         draw_state(sp, IntuitionBase, GfxBase);
  1245.                         
  1246.                         return;
  1247.                     }
  1248.                     free_gadget(disg);
  1249.                 }
  1250.                 free_gadget(aborg);
  1251.             }
  1252.         }
  1253.     }
  1254.     
  1255.     UnlockPubScreen(nil, s);
  1256.     return;
  1257. }
  1258.  
  1259. void close_status_window(site *sp, struct MsgPort *wport, struct IntuitionBase *IntuitionBase)
  1260. {
  1261.     struct IntuiMessage *im;
  1262.     struct Node *succ;
  1263.     struct Window *w;
  1264.     
  1265.     verify(sp, V_site);
  1266.     
  1267.     w = sp->status_window;
  1268.     
  1269.     if (!w) return;
  1270.     
  1271.     Forbid();
  1272.     im = (struct IntuiMessage *)wport->mp_MsgList.lh_Head;
  1273.     while (succ = im->ExecMessage.mn_Node.ln_Succ) {
  1274.         if (im->IDCMPWindow == w) {
  1275.             Remove((struct Node *)im);
  1276.             ReplyMsg((struct Message *)im);
  1277.         }
  1278.         im = (struct IntuiMessage *)succ;
  1279.     }
  1280.     
  1281.     w->UserPort = nil;
  1282.     ModifyIDCMP(w, 0);
  1283.     Permit();
  1284.     
  1285.     CloseWindow(w);
  1286.     
  1287.     free_gadget(sp->abort_gadget);
  1288.     free_gadget(sp->disconnect_gadget);
  1289.     
  1290.     sp->status_window = nil;
  1291.     
  1292.     return;
  1293. }
  1294.  
  1295. void __saveds status_handler(void)
  1296. {
  1297.     struct Process *me;
  1298.     struct MsgPort *rank, *sync, *myport, *cxport, *winport;
  1299.     status_message *reserve, *startup, *sm;
  1300.     struct Library *GadToolsBase, *CxBase;
  1301.     struct IntuitionBase *IntuitionBase;
  1302.     struct GfxBase *GfxBase;
  1303.     CxObj *broker, *filter, *sender, *translate;
  1304.     CxMsg *cxmsg;
  1305.     b32 signals;
  1306.     b32 msgid, msgtype;
  1307.     struct Window *mainw;
  1308.     struct NewBroker nb;
  1309.     struct List *site_labels;
  1310.     struct IntuiMessage *imsg;
  1311.     struct Node *n;
  1312.     site *sp;
  1313.     
  1314.     mainw = nil;
  1315.     site_labels = nil;
  1316.     
  1317.     me = (struct Process *)FindTask(0l);
  1318.     myport = &me->pr_MsgPort;
  1319.     
  1320.     WaitPort(myport);
  1321.     startup = (status_message *)GetMsg(myport);
  1322.     
  1323.     mem_tracking_on();
  1324.     
  1325.     IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 36);
  1326.     if (IntuitionBase) {
  1327.         GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 36);
  1328.         if (GfxBase) {
  1329.             GadToolsBase = OpenLibrary("gadtools.library", 0);
  1330.             if (GadToolsBase) {
  1331.                 CxBase = OpenLibrary("commodities.library", 0);
  1332.                 if (CxBase) {
  1333.                     rank = CreatePort(0, 0);
  1334.                     if (rank) {
  1335.                         sync = CreatePort(0, 0);
  1336.                         if (sync) {
  1337.                             cxport = CreatePort(0, 0);
  1338.                             if (cxport) {
  1339.                                 winport = CreatePort(0, 0);
  1340.                                 if (winport) {
  1341.                                     reserve = (status_message *)allocate_flags(sizeof(*reserve), MEMF_PUBLIC, V_status_message);
  1342.                                     if (reserve) {
  1343.                                         ensure(reserve, V_status_message);
  1344.     
  1345.                                         reserve->header.mn_Length = sizeof(*reserve);
  1346.                                         reserve->header.mn_ReplyPort = sync;
  1347.                                         reserve->header.mn_Node.ln_Name = "ftpstatus reserve message";
  1348.                                         reserve->header.mn_Node.ln_Type = NT_MESSAGE;
  1349.                                         reserve->header.mn_Node.ln_Pri = 0;
  1350.                                 
  1351.                                         nb.nb_Version = NB_VERSION;
  1352.                                         nb.nb_Name = strings[MSG_BROKER_NAME];
  1353.                                         nb.nb_Title = "FTPMount v" VERSION "." REVISION;
  1354.                                         nb.nb_Descr = strings[MSG_BROKER_DESCR];
  1355.                                         nb.nb_Unique = NBU_DUPLICATE;
  1356.                                         nb.nb_Flags = COF_SHOW_HIDE;
  1357.                                         nb.nb_Pri = 0;
  1358.                                         nb.nb_Port = cxport;
  1359.                                         nb.nb_ReservedChannel = 0;
  1360.                 
  1361.                                         broker = CxBroker(&nb, nil);
  1362.                                         if (broker) {
  1363.                                             /* this hotkey stuff taken directly from RKM example */
  1364.                                             if (filter = CxFilter(strings[MSG_HOTKEY])) {
  1365.                                                 /* if we can't add the hotkey stuff, don't fail */
  1366.                                                 if (sender = CxSender(cxport, 1)) {
  1367.                                                     if (translate = (CxTranslate(nil))) {
  1368.                                                         AttachCxObj(broker, filter);
  1369.                                                         AttachCxObj(filter, sender);
  1370.                                                         AttachCxObj(filter, translate);
  1371.                                                     }
  1372.                                                 }
  1373.                                             }
  1374.                                             ActivateCxObj(broker, 1l);
  1375.                                     
  1376.                                             startup->command = 0;
  1377.                                             ReplyMsg(&startup->header);
  1378.                                             goto begin_listening;
  1379.                                         }
  1380.                                         deallocate(reserve, V_status_message);
  1381.                                     }
  1382.                                     DeletePort(winport);
  1383.                                 }
  1384.                                 DeletePort(cxport);
  1385.                             }
  1386.                             DeletePort(sync);
  1387.                         }
  1388.                         DeletePort(rank);
  1389.                     }
  1390.                     CloseLibrary(CxBase);
  1391.                 }
  1392.                 CloseLibrary(GadToolsBase);
  1393.             }
  1394.             CloseLibrary((struct Library *)GfxBase);
  1395.         }
  1396.         CloseLibrary((struct Library *)IntuitionBase);
  1397.     }
  1398.     
  1399.     startup->command = SM_KILL;
  1400.     Forbid();
  1401.     ReplyMsg(&startup->header);
  1402.     return;
  1403.  
  1404. begin_listening:
  1405.     signals = (1 << myport->mp_SigBit) | (1 << cxport->mp_SigBit) | (1 << winport->mp_SigBit);
  1406.  
  1407.     while (1) {
  1408.         Wait(signals);
  1409.         
  1410.         while (cxmsg = (CxMsg *)GetMsg(cxport)) {
  1411.             msgid = CxMsgID(cxmsg);
  1412.             msgtype = CxMsgType(cxmsg);
  1413.             
  1414.             ReplyMsg((struct Message *)cxmsg);
  1415.             
  1416.             switch (msgtype) {
  1417.             case CXM_IEVENT:    /* copied from CXCMD_APPEAR below */
  1418.                 if (mainw != nil) {
  1419.                     close_main_window(mainw, IntuitionBase, GadToolsBase);
  1420.                     mainw = nil;
  1421.                     free_labels(site_labels);
  1422.                 }
  1423.                 
  1424.                 site_labels = site_list();
  1425.                 mainw = open_main_window(site_labels, IntuitionBase, GadToolsBase, GfxBase);
  1426.                 signals = (1 << cxport->mp_SigBit) |
  1427.                         (1 << myport->mp_SigBit) |
  1428.                         (1 << winport->mp_SigBit);
  1429.                 if (mainw != nil) {
  1430.                     signals |= (1 << mainw->UserPort->mp_SigBit);
  1431.                 }
  1432.                 
  1433.                 break;
  1434.             case CXM_COMMAND:
  1435.                 switch (msgid) {
  1436.                 case CXCMD_DISABLE:
  1437.                     reserve->command = SM_SUSPEND;
  1438.                     PutMsg(status_control, &reserve->header);
  1439.                     WaitPort(sync); GetMsg(sync);
  1440.                     
  1441.                     ActivateCxObj(broker, 0l);
  1442.                     break;
  1443.                 case CXCMD_ENABLE:
  1444.                     reserve->command = SM_RESUME;
  1445.                     PutMsg(status_control, &reserve->header);
  1446.                     WaitPort(sync); GetMsg(sync);
  1447.                     
  1448.                     ActivateCxObj(broker, 1l);
  1449.                     break;
  1450.                 case CXCMD_KILL:
  1451.                     reserve->command = SM_KILL;
  1452.                     PutMsg(status_control, &reserve->header);
  1453.                     WaitPort(sync); GetMsg(sync);
  1454.                     
  1455.                     break;
  1456.                 case CXCMD_APPEAR:
  1457.                     if (mainw != nil) {
  1458.                         close_main_window(mainw, IntuitionBase, GadToolsBase);
  1459.                         mainw = nil;
  1460.                         free_labels(site_labels);
  1461.                     }
  1462.                     
  1463.                     site_labels = site_list();
  1464.                     mainw = open_main_window(site_labels, IntuitionBase, GadToolsBase, GfxBase);
  1465.                     signals = (1 << cxport->mp_SigBit) |
  1466.                             (1 << myport->mp_SigBit) |
  1467.                             (1 << winport->mp_SigBit);
  1468.                     if (mainw != nil) {
  1469.                         signals |= (1 << mainw->UserPort->mp_SigBit);
  1470.                     }
  1471.                     
  1472.                     break;
  1473.                 case CXCMD_DISAPPEAR:
  1474.                     if (mainw != nil) {
  1475.                         close_main_window(mainw, IntuitionBase, GadToolsBase);
  1476.                         mainw = nil;
  1477.                         free_labels(site_labels);
  1478.                         
  1479.                         signals = (1 << cxport->mp_SigBit) |
  1480.                                 (1 << myport->mp_SigBit) |
  1481.                                 (1 << winport->mp_SigBit);
  1482.                     }
  1483.                     break;
  1484.                 }
  1485.             }
  1486.         }
  1487.         
  1488.         while (mainw && (imsg = GT_GetIMsg(mainw->UserPort))) {
  1489.             switch (imsg->Class) {
  1490.             case IDCMP_CLOSEWINDOW:
  1491.                 GT_ReplyIMsg(imsg);
  1492.                 close_main_window(mainw, IntuitionBase, GadToolsBase);
  1493.                 mainw = nil;
  1494.                 free_labels(site_labels);
  1495.                 
  1496.                 signals = (1 << cxport->mp_SigBit) |
  1497.                         (1 << myport->mp_SigBit) |
  1498.                         (1 << winport->mp_SigBit);
  1499.                 continue;
  1500.             case IDCMP_REFRESHWINDOW:
  1501.                 GT_BeginRefresh(mainw);
  1502.                 GT_EndRefresh(mainw, true);
  1503.                 break;
  1504.             case IDCMP_GADGETUP:
  1505.                 msgid = imsg->Code;
  1506.                 GT_ReplyIMsg(imsg);
  1507.                 close_main_window(mainw, IntuitionBase, GadToolsBase);
  1508.                 mainw = nil;
  1509.                 
  1510.                 n = site_labels->lh_Head;
  1511.                 while (msgid-- && (n->ln_Succ)) {
  1512.                     n = n->ln_Succ;
  1513.                 }
  1514.                 
  1515.                 if (n->ln_Succ) {
  1516.                     sp = sites;
  1517.                     while (sp) {
  1518.                         if (strcmp(sp->name, n->ln_Name) == 0) {
  1519.                             break;
  1520.                         }
  1521.                         sp = sp->next;
  1522.                     }
  1523.                     
  1524.                     if (sp) {
  1525.                         open_status_window(sp, winport, IntuitionBase, GfxBase);
  1526.                     }
  1527.                 }
  1528.                 
  1529.                 free_labels(site_labels);
  1530.                 
  1531.                 signals = (1 << cxport->mp_SigBit) |
  1532.                         (1 << myport->mp_SigBit) |
  1533.                         (1 << winport->mp_SigBit);
  1534.                 continue;
  1535.             default:
  1536.                 break;
  1537.             }
  1538.             GT_ReplyIMsg(imsg);
  1539.         }
  1540.         
  1541.         while (imsg = (struct IntuiMessage *)GetMsg(winport)) {
  1542.             sp = (site *)imsg->IDCMPWindow->UserData;
  1543.             verify(sp, V_site);
  1544.             
  1545.             switch (imsg->Class) {
  1546.             case IDCMP_CLOSEWINDOW:
  1547.                 ReplyMsg((struct Message *)imsg);
  1548.                 close_status_window(sp, winport, IntuitionBase);
  1549.                 continue;
  1550.             case IDCMP_GADGETUP:
  1551.                 if (((struct Gadget *)imsg->IAddress)->GadgetID == 1) {
  1552.                     /* abort */
  1553.                     Signal(sp->port->mp_SigTask, sp->abort_signals);
  1554.                 } else {
  1555.                     /* disconnect */
  1556.                     Signal(sp->port->mp_SigTask, sp->disconnect_signals);
  1557.                 }
  1558.                 break;
  1559.             }
  1560.         
  1561.             ReplyMsg((struct Message *)imsg);
  1562.         }
  1563.         
  1564.         while (sm = (status_message *)GetMsg(myport)) {
  1565.             verify(sm, V_status_message);
  1566.             
  1567.             switch (sm->command) {
  1568.             case SM_KILL:
  1569.                 if (mainw != nil) {
  1570.                     close_main_window(mainw, IntuitionBase, GadToolsBase);
  1571.                     free_labels(site_labels);
  1572.                 }
  1573.                 
  1574.                 Forbid();
  1575.                 while (cxmsg = (CxMsg *)GetMsg(cxport)) {
  1576.                     ReplyMsg((struct Message *)cxmsg);
  1577.                 }
  1578.                 
  1579.                 DeleteCxObjAll(broker);
  1580.                 Permit();
  1581.                 
  1582.                 deallocate(reserve, V_status_message);
  1583.                 
  1584.                 DeletePort(winport);
  1585.                 DeletePort(cxport);
  1586.                 DeletePort(sync);
  1587.                 DeletePort(rank);
  1588.                 
  1589.                 check_memory();
  1590.  
  1591.                 CloseLibrary(CxBase);
  1592.                 CloseLibrary(GadToolsBase);
  1593.                 CloseLibrary((struct Library *)GfxBase);
  1594.                 CloseLibrary((struct Library *)IntuitionBase);
  1595.                 
  1596.                 Forbid();
  1597.                 ReplyMsg(&sm->header);
  1598.                 return;
  1599.             case SM_NEW_SITE:
  1600.                 if (sm->data) {
  1601.                     open_status_window(sm->this_site, winport, IntuitionBase, GfxBase);
  1602.                 }
  1603.                 break;
  1604.             case SM_DEAD_SITE:
  1605.                 close_status_window(sm->this_site, winport, IntuitionBase);
  1606.                 break;
  1607.             case SM_STATE_CHANGE:
  1608.                 if (sm->this_site->status_window) {
  1609.                     clear_state(sm->this_site, IntuitionBase, GfxBase);
  1610.                     draw_state(sm->this_site, IntuitionBase, GfxBase);
  1611.                 }
  1612.                 break;
  1613.             case SM_PROGRESS:
  1614.                 if (sm->this_site->status_window) {
  1615.                     update_fill_bar(sm->this_site, IntuitionBase, GfxBase);
  1616.                 }
  1617.                 break;
  1618.             }
  1619.             ReplyMsg(&sm->header);
  1620.         }
  1621.     }
  1622. }
  1623.  
  1624.