home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / clintsrc.sit / DAdialog.c < prev    next >
Text File  |  1990-05-04  |  28KB  |  1,232 lines

  1. /*========================================================================
  2. ===  DAdialog.c
  3. ===
  4. ===  Greg Anderson
  5. ===  29 Kerr Hall
  6. ===  Social Sciences Computing
  7. ===  University of California at Santa Cruz
  8. ===  Santa Cruz CA  95062
  9. ===
  10. ===  (408) 459-2658
  11. ===  sirkm@ssyx.ucsc.edu
  12. ===
  13. ===  Dialog box routines.
  14. ===
  15. ========================================================================*/
  16. #include    <types.h>
  17. #include    <osutils.h>
  18. #include    <memory.h>
  19. #include    <devices.h>
  20. #include    <events.h>
  21. #include    <quickdraw.h>
  22. #include    <fonts.h>
  23. #include    <windows.h>
  24. #include    <files.h>
  25. #include    <errors.h>
  26. #include    <toolutils.h>
  27. #include    <packages.h>
  28.  
  29. #include    <Limits.h>
  30. #include    <Controls.h>
  31. #include    <TextEdit.h>
  32. #include    <Dialogs.h>
  33. #include    <Desk.h>
  34. #include    <Scrap.h>
  35. #include    <Traps.h>
  36. #include    <Lists.h>
  37. #include    <Menus.h>
  38. #include    <Resources.h>
  39.  
  40. #include    "unixDA.h"
  41. #include    "DA.h"
  42.  
  43. /*----------------------------------------------------------------------
  44. |  Draw a shaded rectangle.  The shaded part hangs outside the
  45. |  rectangle by one pixel below and to the right.
  46. ----------------------------------------------------------------------*/
  47. ShadedRect( Rect *theRect )
  48. {
  49.     PenNormal();
  50.     EraseRect( theRect );
  51.     FrameRect( theRect );
  52.     
  53.     MoveTo( theRect->left+2,    theRect->bottom );
  54.     LineTo( theRect->right,        theRect->bottom );
  55.     LineTo( theRect->right,        theRect->top+2 );
  56. }
  57.  
  58. /*----------------------------------------------------------------------
  59. |  Draw the thick rounded rectangle around the default button
  60. ----------------------------------------------------------------------*/
  61. drawDefault(dialog)
  62.     DialogPtr        dialog;
  63. {
  64.     short            type;
  65.     Handle            item;
  66.     Rect            box;
  67.     
  68.     SetPort(dialog);
  69.     GetDItem(dialog, 1, &type, &item, &box);
  70.     PenSize(3,3);
  71.     InsetRect(&box,-4,-4);
  72.     FrameRoundRect(&box,18,18);
  73. }
  74.  
  75. /*----------------------------------------------------------------------
  76. |  Draw the pop-up menu icon
  77. ----------------------------------------------------------------------*/
  78. pascal void drawPopIcon(DialogPtr dlog,short whichItem)
  79. {
  80.     DCtlPtr            dCtl;
  81.     Handle            item;
  82.     short            type;
  83.     Rect            box;
  84.     Str255            Pstr;
  85.     int                x;
  86.     
  87.     dCtl = (DCtlPtr)GetWRefCon(dlog);
  88.     GetDItem(dlog,whichItem,&type,&item,&box);
  89.     ShadedRect(&box);
  90.     GetIndString(Pstr, DA_global->rsrcID, ePopMsg);
  91.     x = ( (box.right - box.left) - StringWidth(Pstr) ) / 2;
  92.     MoveTo( box.left + x , box.top+12 );
  93.     DrawString(Pstr);
  94. }
  95.  
  96. /*----------------------------------------------------------------------
  97. |  Draw the scrolling item list
  98. ----------------------------------------------------------------------*/
  99. pascal void drawItemList(DialogPtr dlog,short whichItem)
  100. {
  101.     DCtlPtr            dCtl;
  102.     short            type;
  103.     Handle            item;
  104.     Rect            box;
  105.     
  106.     dCtl = (DCtlPtr)GetWRefCon(dlog);
  107.     GetDItem(dlog,whichItem,&type,&item,&box);
  108.     ShadedRect(&box);
  109.     LUpdate( ((*DA_iList)->port)->visRgn,DA_iList);
  110. }
  111.  
  112. /*----------------------------------------------------------------------
  113. |  Center the dialog box
  114. ----------------------------------------------------------------------*/
  115. centerDialog(param)
  116.     DialogPtr        param;
  117. {
  118.     Rect            scrRect;
  119.     int                w,h,x,y;
  120.     
  121.     w = param->portRect.right - param->portRect.left;
  122.     h = param->portRect.bottom - param->portRect.top;
  123.     getScreenRect(&scrRect);
  124.     x = (scrRect.right/2) - (w/2);
  125.     y = ( (scrRect.bottom - 16 - h)/2) + 16;
  126.     if( y < 16 ) y = 16;
  127.     MoveWindow(param,x,y,false);
  128. }
  129.  
  130. /*----------------------------------------------------------------------
  131. |  Set the item handle of a dialog item (particularly useritems
  132. ----------------------------------------------------------------------*/
  133. void setItemHandle(DialogPtr dlog, short whichItem, Handle newItem)
  134. {
  135.     short            type;
  136.     Handle            item;
  137.     Rect            box;
  138.     
  139.     GetDItem(dlog,whichItem,&type,&item,&box);
  140.     SetDItem(dlog,whichItem,type,newItem,&box);
  141. }
  142.  
  143. /*----------------------------------------------------------------------
  144. |  Put up an alert with some arbitrary message
  145. ----------------------------------------------------------------------*/
  146. void alertMsg( DCtlPtr dCtl, char *msg )
  147. {
  148.     Str255        Pmsg;
  149.     short        itemHit;
  150.     
  151.     C2Pstr(Pmsg,msg);
  152.     ParamText(Pmsg, Pmsg, Pmsg, Pmsg);
  153.     itemHit = Alert(DA_global->rsrcID, nil);
  154. }
  155.  
  156. /*----------------------------------------------------------------------
  157. |  Display an alert that tells the user an error occurred. The error
  158. |  number is used to index an 'STR#' resource so that a relevant
  159. |  message can be displayed.
  160. ----------------------------------------------------------------------*/
  161. void alertUser2( DCtlPtr dCtl, short error1, short error2 )
  162. {
  163.     short        itemHit;
  164.     Str255        msg1,
  165.                 msg2;
  166.  
  167.     if( DA_global->flag == NOERRORMAGIC ) return;
  168.     
  169.     /* SetCursor(&qd.arrow); */
  170.     InitCursor();
  171.     /*
  172.      *  The type 'Str255' is an array in MPW 3
  173.      */
  174.     GetIndString(msg2, DA_global->rsrcID, error2);
  175.     GetIndString(msg1, DA_global->rsrcID, error1);
  176.     ParamText(msg1, msg2, msg1, msg2);
  177.     itemHit = Alert(DA_global->rsrcID, nil);
  178. }
  179.  
  180. /*----------------------------------------------------------------------
  181. |  Like alertUser2, but has only one error message.
  182. ----------------------------------------------------------------------*/
  183. void alertUser( DCtlPtr dCtl, short error )
  184. {
  185.     alertUser2( dCtl, error, eNulString );
  186. }
  187.  
  188. /*----------------------------------------------------------------------
  189. |  Display the HELP dialog box.
  190. ----------------------------------------------------------------------*/
  191. void helpDialog( DCtlPtr dCtl )
  192. {
  193.     DialogPtr    dlog;
  194.     short        itemHit;
  195.     Str255        Pstr;
  196.     
  197.     /*
  198.      * Set up the dialog box
  199.      */
  200.     dlog = GetNewDialog(DA_global->rsrcID + 2, nil, (WindowPtr)-1L);
  201.     SetWRefCon(dlog,(long)dCtl);
  202.     setItemHandle(dlog,9,(Handle)drawPopIcon);
  203.     SetPort(dlog);
  204.     centerDialog(dlog);
  205.     ShowWindow(dlog);
  206.     SelectWindow(dlog);
  207.     DrawDialog(dlog);
  208.     drawDefault(dlog);
  209.     
  210.     do
  211.     {
  212.         ModalDialog( nil, &itemHit);
  213.         if( itemHit == 9 )
  214.             doPopup( dCtl, dlog, itemHit, Pstr );
  215.     } while( itemHit != 1 );
  216.     DisposDialog(dlog);
  217. }
  218.  
  219. /*----------------------------------------------------------------------
  220. |  A short delay used when flashing stuff
  221. ----------------------------------------------------------------------*/
  222. shortPause()
  223. {
  224.     long    ticky;
  225.  
  226.     ticky = TickCount() + 10;
  227.     while( ticky > TickCount() );
  228. }
  229.  
  230. /*----------------------------------------------------------------------
  231. |  Momentarily hilite a dialog button
  232. ----------------------------------------------------------------------*/
  233. FlashDlogItem( DialogPtr dlog, short itemNum )
  234. {
  235.     Handle        item;
  236.     short        itemType;
  237.     Rect        iRect;
  238.     
  239.     GetDItem(dlog,itemNum,&itemType,&item,&iRect);
  240.     InsetRect(&iRect,1,1);
  241.     InvertRoundRect( &iRect, 8, 8 );
  242.     shortPause();
  243.     InvertRoundRect( &iRect, 8, 8 );
  244. }
  245.  
  246. /*
  247.  *  A list of events returned by the filter:
  248.  */
  249. #define fUndo        1000
  250. #define fCut        1001
  251. #define fCopy        1002
  252. #define fPaste        1003
  253. #define fClear        1004
  254. #define fSelAll        1005
  255.  
  256. #define fUpArrow    1010
  257. #define fDownArrow    1011
  258. #define fHome        1012
  259. #define fEnd        1013
  260. #define fPgUp        1014
  261. #define fPgDown        1015
  262.  
  263. /*----------------------------------------------------------------------
  264. |  This filter, when passed to ModalDialog, will allow the user to
  265. |  cut, copy and paste by pressing command-X, command-C or command-V,
  266. |  respectively.
  267. ----------------------------------------------------------------------*/
  268. pascal Boolean cutPasteFilter( DialogPtr dlog, EventRecord *theEvent, short *itemHit )
  269. {
  270.     Str255        Pstr;
  271.     long        num;
  272.     char        key,
  273.                 code;
  274.     short        itemType,
  275.                 itemNum;
  276.     Handle        item;
  277.     Point        mouse;
  278.     Rect        tRect;
  279.     
  280.     /*
  281.      *  Adjust the cursor to an iBeam or Arrow as appropriate
  282.      */    
  283.     GetMouse( &mouse );
  284.     itemNum = FindDItem(dlog,mouse) + 1;
  285.     itemType = statText;
  286.     if( itemNum > 0 )
  287.         GetDItem(dlog,itemNum,&itemType,&item,&tRect);
  288.     if( itemType == editText )
  289.         SetCursor(*GetCursor(iBeamCursor));
  290.     else
  291.         InitCursor();
  292.     
  293.     /*
  294.      *  We only wish to filter keyDown events.
  295.      */
  296.     if( (theEvent->what == keyDown) || (theEvent->what == autoKey) )
  297.     {
  298.         key  = (theEvent->message & charCodeMask);
  299.         code = (theEvent->message &  keyCodeMask) >> 8;
  300.  
  301.         if( theEvent->modifiers & optionKey )
  302.         {
  303.             num = code;
  304.             NumToString(num, Pstr);
  305.             GetDItem(dlog,11,&itemType,&item,&tRect);
  306.             SetIText(item,Pstr);
  307.  
  308.             theEvent->what = nullEvent;
  309.             return(false);        
  310.         }
  311.         /*
  312.          *  If ESCAPE was pressed, forge a command-. and continue
  313.          *  (Note that CLEAR <code 71> also sends an ESCAPE, which isn't what
  314.          *   we want)
  315.          */
  316.         if( (key == 27) && (code != 71) )
  317.         {
  318.             theEvent->modifiers |= cmdKey;
  319.             key = '.';
  320.         }
  321.         /*
  322.          *  If F1, F2, F3 or F4 (undo, cut, copy or paste) are pressed, exit
  323.          *  with the appropriate result code.
  324.          */
  325.         switch( code )
  326.         {
  327.         case 122:    
  328.                     *itemHit = fUndo;
  329.                     return(true);
  330.         case 120:    
  331.                     *itemHit = fCut;
  332.                     return(true);
  333.         case  99:    
  334.                     *itemHit = fCopy;
  335.                     return(true);
  336.         case 118:    
  337.                     *itemHit = fPaste;
  338.                     return(true);
  339.         case 126:    
  340.                     *itemHit = fUpArrow;
  341.                     return(true);
  342.         case 125:    
  343.                     *itemHit = fDownArrow;
  344.                     return(true);
  345.         case 115:    
  346.                     *itemHit = fHome;
  347.                     return(true);
  348.         case 119:    
  349.                     *itemHit = fEnd;
  350.                     return(true);
  351.         case 116:    
  352.                     *itemHit = fPgUp;
  353.                     return(true);
  354.         case 121:    
  355.                     *itemHit = fPgDown;
  356.                     return(true);
  357.         case 114:    
  358.                     *itemHit = 5;
  359.                     FlashDlogItem( dlog, 5 );
  360.                     return(true);
  361.  
  362.         default:
  363.                     break;
  364.                     GetDItem(dlog,11,&itemType,&item,&tRect);
  365.                     NumToString((long)code, Pstr);
  366.                     SetIText(item,Pstr);
  367.         
  368.         }
  369.         /*
  370.          *  Is the command key down?
  371.          */
  372.         if( theEvent->modifiers & cmdKey )
  373.         {
  374.             switch( key )
  375.             {
  376.             case 'x':    *itemHit = fCut;
  377.                         return(true);                        
  378.             case 'c':    *itemHit = fCopy;
  379.                         return(true);                        
  380.             case 'v':    *itemHit = fPaste;
  381.                         return(true);                        
  382.             case 'z':    *itemHit = fUndo;
  383.                         return(true);
  384.             case 'a':    *itemHit = fSelAll;
  385.                         return(true);
  386.             case '.':    *itemHit = 2;
  387.                         FlashDlogItem( dlog, 2 );
  388.                         return(true);
  389.             }
  390.             theEvent->what = nullEvent;
  391.             return(false);
  392.         }
  393.         /*
  394.          *  If CLEAR was pressed, return fClear
  395.          */
  396.         if( code == 71 )
  397.         {
  398.             *itemHit = fClear;
  399.             return(true);
  400.         }
  401.         /*
  402.          *  If RETURN or ENTER was pressed, exit with itemHit = 1.
  403.          */
  404.         if( (key == 13) || (key == 3) )
  405.         {
  406.             *itemHit = 1;
  407.             FlashDlogItem( dlog, 1 );
  408.             return(true);
  409.         }
  410.         /*
  411.          *  Swallow non-printing characters
  412.          */
  413.         if( (key < ' ') && (key != 8) && (key != 9) )
  414.         {
  415.             theEvent->what = nullEvent;
  416.             return(false);
  417.         }
  418.     }
  419.     return(false);
  420. }
  421.  
  422. /*----------------------------------------------------------------------
  423. |  Dialog box Special functions
  424. ----------------------------------------------------------------------*/
  425. void specialDlog(DCtlPtr dCtl, DialogPtr dlog, int what)
  426. {
  427.     DialogRecord    *dp = dlog;
  428.     TEHandle        te;
  429.     Cell            selectionCell;
  430.     int                i;
  431.     
  432.     te = dp->textH;
  433.     
  434.     switch( what )
  435.     {
  436.     case fCut:
  437.     case fCopy:
  438.                 /*
  439.                  *  If there is no selection, do nothing
  440.                  */
  441.                 if( (*te)->selEnd != (*te)->selStart )
  442.                 {
  443.                     HiliteEditMenu();
  444.                     ZeroScrap();
  445.                     if(what == fCut)
  446.                         DlgCut( dlog );
  447.                     else
  448.                         DlgCopy( dlog );
  449.                     if( TEToScrap() != noErr )
  450.                         SysBeep(0);
  451.                     shortPause();
  452.                     HiliteMenu(0);
  453.                 }
  454.                 break;
  455.                                 
  456.     case fPaste:
  457.                 HiliteEditMenu();
  458.                 if( TEFromScrap() == noErr )
  459.                     DlgPaste( dlog );
  460.                 else
  461.                     SysBeep(0);
  462.                 shortPause();
  463.                 HiliteMenu(0);
  464.                 break;
  465.     
  466.     case fClear:
  467.                 if( (*te)->selEnd != (*te)->selStart )
  468.                     DlgDelete( dlog );
  469.                 break;
  470.     
  471.     case fSelAll:
  472.                 TESetSelect(0,kMaxTELength,te);
  473.                 break;
  474.     case fUndo:
  475.                 break;
  476.                 
  477.     case fUpArrow:
  478.     case fDownArrow:
  479.     case fPgUp:
  480.     case fPgDown:
  481.     case fHome:
  482.     case fEnd:
  483.                 selectionCell.h = 0; selectionCell.v = 0;
  484.                 if( LGetSelect(true, &selectionCell, DA_iList) )
  485.                 {
  486.                     LSetSelect(false,selectionCell,DA_iList);
  487.                     i = (*(DA_iList))->dataBounds.bottom;
  488.                     selectionCell.v +=    (what == fDownArrow)
  489.                                     -    (what == fUpArrow)
  490.                                     -    (what == fPgUp) * 10
  491.                                     +    (what == fPgDown) * 10;
  492.                     if(what == fHome) selectionCell.v = 0;
  493.                     if(what == fEnd)  selectionCell.v = i-1;
  494.                     if(selectionCell.v < 0) selectionCell.v = 0;
  495.                     if(selectionCell.v >=i) selectionCell.v = i-1;
  496.                 }
  497.                 LSetSelect(true,selectionCell,DA_iList);
  498.                 LAutoScroll(DA_iList);
  499.                 break;
  500.     }
  501. }
  502.  
  503. /*----------------------------------------------------------------------
  504. |  Put up the 'SelectService' dialog box and wait for the user to
  505. |  select the service desired.
  506. |
  507. |  Returns 'true' if the user clicks 'Okay' and 'false' if the user
  508. |  clicks 'Cancel'.
  509. ----------------------------------------------------------------------*/
  510. short selectService( DCtlPtr dCtl, long *inet_addr, char *result )
  511. {
  512.     DialogPtr    dlog;
  513.     Handle        tmpHandle,
  514.                 hostHandle;
  515.     Point        cSize,
  516.                 clickAt;
  517.     Str255        Pstr,
  518.                 lastHost,
  519.                 params;
  520.     short        itemHit,
  521.                 lastHit = 0,
  522.                 itemType,
  523.                 len;
  524.     Cell        selectionCell;
  525.     Rect        tRect,
  526.                 rView,
  527.                 dataBounds;
  528.     int            i;
  529.     
  530.     *result = 0;
  531.     HiliteMenu(0);
  532.     /*
  533.      * Set up the dialog box
  534.      */
  535.     dlog = GetNewDialog(DA_global->rsrcID, nil, (WindowPtr)-1L);
  536.     SetPort(dlog);
  537.     centerDialog(dlog);
  538.     SetWRefCon(dlog,(long)dCtl);
  539.     setItemHandle(dlog,9,(Handle)drawItemList);
  540.     setItemHandle(dlog,12,(Handle)drawPopIcon);
  541.     /*
  542.      *  Get the name of the host and set the editable text field in the dialog
  543.      */
  544.     hostHandle = GetResource('STR ',DA_global->rsrcID );
  545.     pstrcpy(Pstr,*hostHandle);
  546.     GetDItem(dlog,7,&itemType,&tmpHandle,&tRect);
  547.     SetIText(tmpHandle,Pstr);
  548.     
  549.     do
  550.     {
  551.         GetDItem(dlog,7,&itemType,&tmpHandle,&tRect);
  552.         GetIText(tmpHandle,&lastHost);
  553.         /*
  554.          * Set up the item list:  rView should be the same size as dialog item #9.
  555.          */
  556.         GetDItem(dlog,9,&itemType,&tmpHandle,&rView);
  557.         InsetRect(&rView,1,1);
  558.         rView.right -= 15;
  559.         SetRect(&dataBounds,0,0,1,0);
  560.         cSize.h = 0; cSize.v = 0;
  561.         DA_iList = LNew(&rView,&dataBounds,cSize,(short)0,dlog,true,false,false,true);
  562.         lastHit = 0;
  563.         /*
  564.          *  Now show the dialog box & draw a rectangle around the item list
  565.          */
  566.         ShowWindow(dlog);
  567.         SelectWindow(dlog);
  568.         DrawDialog(dlog);
  569.         drawDefault(dlog);
  570.         
  571.         /*
  572.          *  Find all services offered & add them to the scrolling item list.
  573.          */
  574.         SetCursor( *GetCursor( watchCursor) );
  575.         setupList(dCtl, dlog, inet_addr);
  576.         LUpdate( ((*DA_iList)->port)->visRgn,DA_iList);
  577.         InitCursor();
  578.         selectionCell.h = 0; selectionCell.v = DA_global->lastService;
  579.         LSetSelect(true,selectionCell,DA_iList);
  580.         LAutoScroll(DA_iList);
  581.         
  582.         do
  583.         {
  584.             ModalDialog( (ModalFilterProcPtr)cutPasteFilter, &itemHit);
  585.             /* ModalDialog( nil, &itemHit); */
  586.             /*
  587.              *  If itemHit >= 1000, then do special handling stuff
  588.              */
  589.             if( itemHit >= 1000 )
  590.                 specialDlog(dCtl, dlog, itemHit );
  591.  
  592.             /*
  593.              *  Did user click the question mark button?
  594.              */
  595.             if( itemHit == 5 )
  596.             {
  597.                 helpDialog( dCtl );
  598.                 SelectWindow(dlog);
  599.                 SetPort(dlog);
  600.                 DrawDialog(dlog);
  601.                 drawDefault(dlog);
  602.             }
  603.             /*
  604.              *  Did user click the popup menu marker?
  605.              */
  606.             if( itemHit == 12 )
  607.             {
  608.                 /*
  609.                 GetDItem(dlog,12,&itemType,&tmpHandle,&tRect);
  610.                 tRect.bottom += 160;
  611.                 tRect.right  += 160;
  612.                 */
  613.                 i = doPopup( dCtl, dlog, itemHit, Pstr );
  614.                 /*
  615.                 udRegion = NewRgn();
  616.                 RectRgn(udRegion,&tRect);
  617.                 UpdtDialog(dlog,udRegion);
  618.                 drawDefault(dlog);
  619.                 DisposeRgn(udRegion);
  620.                 */
  621.                 
  622.                 if( i > -1 )
  623.                 {
  624.                     GetDItem(dlog,7,&itemType,&tmpHandle,&tRect);
  625.                     SetIText(tmpHandle,Pstr);
  626.                     itemHit = -1;
  627.                 }
  628.             }
  629.             GetDItem(dlog,7,&itemType,&tmpHandle,&tRect);
  630.             GetIText(tmpHandle,&Pstr);
  631.             /*
  632.              *  Did the user change the host name field and then move the
  633.              *  cursor to the 'Parameters' field?
  634.              */
  635.             if( ( (itemHit == 3) || (itemHit == 9) ) && pstrcmp(Pstr,lastHost) )
  636.                 itemHit = -1;
  637.             /*
  638.              *  Check for a double-click on the item list
  639.              */
  640.             if( itemHit == 9 )
  641.             {
  642.                 GetMouse(&clickAt);
  643.                 if( LClick(clickAt,0,DA_iList) )
  644.                 {
  645.                     FlashDlogItem( dlog, 1 );
  646.                     itemHit = 1;
  647.                 }
  648.             }
  649.             /*
  650.              *  If the host name field was touched & the user hit "Okay",
  651.              *  re-read the service list
  652.              */
  653.             if( (itemHit == 1) && pstrcmp( Pstr, lastHost ) )
  654.                 itemHit = -1;
  655.             /*
  656.              *  Requested a new item list?  Ignore if hostname has not changed
  657.              */
  658.             if( itemHit == -1 )
  659.             {
  660.                 if( pstrcmp( Pstr,lastHost ) )
  661.                 {
  662.                     DA_global->lastService = 0;
  663.                     LDispose(DA_iList);
  664.                 }
  665.                 else
  666.                     itemHit = 9999;
  667.             }
  668.         } while( itemHit > 2 );
  669.     } while( itemHit < 0 );
  670.     
  671.     selectionCell.h = 0; selectionCell.v = 0;
  672.     if( LGetSelect(true, &selectionCell, DA_iList) )
  673.     {
  674.         /*
  675.         | |  Get the selection
  676.          */
  677.         DA_global->lastService = selectionCell.v;
  678.         len = 79;
  679.         LGetCell(result,&len,selectionCell,DA_iList);
  680.         result[len++] = '\r';
  681.         /*
  682.          *  If it is ever deemed necessary:  insert username here
  683.          */
  684.         result[len++] = '\r';
  685.         result[len] = 0;
  686.         /*
  687.         | |  Get the text from the 'parameters' field
  688.          */
  689.         GetDItem(dlog,3,&itemType,&tmpHandle,&rView);
  690.         GetIText(tmpHandle,¶ms);
  691.         processParams( (char *)params, result+len );
  692.     }
  693.     
  694.     LDispose(DA_iList);
  695.     DisposDialog(dlog);
  696.  
  697.     if( itemHit == 2 )
  698.         CloseDeskAcc( dCtl->dCtlRefNum );
  699.  
  700.     return( itemHit == 1 );
  701. } /* SelectService */
  702.  
  703. /*----------------------------------------------------------------------
  704. |  Set up the list of services offered.
  705. ----------------------------------------------------------------------*/
  706. void setupList(DCtlPtr dCtl, DialogPtr dlog, long *inet_addr)
  707. {
  708.     #define        SBSIZE        1000
  709.     
  710.     Handle        item,
  711.                 knownHosts,
  712.                 hostHandle;
  713.     Str255        Pstr;
  714.     OSErr        err        = noErr;
  715.     short        m,
  716.                 itemType;
  717.     Rect        tRect;
  718.     Cell        theCell;
  719.     char        serviceBuf[SBSIZE+4],
  720.                 msg[80],
  721.                 *serv,
  722.                 *line,
  723.                 hostName[255],
  724.                 dot_addr[40];
  725.     int            i,
  726.                 j,
  727.                 tries = 0;
  728.  
  729.     DA_global->flag = NOERRORMAGIC;
  730.     /*
  731.      *  Get the name of the host:
  732.      */
  733.     GetDItem(dlog,7,&itemType,&item,&tRect);
  734.     GetIText(item,&Pstr);
  735.     P2Cstr(hostName,Pstr);
  736.     /*
  737.      *  Set the error message text field to the 'looking up inetadr' message
  738.      *  and clear the internet address field
  739.      */
  740.     GetIndString(Pstr,DA_global->rsrcID, eNoServ-1 );
  741.     GetDItem(dlog,11,&itemType,&item,&tRect);
  742.     SetIText(item,Pstr);
  743.     *Pstr = 0;
  744.     GetDItem(dlog,8,&itemType,&item,&tRect);
  745.     SetIText(item,Pstr);
  746.     /*
  747.      *  Put the name of the host & its inet address into the
  748.      *  appropriate dialog fields
  749.      */
  750.     C2Pstr(Pstr,hostName);
  751.     GetDItem(dlog,7,&itemType,&item,&tRect);
  752.     SetIText(item,Pstr);
  753.     /*
  754.      *  Look up the internet address of the host
  755.      */
  756.     knownHosts = GetResource('STR#',DA_global->rsrcID+1 );
  757.     HLock(knownHosts);
  758.     checkHostCache( *knownHosts, hostName, inet_addr );
  759.     HUnlock(knownHosts);
  760.     if( !(*inet_addr) )
  761.         err = NameToAddr(hostName,inet_addr,0L);
  762.     
  763.     myAddrToStr(*inet_addr,dot_addr);
  764.     C2Pstr(Pstr,dot_addr);
  765.     GetDItem(dlog,8,&itemType,&item,&tRect);
  766.     SetIText(item,Pstr);
  767.  
  768.     /*
  769.      *  Set the error message text field to the 'reading service list' message
  770.      */
  771.     GetIndString(Pstr,DA_global->rsrcID, eNoServ+1 );
  772.     if( !(*inet_addr) ) *Pstr = 0;
  773.     GetDItem(dlog,11,&itemType,&item,&tRect);
  774.     SetIText(item,Pstr);
  775.  
  776.     if( !(*inet_addr) ) return;
  777.  
  778.     do
  779.     {
  780.         i=0;
  781.         ++tries;
  782.         /*
  783.          *  Ask the superserver for a list of services
  784.          */
  785.         getCstr(eList,msg,DA_global);
  786.         if( (err = MakeTCPStream( dCtl )) != noErr)
  787.             continue;
  788.         
  789.         if( (err = ActiveOpen( dCtl, *inet_addr, 3502 )) != noErr )
  790.         {
  791.             KillTCPStream( dCtl );
  792.             continue;
  793.         }
  794.  
  795.         /*
  796.          *  Send the 'LIST' command & read back the response.
  797.          */
  798.         if( (err = SendTCP( dCtl, msg )) == noErr )
  799.             err = GetUntilClosed( dCtl, serviceBuf, SBSIZE );
  800.         KillTCPStream( dCtl );
  801.  
  802.         LDoDraw(false,DA_iList);
  803.         theCell.h = 0;
  804.         serv = serviceBuf;
  805.         findNextLine(&serv);
  806.         findNextLine(&serv);
  807.         findNextLine(&serv);
  808.         /*
  809.          *  Add all of the service names to the item list
  810.          */
  811.         while(*serv)
  812.         {
  813.             /*
  814.              *  Find the next service name
  815.              */
  816.             line = serv;
  817.             findNextLine(&serv);
  818.             while( (*line) && (*line != '\t') ) ++line;
  819.             if( *line ) line++;
  820.             if( !(*line) ) continue;
  821.             /*
  822.              *  Put it into the list in alphabetical order
  823.              */
  824.             for(j=0;j<i;++j)
  825.             {
  826.                 m = 80;
  827.                 theCell.v = j;
  828.                 LGetCell(msg,&m,theCell,DA_iList);
  829.                 msg[m] = 0;
  830.                 if( cistrcmp(msg,line) > 0 )
  831.                     break;
  832.             }
  833.             theCell.v = j;
  834.             LAddRow(1,j,DA_iList);
  835.             LAddToCell(line,strlen(line),theCell,DA_iList);
  836.             ++i;
  837.         }
  838.         LDoDraw(true,DA_iList);
  839.     } while( (i==0) && (tries<2) );
  840.     
  841.     /*
  842.      *  If no services were added, put up an error message
  843.      */
  844.     m = getTCPErrorStr(err);
  845.     if( (m == eBadOpen) || (err == noErr) )
  846.     {
  847.         getCstr(eNoServ,msg,DA_global);
  848.         strcat(msg,hostName);
  849.         C2Pstr(Pstr,msg);
  850.     }
  851.     else
  852.         GetIndString(Pstr, DA_global->rsrcID, m );
  853.     
  854.     if( i ) *Pstr = 0;
  855.     GetDItem(dlog,11,&itemType,&item,&tRect);
  856.     SetIText(item,Pstr);
  857.     /*
  858.      *  If services are offered here, remember the name of the host
  859.      *  for use in subsiquent lookups.
  860.      */
  861.     if( i )
  862.     {
  863.         addHostToCache( dCtl, hostName, dot_addr, dlog );
  864.         
  865.         hostHandle = GetResource('STR ',DA_global->rsrcID );
  866.         ReallocHandle(hostHandle,lstrlen(hostName)+2);
  867.         C2Pstr(*hostHandle,hostName);
  868.         ChangedResource(hostHandle);
  869.         WriteResource(hostHandle);
  870.     }
  871.     DA_global->flag = 0;
  872. }
  873.  
  874. /*----------------------------------------------------------------------
  875. |  Search the cache & see if the inet_addr of this host is known
  876. ----------------------------------------------------------------------*/
  877. char *checkHostCache( char *walk, char *hostName, long *inet_addr )
  878. {
  879.     char    c,
  880.             *begin;
  881.     int        i,
  882.             starting = 1,
  883.             hLen;
  884.     
  885.     hLen = strlen(hostName);
  886.     *inet_addr = 0;
  887.     /*
  888.      *  Check if the host is in inet addr cache list
  889.      */
  890.     walk += 2;
  891.     while( *walk )
  892.     {
  893.         if( starting )
  894.             begin = walk;
  895.         ++walk;
  896.         /*
  897.          *  Only do a string compare if the target string is the
  898.          *  right length
  899.          */
  900.         if( ((c = walk[hLen]) == '=') || (c == ',') || (c == '.') || (c == '\n') )
  901.         {
  902.             walk[hLen] = 0;
  903.             i = strcmp(walk,hostName);
  904.             walk[hLen] = c;
  905.             /*
  906.              *  Did we find a match?
  907.              */
  908.             if( !i )
  909.             {
  910.                 if( c == '\n')
  911.                     --walk;
  912.                 else
  913.                     while( (*walk) && (*walk != '=') )
  914.                         ++walk;
  915.                 if( *walk )
  916.                     myStrToAddr(walk + 1,inet_addr);
  917.                 return(begin);
  918.             }
  919.         }
  920.         while( (*walk >= ' ') && (*walk != ',') && (*walk != '=') )
  921.             ++walk;
  922.         starting = (*walk < ' ');
  923.         if( starting && *walk ) ++walk;
  924.     }
  925.     return( nil );
  926. }
  927.  
  928. /*----------------------------------------------------------------------
  929. |  Add a host name & its internet address to the cache
  930. ----------------------------------------------------------------------*/
  931. void addHostToCache( DCtlPtr dCtl, char *hostName, char *dotAddr, DialogPtr dlog)
  932. {
  933.     Handle    knownHosts,
  934.             newCache;
  935.     unsigned char pLen;
  936.     char    hostEntry[256],
  937.             *walk,
  938.             *build,
  939.             *inCache;
  940.     long    inet_addr,
  941.             tLen;
  942.     short    tLines = 0,
  943.             *lPeek;
  944.     int        i,
  945.             j = 0,
  946.             hLen;
  947.     
  948.     hLen = strlen(hostName);
  949.     knownHosts = GetResource('STR#',DA_global->rsrcID+1 );
  950.     newCache = NewHandle( GetHandleSize(knownHosts) + 256L );
  951.     MoveHHi(newCache);
  952.     HLock(newCache);
  953.     HLock(knownHosts);
  954.     /*
  955.      *  First we want to know if the host is already in the cache.
  956.      */
  957.     inCache = checkHostCache( *knownHosts, dotAddr, &inet_addr );
  958.     
  959.     lPeek = (short *)*newCache;
  960.     build = *newCache + 2;
  961.     walk = *knownHosts + 2;
  962.     
  963.     strcpy(hostEntry,hostName);
  964.     straddc(hostEntry,'=');
  965.     strcat(hostEntry,dotAddr);
  966.     straddc(hostEntry,'\n');
  967.     /*
  968.      *  Copy the new host name entry into the cache
  969.      */
  970.     C2Pstr( build, hostEntry );
  971.     tLen = lstrlen(hostEntry)+1;
  972.     build += tLen;
  973.     /*
  974.      *  Copy the rest of the old cache to the new cache
  975.      */
  976.     while( (*walk) && (tLines < 8) )
  977.     {
  978.         ++j;
  979.         
  980.         pLen = pstrlen(walk) + 1;
  981.         if( (StripAddress(walk) == StripAddress(inCache)) )
  982.             walk += pLen;
  983.         else
  984.         {
  985.             ++tLines;
  986.             tLen += pLen;
  987.             for(i=0;i<pLen;++i)
  988.                 *build++ = *walk++;
  989.         }
  990.     }
  991.     *build++ = 0;
  992.     *build++ = 0;
  993.     *lPeek = tLines + 1;
  994.     
  995.     HUnlock(knownHosts);
  996.     ReallocHandle(knownHosts,tLen+2);
  997.     HLock(knownHosts);
  998.     
  999.     BlockMove(*newCache,*knownHosts,tLen+2);
  1000.     ChangedResource(knownHosts);
  1001.     WriteResource(knownHosts);
  1002.     DisposHandle(newCache);
  1003. }
  1004.  
  1005. /*----------------------------------------------------------------------
  1006. |  Find the next line in the service list buffer
  1007. ----------------------------------------------------------------------*/
  1008. void findNextLine(char **str)
  1009. {
  1010.     while( **str )
  1011.     {
  1012.         if( ( (**str) == '\n') || ( (**str) == '\r'))
  1013.         {
  1014.             **str = 0;
  1015.             ++(*str);
  1016.             return;
  1017.         }
  1018.         ++(*str);
  1019.     }
  1020. }
  1021.  
  1022. /*----------------------------------------------------------------------
  1023. |  Process the parameters list.
  1024. |
  1025. |  On entry, parameters are separated by whitespace (space, tab, cr,
  1026. |  etc.) in a Pascal string.  Single or double quotes may be used to
  1027. |  imbed whitespace inside a parameter.  Single quotes may appear inside
  1028. |  double-quoted strings, and visa-versa.  A backslash may preceed
  1029. |  special characters (quotes, backslashes) to include them in the
  1030. |  string.
  1031. |
  1032. |  On exit, parameters are concatinated to a C string & separated by
  1033. |  newlines..
  1034. ----------------------------------------------------------------------*/
  1035. processParams(char *str, char *new)
  1036. {
  1037.     char    c,
  1038.             quote = 0;
  1039.     int        skipwhite = 1,
  1040.             backslash = 0,
  1041.             i = *str;
  1042.     
  1043.     while(i-- > 0)
  1044.     {
  1045.         ++str;
  1046.         c = *str;
  1047.         if( backslash )
  1048.         {
  1049.             *new++ = c;
  1050.             backslash = 0;
  1051.             skipwhite = 0;
  1052.         }
  1053.         else if( c == '\\')
  1054.         {
  1055.             backslash = 1;
  1056.         }
  1057.         else if( c <= ' ' )
  1058.         {
  1059.             if( !skipwhite )
  1060.             {
  1061.                 if( quote )
  1062.                     *new++ = ' ';
  1063.                 else
  1064.                 {
  1065.                     *new++ = '\r';
  1066.                     skipwhite = 1;
  1067.                 }
  1068.             }
  1069.         }
  1070.         else if( (c == '"') || (c == '\'') )
  1071.         {
  1072.             if( c == quote )
  1073.                 quote = 0;
  1074.             else
  1075.                 quote = c;
  1076.             skipwhite = 0;
  1077.         }
  1078.         else
  1079.         {
  1080.             *new++ = c;
  1081.             skipwhite = 0;
  1082.         }
  1083.     }
  1084.     *new++ = '\r';
  1085.     if( !skipwhite ) *new++ = '\r';
  1086.     *new++ = 0;
  1087. }
  1088.  
  1089. /*----------------------------------------------------------------------
  1090. |  Return which rectangle the mouse is in.  WholeRect contains the
  1091. |  coordinates of the entire rectangle; inRect is set to the rectangle
  1092. |  that bounds the line that the mouse it pointing at.
  1093. ----------------------------------------------------------------------*/
  1094. mouseInRect( Rect *wholeRect, Rect *inRect )
  1095. {
  1096.     Point    theMouse;
  1097.     int        i;
  1098.     
  1099.     GetMouse( &theMouse );
  1100.     i = PtInRect( theMouse, wholeRect );
  1101.     
  1102.     *inRect = *wholeRect;
  1103.     InsetRect(inRect,1,1);
  1104.     theMouse.v -= wholeRect->top;
  1105.     theMouse.v /= 16;
  1106.     inRect->top = wholeRect->top + 1 + theMouse.v * 16;
  1107.     inRect->bottom = inRect->top+15;
  1108.     
  1109.     if( !i || (inRect->bottom > wholeRect->bottom) )
  1110.     {
  1111.         SetRect( inRect,-1,-1,-1,-1);
  1112.         return( -1 );
  1113.     }
  1114.     return(theMouse.v);
  1115. }
  1116.  
  1117. /*----------------------------------------------------------------------
  1118. |  Do the popup menu stuff.
  1119. ----------------------------------------------------------------------*/
  1120. int doPopup( DCtlPtr dCtl, DialogPtr dlog, int popItem, Str255 Pstr)
  1121. {
  1122.     RgnHandle    udRegion;
  1123.     Handle        knownHosts,
  1124.                 hList,
  1125.                 item;
  1126.     Rect        lastRect,
  1127.                 inRect,
  1128.                 tRect;
  1129.     char        *walk,
  1130.                 *build,
  1131.                 *hNames[maxInCache+2];
  1132.     short        itemType,
  1133.                 tlines = 0,
  1134.                 ilines = 0;
  1135.     int            i,
  1136.                 hLens[maxInCache+2],
  1137.                 mline;
  1138.  
  1139.     GetDItem(dlog,popItem,&itemType,&item,&tRect);
  1140.     tRect.bottom += 160;
  1141.     tRect.right  =  tRect.left + 176;
  1142.                 
  1143.     knownHosts = GetResource('STR#',DA_global->rsrcID+1 );
  1144.     hList = NewHandle( GetHandleSize(knownHosts) + 20L );
  1145.     if( (knownHosts == nil) || (hList == nil) )
  1146.     {
  1147.         SysBeep(0);
  1148.         return(-1);
  1149.     }
  1150.     
  1151.     MoveHHi(hList);
  1152.     HLock(hList);
  1153.     HLock( knownHosts );
  1154.     
  1155.     walk = *knownHosts + 2;
  1156.     build = *hList;
  1157.     while( (*walk) && (tlines < maxInCache) )
  1158.     {
  1159.         hNames[ilines] = build;
  1160.         hLens[ilines] = 0;
  1161.         walk++;
  1162.         while( (*walk) && (*walk != '=') && (*walk != ',') )
  1163.         {
  1164.             *build++ = *walk++;
  1165.             ++hLens[ilines];
  1166.         }
  1167.         *build++ = 0;
  1168.         ++ilines;
  1169.         while( *walk >= ' ' )
  1170.             ++walk;
  1171.         if( *walk )
  1172.         {
  1173.             ++walk;
  1174.             ++tlines;
  1175.         }
  1176.     }
  1177.     *build++ = 0;
  1178.     tRect.bottom = tRect.top + tlines * 16 + 1;
  1179.     SetRect(&lastRect,-1,-1,-1,-1);
  1180.     ShadedRect(&tRect);
  1181.  
  1182.     InsetRect(&tRect,1,1);
  1183.     for(i=0;i<tlines;++i)
  1184.     {
  1185.         MoveTo( tRect.left+8, tRect.top + 10 + i*16 );
  1186.         DrawText( hNames[i], 0, min(hLens[i],18) );
  1187.     }
  1188.     InsetRect(&tRect,-1,-1);
  1189.     
  1190.     while( StillDown() )
  1191.     {
  1192.         mline = mouseInRect( &tRect, &inRect );
  1193.         if( !EqualRect(&inRect, &lastRect) )
  1194.         {
  1195.             InvertRect( &lastRect );
  1196.             InvertRect( &inRect );
  1197.             lastRect = inRect;
  1198.         }
  1199.     }
  1200.     /*
  1201.      *  If the mouse was inside the popup menu, build a pascal string
  1202.      */
  1203.     if( mline > -1 )
  1204.     {
  1205.         C2Pstr(Pstr,hNames[mline]);
  1206.         /*
  1207.         walk = hNames[mline];
  1208.         build = Pstr + 1;
  1209.         *Pstr = 0;
  1210.         while( *walk >= ' ' )
  1211.         {
  1212.             *build++ = *walk++;
  1213.             ++(*Pstr);
  1214.         }
  1215.         */
  1216.     }
  1217.     HUnlock( knownHosts );
  1218.     DisposHandle( hList );
  1219.     InsetRect(&tRect,-2,-2);
  1220.     EraseRect(&tRect);
  1221.     /*
  1222.      *  Redraw the portion of the dialog that was covered
  1223.      */
  1224.     udRegion = NewRgn();
  1225.     RectRgn(udRegion,&tRect);
  1226.     UpdtDialog(dlog,udRegion);
  1227.     drawDefault(dlog);
  1228.     DisposeRgn(udRegion);
  1229.     
  1230.     return( mline );
  1231. }
  1232.