home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / UNIX / ARCHIE / CLIENTS / NEXTARCH.TAR / NeXTArchie / ArchieServer.m < prev    next >
Encoding:
Text File  |  1992-01-26  |  23.8 KB  |  914 lines

  1. /*
  2.  * Copyright (c) 1991 by the University of Washington
  3.  *
  4.  * For copying and distribution information, please see the file
  5.  * <uw-copyright.h>.
  6.  *
  7.  * Written by Clifford Neuman (bcn@isi.edu) with changes by
  8.  *            Brendan Kehoe (brendan@cs.widener.edu) and
  9.  *            George Ferguson (ferguson@cs.rochester.edu).
  10.  */
  11. #include <uw-copyright.h>
  12.  
  13. #import "ArchieServer.h"
  14. #import "MyBrowserCell.h"
  15. #import "ProsperoVLINK.h"
  16. #import <ClockView.h>
  17. #import <CalendarView.h>
  18. #import <FTPManager.h>
  19.  
  20. #import <objc/HashTable.h>
  21. #import <objc/List.h>
  22. #import <objc/NXStringTable.h>
  23. #import <objc/Storage.h>
  24. #import <appkit/Application.h>
  25. #import <appkit/ButtonCell.h>
  26. #import <appkit/Matrix.h>
  27. #import <appkit/NXBrowser.h>
  28. #import <appkit/SavePanel.h>
  29. #import <appkit/appkit.h>
  30. #import <NXCType.h>
  31. #import <defaults.h>
  32. #import <stdio.h>
  33. #import <sys/time.h>
  34. #import <perrno.h>
  35. #import <rdgram.h>
  36. #import <archie.h>
  37. #import <mach.h>
  38. #import <fcntl.h>
  39. #import <signal.h>
  40.  
  41. /* Import the error message NXStringTable keys */
  42. #import "errMessages.keys"
  43.  
  44. /* The Prospero debugging level */
  45. int    pfs_debug;
  46.  
  47. /* Globals defined in dirsend2.c used to communicate the query status */
  48. extern char dirsendStatusBuffer[128];
  49. char statusBuffer[128];
  50.  
  51. #define QUERY_ABORT 1
  52. int queryActiveFlag;        // A flag used to indicate that the query thread is active
  53. void QueryThreadProc(ArchieServer *self);
  54.  
  55. /* The query string sent to the query_archie() procedure */
  56. const char *searchString;
  57.  
  58. /* Sort enums */
  59. enum {ByName,ByDate,NoSort};
  60. /* Niceness level enums */
  61. enum {MinNice = 0,LowNice = 500,HighNice = 10000,MaxNice = 32765};
  62.  
  63. /* Defaults stuff */
  64. /* The owner of the application defaults */
  65. const char *NeXTArchieOwner = "NeXTArchie_SMS";
  66. enum {QueryType,MaxReplies,Offset,SortType,
  67.     ExactFlag,NiceLevel,Hostname,HostTag,DebugLevel,FtpDebugLevel}; 
  68. /* A stringification macro */
  69. #define DefaultString(STR) #STR
  70. /* A macro for retriveing default values */
  71. #define GetDefault(STR) NXGetDefaultValue(NeXTArchieOwner, #STR)
  72. /* A flag indicating if the pref panel widgets are in sync with the defaults */
  73. BOOL resetPrefPanel;
  74. /* The virgin defaults */
  75. static struct _NXDefault *NextArchieDefaults;
  76. #define _QueryType    "C"
  77. #define _MaxReplies    "100"
  78. #define _Offset        "0"
  79. #define _SortType    "0"
  80. #define _ExactFlag    "YES"
  81. #define _NiceLevel    "0"
  82. #define _Hostname    "archie.mcgill.ca"
  83. #define _HostTag    "0"
  84. #define _DebugLevel    "2"
  85. #define _FtpDebugLevel "0"
  86.  
  87. /* The title for the custom host radio button */
  88. #define CUSTOM_TITLE "Custom host"
  89. #define CUSTOM_TAG 7
  90.  
  91. @implementation ArchieServer
  92.  
  93. /* Initialization */
  94. + initialize
  95. {
  96. int i;
  97.     /* Register the defaults for the preference items */
  98.     NextArchieDefaults = (struct _NXDefault *) malloc(11*sizeof(struct _NXDefault));
  99.     for(i = 0; i < 10; i ++)
  100.     {
  101.         NextArchieDefaults[i].name = (char *) malloc(16);
  102.         NextArchieDefaults[i].value = (char *) malloc(32);
  103.     }
  104.     NextArchieDefaults[10].name = NULL;
  105.     NextArchieDefaults[10].value = NULL;
  106.     strcpy(NextArchieDefaults[QueryType].name, DefaultString(QueryType));
  107.     strcpy(NextArchieDefaults[MaxReplies].name, DefaultString(MaxReplies));
  108.     strcpy(NextArchieDefaults[Offset].name, DefaultString(Offset));
  109.     strcpy(NextArchieDefaults[SortType].name, DefaultString(SortType));
  110.     strcpy(NextArchieDefaults[ExactFlag].name, DefaultString(ExactFlag));
  111.     strcpy(NextArchieDefaults[NiceLevel].name, DefaultString(NiceLevel));
  112.     strcpy(NextArchieDefaults[Hostname].name, DefaultString(Hostname));
  113.     strcpy(NextArchieDefaults[HostTag].name, DefaultString(HostTag));
  114.     strcpy(NextArchieDefaults[DebugLevel].name, DefaultString(DebugLevel));
  115.     strcpy(NextArchieDefaults[FtpDebugLevel].name, DefaultString(FtpDebugLevel));
  116.     strcpy(NextArchieDefaults[QueryType].value, _QueryType);
  117.     strcpy(NextArchieDefaults[MaxReplies].value, _MaxReplies);
  118.     strcpy(NextArchieDefaults[Offset].value, _Offset);
  119.     strcpy(NextArchieDefaults[SortType].value, _SortType);
  120.     strcpy(NextArchieDefaults[ExactFlag].value, _ExactFlag);
  121.     strcpy(NextArchieDefaults[NiceLevel].value, _NiceLevel);
  122.     strcpy(NextArchieDefaults[Hostname].value, _Hostname);
  123.     strcpy(NextArchieDefaults[HostTag].value, _HostTag);
  124.     strcpy(NextArchieDefaults[DebugLevel].value, _DebugLevel);
  125.     strcpy(NextArchieDefaults[FtpDebugLevel].value, _FtpDebugLevel);
  126.  
  127.     NXRegisterDefaults(NeXTArchieOwner, NextArchieDefaults);
  128.  
  129.     return self;
  130. }
  131.  
  132. - init
  133. {
  134. const char *defString;
  135.  
  136.     [super init];
  137.  
  138.     /* Initialize the host keyed hashtable */
  139.     hostHashTable = [[HashTable alloc] initKeyDesc: "*"];
  140.     if(hostHashTable == nil)
  141.         return [self error: SEVERE key: HOSTHASHTABLE_ALLOC_FAILED];
  142.     hostList = [[List alloc] initCount: 0];
  143.     if(hostList == nil)
  144.         return [self error: SEVERE key: HOSTLIST_ALLOC_FAILED];
  145.  
  146.     /* Load the default values for the archie options */
  147.     defString = GetDefault(QueryType);
  148.     queryType = defString[0];
  149.     maxReplies = atoi(GetDefault(MaxReplies));
  150.     offset = atoi(GetDefault(Offset));
  151.     sortType = atoi(GetDefault(SortType));
  152.     cmpProc = (sortType == ByName ? AQ_DEFCMP: AQ_INVDATECMP);
  153.     defString = GetDefault(ExactFlag);
  154.     exactFlag = (defString[0] == 'Y' ? YES: NO);
  155.     defString = GetDefault(NiceLevel);
  156.     niceLevel = atoi(defString);
  157.     hostname = GetDefault(Hostname);
  158.     if(hostname == NULL)
  159.         hostname = ARCHIE_HOST;
  160.     hostTag= atoi(GetDefault(HostTag));
  161.     defString = GetDefault(DebugLevel);
  162.     pfs_debug =  debugLevel = atoi(defString);
  163.     resetPrefPanel = YES;
  164.  
  165.     return self;
  166. }
  167.  
  168. - archieRequest: sender
  169. {
  170. int threadExitStatus,modalStatus;
  171. char messageBuffer[128];
  172. NXModalSession  theSession;
  173. /* Prototypes taken from pfs/perrmesg.c */
  174. int spwarnmesg(char *buf,char *prefix,int no,char *text);
  175. int sperrmesg(char *buf,char *prefix,int no,char *text);
  176.  
  177.     /* Get the search string from the interface and query the Archie server */
  178.     searchString = [sender stringValue];
  179.     
  180.     /* Begin a modal session which gives the user the opportunity to
  181.         abort the query */
  182.     [NXApp beginModalSession: &theSession for: queryPanelID];
  183.     [hostnameID setStringValue: hostname];
  184.     strcpy(statusBuffer,"Querying Archie Server...");
  185.     strcpy(dirsendStatusBuffer,"Querying Archie Server...");
  186.     [statusID setStringValue: statusBuffer];
  187.     [queryTimerID startMinSecTimer: self];
  188.     [queryPanelID display];
  189.  
  190.     /* Create a thread to query the Archie server */
  191.     queryActiveFlag = 1;
  192.     queryThread = cthread_fork((cthread_fn_t) QueryThreadProc,(any_t) self);
  193.  
  194.     while ( queryActiveFlag )
  195.     {
  196.         modalStatus = [NXApp runModalSession:&theSession];
  197.         if ( modalStatus != NX_RUNCONTINUES )
  198.             break;
  199.         /* Display the current query status */
  200.         if( strcmp(statusBuffer,dirsendStatusBuffer) )
  201.         {
  202.             [statusID setStringValue: dirsendStatusBuffer];
  203.             strcpy(statusBuffer,dirsendStatusBuffer);
  204.         }
  205.         cthread_yield();
  206.     }
  207.     [queryPanelID orderOut: self];
  208.     [NXApp endModalSession: &theSession];
  209.  
  210.     /* Check result status */
  211.     if(queryActiveFlag)
  212.         // Query was aborted
  213.         thread_resume(cthread_thread(queryThread));
  214.  
  215.     threadExitStatus = (int) cthread_join(queryThread);
  216.     if(modalStatus != QUERY_ABORT && threadExitStatus > 0)
  217.     {
  218.         if(perrno == 0)
  219.             strcpy(messageBuffer,"No matches found");
  220.         else
  221.             sperrmesg(messageBuffer,"Propsero Error Message:\n",0,NULL);
  222.         NXBeep();
  223.         NXRunAlertPanel(NULL, messageBuffer,NULL,NULL,NULL);
  224.         return nil;
  225.     }
  226.     else if(modalStatus == QUERY_ABORT)
  227.         return nil;
  228.  
  229.     if(pwarn)
  230.     {
  231.         spwarnmesg(messageBuffer,"Propsero Warning Message:\n",0,NULL);
  232.         NXBeep();
  233.         NXRunAlertPanel(NULL, messageBuffer,NULL,NULL,NULL);
  234.     }
  235.  
  236.     /* Parse the Archie response for display in the browser */
  237.     if(threadExitStatus == 0)
  238.         if( [self parseResponse: archieRslt] != nil)
  239.         {
  240.             /* Set the fileBrowserID cells class to MyBrowserCell */
  241.             [fileBrowserID setCellClass: [MyBrowserCell class]];
  242.             [fileBrowserID setPathSeparator: ':'];  // Not used presently
  243.             [fileBrowserID loadColumnZero];
  244.         }
  245.  
  246.     return self;
  247. }
  248.  
  249. - parseResponse: (VLINK) response
  250. {
  251. ProsperoVLINK *v;
  252. List *hostFiles;
  253. const char *host_name;
  254.  
  255.     [hostHashTable freeObjects];
  256.     [hostList freeObjects];
  257.     while(response)
  258.     {    /* Step 1 - Create a ProsperoVLINK object this VLINK */
  259.         v = [[ProsperoVLINK alloc] initVLINK: response];
  260.         if(v == nil)
  261.         {    // Error
  262.             return [self error: ALERT key: VLINK_ALLOC_FAILED];
  263.         }
  264.         /* Step 2 - See if the hostname has been entered as a key in the hostHashTable */
  265.         host_name = [v hostname];
  266.         if( [hostHashTable isKey: host_name] == YES)
  267.         {    // Then get the List of files for this host
  268.             hostFiles = (List *) [hostHashTable valueForKey: host_name];
  269.             if(hostFiles == nil)
  270.             {    // Error
  271.                 return [self error: ALERT key: VALID_KEY_NIL_ENTRY];
  272.             }
  273.             // Add this file to the host list
  274.             [hostFiles addObject: v];
  275.         }
  276.         else
  277.         {    // Create a new List for this host and add it to the
  278.             //    hostHashTable for fast acces and to the hostList to maintain
  279.             //    the requested order
  280.             hostFiles = [[List alloc] initCount: 0];
  281.             if(hostFiles == nil)
  282.                 return [self error: SEVERE key: HOSTFILES_ALLOC_FAILED];
  283.             [hostFiles addObject: v];
  284.             [hostHashTable insertKey: host_name value: hostFiles];
  285.             [hostList addObject: v];
  286.         }
  287.         response = response->next;
  288.     }
  289.     return self;
  290. }
  291.  
  292. /* Interrupt the request */
  293. - interruptRequest: sender
  294. {
  295.     /* Suspend and abort the query thread */
  296.     thread_suspend(cthread_thread(queryThread));
  297.     cthread_abort(queryThread);
  298.     
  299.     /* Stop the modal loop */
  300.     [NXApp stopModal: QUERY_ABORT];
  301.  
  302.     return self;
  303. }
  304.  
  305. /* A simple wrapper function that is passed to cthread_fork().  The thread that
  306.     calls this function simply invokes the archie_query() function and sets the
  307.     archieRslt instance variable to its reslt.
  308.     It returns 0 on sucess and nonzero if an error occurs.
  309. */
  310. void QueryThreadProc(ArchieServer *self)
  311. {
  312. int queryFlags;
  313.  
  314.     if(self->sortType == NoSort)
  315.         queryFlags = AQ_NOSORT;
  316.     else
  317.         queryFlags = 0;
  318.     if(self->exactFlag == YES)
  319.         self->queryType = NXToLower(self->queryType);
  320.  
  321.     /* Initialize the Prospero error variables */ 
  322.     perrno = 0; *p_err_string = '\0';
  323.     pwarn = 0;  *p_warn_string = '\0';
  324.  
  325.     self->archieRslt = archie_query(self->hostname,searchString,self->maxReplies,
  326.         self->offset,self->queryType,self->cmpProc,queryFlags);
  327.     
  328.     queryActiveFlag = 0;
  329.     if(self->archieRslt == NULL)
  330.         cthread_exit( (any_t)1 );    // No matches found, query aborted, or Prospero error
  331.  
  332.     cthread_exit( (any_t)0 );        // Successful query
  333. }
  334.  
  335. /* Bring up the info panel */
  336. - infoPanel: sender
  337. {
  338.     if(infoPanelID == nil)
  339.     {
  340.         [NXApp loadNibSection: "Info.nib" owner: self withNames: NO];
  341.         if(infoPanelID == nil)
  342.             return [self error: SORRY key: INFO_PANEL_FAILED];
  343.     }
  344.     [infoPanelID makeKeyAndOrderFront: self];
  345.     return self;
  346. }
  347.  
  348. /* Display the query options panel */
  349. - preferences: sender
  350. {
  351.     if(prefPanelID == nil)
  352.     {
  353.         [NXApp loadNibSection: "Preferences.nib" owner: self withNames: NO];
  354.         if(prefPanelID == nil)
  355.             return [self error: SORRY key: PREF_PANEL_FAILED];
  356.     }
  357.     if(resetPrefPanel == YES)
  358.     {
  359.     int nice,query;
  360.         [ hostMatrixID selectCellWithTag: hostTag];
  361.         if(hostTag == CUSTOM_TAG)
  362.             [customHostID setStringValue: hostname];
  363.         [ sortMatrixID selectCellAt: sortType: 0];
  364.         switch(queryType)
  365.         {
  366.             case 'C' :
  367.                 query = 0;
  368.                 break;
  369.             case 'S' :
  370.                 query = 1;
  371.                 break;
  372.             case 'R' :
  373.                 query = 2;
  374.                 break;
  375.             case '=' :
  376.                 query = 3;
  377.                 break;
  378.             default :
  379.                 query = 0;
  380.                 break;
  381.         }
  382.         [ patternMatrixID selectCellAt: query: 0];
  383.         [ exactBtnID setState: exactFlag];
  384.         switch(niceLevel)
  385.         {
  386.             case MinNice :
  387.                 nice = 0;
  388.                 break;
  389.             case LowNice :
  390.                 nice = 1;
  391.                 break;
  392.             case HighNice :
  393.                 nice = 2;
  394.                 break;
  395.             case MaxNice :
  396.                 nice = 3;
  397.                 break;
  398.             default :
  399.                 nice = 0;
  400.                 break;
  401.         }
  402.         [ niceMatrixID selectCellAt: 0 : nice];
  403.         [ hitsFormID setIntValue: maxReplies];
  404.         [ debugMatrixID selectCellAt: 0 : debugLevel];
  405.     }
  406.  
  407.     [[prefPanelID orderFront: self] display];
  408.     return self;
  409. }
  410.  
  411. /* Methods which set the query options */
  412. - setQueryType: sender
  413. {
  414.     switch([sender selectedRow])
  415.     {
  416.         case 0 :
  417.             queryType = 'C';
  418.             break;
  419.         case 1 :
  420.             queryType = 'S';
  421.             break;
  422.         case 2 :
  423.             queryType = 'R';
  424.             break;
  425.         case 3 :
  426.         default:
  427.             queryType = '=';
  428.             break;
  429.     }
  430.     return self;
  431. }
  432. - setExactMode: sender
  433. {
  434.     exactFlag = [sender state];
  435.     return self;
  436. }
  437. - setMaxReplies: sender
  438. {
  439.     maxReplies = [sender intValue];
  440.     return self;
  441. }
  442. - setOffset: sender
  443. {
  444.     offset = [sender intValue];
  445.     return self;
  446. }
  447. - setSortType: sender
  448. {
  449.     sortType = [sender selectedRow];
  450.     switch(sortType)
  451.     {
  452.         case 0 :
  453.             cmpProc = AQ_DEFCMP;
  454.             break;
  455.         case 1 :
  456.             cmpProc = AQ_INVDATECMP;
  457.             break;
  458.         case 2 :
  459.             cmpProc = NULL;
  460.             break;
  461.         default :
  462.             cmpProc = AQ_DEFCMP;
  463.             break;
  464.     }
  465.     return self;
  466. }
  467. - setNiceLevel: sender
  468. {
  469.     switch([sender selectedCol])
  470.     {
  471.         case 0 :
  472.             niceLevel =     MinNice;
  473.             break;
  474.         case 1 :
  475.             niceLevel =     LowNice;
  476.             break;
  477.         case 2 :
  478.             niceLevel =     HighNice;
  479.             break;
  480.         case 3 :
  481.             niceLevel =     MaxNice;
  482.             break;
  483.         default :
  484.             niceLevel =     MinNice;
  485.             break;
  486.     }
  487.     return self;
  488. }
  489. - setHostname: sender
  490. {
  491.     /* See if this is a custom host request */
  492.     if( strcmp([[sender selectedCell] title],CUSTOM_TITLE) == 0 )
  493.         hostname = [customHostID stringValue];
  494.     else
  495.         hostname = (char *) [[sender selectedCell] title];
  496.     hostTag= [[sender selectedCell] tag]; 
  497.     return self;
  498. }
  499. /* The target of the ``Custom hostname'' TextField */
  500. - setCustomHost: sender
  501. {
  502.     hostname = [sender stringValue];
  503.     hostTag = CUSTOM_TAG;
  504.     [hostMatrixID selectCellWithTag: hostTag];
  505.     return self;
  506. }
  507. - setDebugLevel: sender
  508. {
  509. ButtonCell *cell;
  510.     cell = [sender selectedCell];
  511.     pfs_debug = debugLevel = [cell tag];
  512.     return self;
  513. }
  514.  
  515. /* Ftp methods */
  516. - retrieveFile: sender
  517. {
  518. const char *remoteHost,*remoteFile;
  519. BOOL binaryMode;
  520. int selectedColumn;
  521.  
  522.     if(ftpObject == nil)
  523.     {
  524.         ftpObject = [[FTPManager alloc] init];
  525.         if(ftpObject == nil)
  526.             return [self error: ALERT key: FTPOBJECT_ALLOC_FAILED];
  527.     }
  528.     remoteHost = [selectedFile hostname];
  529.     remoteFile = [selectedFile filePath];
  530.     if([modeMatrixID selectedRow] == 0)
  531.         binaryMode = NO;
  532.     else
  533.         binaryMode = YES;
  534.     /* Activate the FTPManager for the transfer */
  535.     if([selectedFile isDirectory] == NO)
  536.         [ftpObject runModal: remoteHost get: remoteFile anon: YES
  537.             write: NO binary: binaryMode vlink: nil];
  538.     else
  539.     {
  540.         [ftpObject runModal: remoteHost get: remoteFile anon: YES
  541.             write: NO binary: NO vlink: selectedFile];
  542.         selectedColumn = [fileBrowserID selectedColumn];
  543.         [fileBrowserID reloadColumn: selectedColumn+1];
  544.     }
  545.     return self;
  546. }
  547.  
  548. - setTransferDir : sender
  549. {
  550.     if(ftpObject == nil)
  551.     {
  552.         ftpObject = [[FTPManager alloc] init];
  553.         if(ftpObject == nil)
  554.             return [self error: ALERT key: FTPOBJECT_ALLOC_FAILED];
  555.     }
  556.     [ftpObject setLocalDir: self];
  557.  
  558.     return self;
  559. }
  560.  
  561. /* Read/Restore default preferences */
  562. - saveDefaults: sender
  563. {
  564. /* An updateable defaults vector */
  565. int i;
  566. struct _NXDefault *_NextArchieDefaults;
  567.     _NextArchieDefaults = (struct _NXDefault *) malloc(10*sizeof(struct _NXDefault));
  568.     if(_NextArchieDefaults == NULL)
  569.         return [self error: ALERT key: NXDEFAULTS_ALLOC_FAILED];
  570.  
  571.     for(i = 0; i < 9; i ++)
  572.     {
  573.         _NextArchieDefaults[i].name = (char *) malloc(16);
  574.         _NextArchieDefaults[i].value = (char *) malloc(32);
  575.         if(_NextArchieDefaults[i].name == NULL ||
  576.             _NextArchieDefaults[i].value == NULL)
  577.             return [self error: ALERT key: NXDEFAULTS_ITEM_ALLOC_FAILED];
  578.     }
  579.     _NextArchieDefaults[9].name = NULL;
  580.     _NextArchieDefaults[9].value = NULL;
  581.  
  582.     strcpy(_NextArchieDefaults[QueryType].name, DefaultString(QueryType));
  583.     strcpy(_NextArchieDefaults[MaxReplies].name, DefaultString(MaxReplies));
  584.     strcpy(_NextArchieDefaults[Offset].name, DefaultString(Offset));
  585.     strcpy(_NextArchieDefaults[SortType].name, DefaultString(SortType));
  586.     strcpy(_NextArchieDefaults[ExactFlag].name, DefaultString(ExactFlag));
  587.     strcpy(_NextArchieDefaults[NiceLevel].name, DefaultString(NiceLevel));
  588.     strcpy(_NextArchieDefaults[Hostname].name, DefaultString(Hostname));
  589.     strcpy(_NextArchieDefaults[HostTag].name, DefaultString(HostTag));
  590.     strcpy(_NextArchieDefaults[DebugLevel].name, DefaultString(DebugLevel));
  591.     sprintf(_NextArchieDefaults[QueryType].value,"%c",queryType);
  592.     sprintf(_NextArchieDefaults[MaxReplies].value,"%d",maxReplies);
  593.     sprintf(_NextArchieDefaults[Offset].value,"%d",offset);
  594.     sprintf(_NextArchieDefaults[SortType].value,"%d",sortType);
  595.     sprintf(_NextArchieDefaults[ExactFlag].value,"%s",(exactFlag == YES ? "YES" : "NO"));
  596.     sprintf(_NextArchieDefaults[NiceLevel].value,"%d",niceLevel);
  597.     sprintf(_NextArchieDefaults[Hostname].value,"%s",hostname);
  598.     sprintf(_NextArchieDefaults[HostTag].value,"%d",hostTag);
  599.     sprintf(_NextArchieDefaults[DebugLevel].value,"%d",debugLevel);
  600.  
  601.     NXWriteDefaults(NeXTArchieOwner, _NextArchieDefaults);
  602.  
  603.     for(i = 0; i < 9; i ++)
  604.     {
  605.         free(_NextArchieDefaults[i].name);
  606.         free(_NextArchieDefaults[i].value);
  607.     }
  608.     free(_NextArchieDefaults);
  609.  
  610.     return self;
  611. }
  612.  
  613. - restoreDefaults: sender
  614. {
  615.     /* Restore the virgin defaults */
  616.     NXWriteDefaults(NeXTArchieOwner, NextArchieDefaults);
  617.     NXUpdateDefaults();
  618.  
  619.     /* Reset the preferences panel objects */
  620.     resetPrefPanel = YES;
  621.     [self preferences: self];
  622.  
  623.     return self;
  624. }
  625.  
  626. /* Browser delegate method which fills the browser with the last
  627.     query result.  This version displays the hosts in column0, the full pathanme
  628.     in column1 and the lowest file in the path in column2. */
  629. - (int)browser: sender  fillMatrix: matrix inColumn:(int) column
  630. {
  631. const char *host_name;
  632. int row,rows,depth;
  633. id hostFileList,link,dirListing;
  634. MyBrowserCell *cell;
  635.  
  636.     /* Column zero */
  637.     if(column == 0)
  638.     {    // Load the host names
  639.  
  640.         rows = [hostList count];
  641.         for(row = 0; row < rows; row ++)
  642.         {
  643.             host_name = [[hostList objectAt: row] hostname];
  644.             [matrix addRow];
  645.             cell = [matrix cellAt: row : 0];
  646.             [cell setStringValue: host_name];
  647.             [cell setLoaded:YES];
  648.             [cell setLeaf: NO];
  649.         }
  650.     }
  651.     else if(column == 1)
  652.     {    // Loop through the host's files and display the pathnames
  653.  
  654.         /* Get the file list for the selected host */
  655.         host_name = [[[sender matrixInColumn: 0] selectedCell] stringValue];
  656.         hostFileList = (List *) [hostHashTable valueForKey: host_name];
  657.         
  658.         rows = [hostFileList count];
  659.         for(row = 0; row < rows; row ++)
  660.         {
  661.             link = (ProsperoVLINK *) [hostFileList objectAt: row];
  662.             [matrix addRow];
  663.             depth = [link fileDepth];
  664.             cell = [matrix cellAt: row : 0];
  665.                 [cell setStringValue: [link filePath]];
  666.             [cell setLoaded:YES];
  667.             if(depth > column)
  668.             {
  669.                 [cell setLeaf: NO];
  670.                 [cell setTag: nil];
  671.             }
  672.             else
  673.             {    // This is the file's level
  674.                 if([link isDirectory] == NO)
  675.                     [cell setLeaf: YES];
  676.                 else
  677.                     [cell setLeaf: NO];
  678.                 [cell setTag: link];
  679.             }
  680.         }
  681.     }
  682.     else if(column == 2)
  683.     {    // Load one cell and display the end item of the selected path
  684.         
  685.         /* Get the file list for the selected host */
  686.         host_name = [[[sender matrixInColumn: 0] selectedCell] stringValue];
  687.         hostFileList = (List *) [hostHashTable valueForKey: host_name];
  688.         rows = 1;
  689.         row = [[sender matrixInColumn: 1] selectedRow];
  690.         link = (ProsperoVLINK *) [hostFileList objectAt: row];
  691.         [matrix addRow];
  692.         cell = [matrix cellAt: 0 : 0];
  693.         [cell setStringValue: [link fileName]];
  694.         [cell setLoaded:YES];
  695.         [cell setTag: link];
  696.         if( [link isDirectory] == NO)
  697.             [cell setLeaf: YES];
  698.         else
  699.             [cell setLeaf: NO];
  700.     }
  701.     else
  702.     {
  703.         // The directory vlink in the previous column
  704.         cell = [[sender matrixInColumn: column - 1] selectedCell] ;
  705.         link = [cell tag];
  706.         dirListing = [link listing];
  707.         rows = [dirListing count];
  708.         for(row = 0; row < rows; row ++)
  709.         {
  710.             link = [dirListing objectAt: row];
  711.             [matrix addRow];
  712.             cell = [matrix cellAt: row : 0];
  713.             [cell setStringValue: [link fileName]];
  714.             [cell setLoaded:YES];
  715.             [cell setTag: link];
  716.             [cell setEnabled: YES];
  717.             if( [link isDirectory] == NO)
  718.                 [cell setLeaf: YES];
  719.             else
  720.                 [cell setLeaf: NO];
  721.         }
  722.         if(rows <= 0)
  723.         {
  724.             rows = 1;
  725.             [matrix addRow];
  726.             cell = [matrix cellAt: row : 0];
  727.             if(dirListing == nil)
  728.                 [cell setStringValue: "Directory not loaded"];
  729.             else
  730.                 [cell setStringValue: "No files"];
  731.             [cell setLoaded:YES];
  732.             [cell setTag: nil];
  733.             [cell setLeaf: YES];
  734.             [cell setEnabled: NO];
  735.         }
  736.     }
  737.     return rows;
  738. }
  739.  
  740. #define Read 4
  741. #define Write 2
  742. #define Exec 1
  743. #define Owner 448
  744. #define Group 56
  745. #define Other 7
  746.  
  747. - fileAttributes: sender
  748. {
  749. ProsperoVLINK *link;
  750. short hr,min,sec;
  751. short day,month,year;
  752. int owner,group,other,mode;
  753. int row,col;
  754. MyBrowserCell *cell;
  755.  
  756.     col = [sender selectedColumn];
  757.     if(col == 0)
  758.     {    // Clear the info display
  759.         [self clearFields];
  760.         [retrieveBtnID setEnabled: NO];
  761.         selectedFile = nil;
  762.         return self;
  763.     }
  764.  
  765.     row = [[sender matrixInColumn: col] selectedRow];
  766.     cell = [sender getLoadedCellAtRow: row inColumn: col];
  767.  
  768.     /* The id value of the selected cell is the cell's tag value */
  769.     link = (ProsperoVLINK *) [cell tag];
  770.     selectedFile = link;
  771.  
  772.     /* Don't display any info for non directories */
  773.     if([cell isLeaf] == NO && col == 1)
  774.     {
  775.         [self clearFields];
  776.         [retrieveBtnID setEnabled: NO];
  777.         selectedFile = nil;
  778.         return self;
  779.     }
  780.  
  781.     /* Enable ftp transfer if the item is not a directory, listing if it is */    [retrieveBtnID setEnabled: YES];
  782.     if([selectedFile isDirectory] == NO)
  783.         [retrieveBtnID setTitle: "Retrieve..."];
  784.     else
  785.         [retrieveBtnID setTitle: "Listing..."];
  786.  
  787.     /* Set the modification time and date */
  788.     [link time: &hr : &min : &sec];
  789.     [clockID setTime: hr : min : sec];
  790.     day = [link day];
  791.     month = [link month];    // Runs from 0-11
  792.     year = [link year];
  793.     // Expects month to run from 1-12 for consistency with string dates
  794.     [calendarID setDate: day : month+1 : year];
  795.  
  796.     /* Set the file info Form */
  797.     [fileInfoID setStringValue: [link hostname] at: 0];
  798.     [fileInfoID setStringValue: [link filePath] at: 1];
  799.     [fileInfoID setStringValue: [link fileName] at: 2];
  800.     [fileInfoID setIntValue: [link fileSize] at: 3];
  801.     [fileInfoID setStringValue: ([link isDirectory] == YES ? "Directory" : "File") at: 4];
  802.  
  803.     /* Set the file permissions */
  804.     mode = [link mode];
  805.     owner = (mode  & Owner) >> 6;
  806.     group = (mode & Group) >> 3;
  807.     other = mode & Other;
  808.     if(owner & Read)
  809.         [readMatrixID setState: YES at: 0 : 0];
  810.     else
  811.         [readMatrixID setState: NO at: 0 : 0];
  812.     if(group & Read)
  813.         [readMatrixID setState: YES at: 0 : 1];
  814.     else
  815.         [readMatrixID setState: NO at: 0 : 1];
  816.     if(other & Read)
  817.         [readMatrixID setState: YES at: 0 : 2];
  818.     else
  819.         [readMatrixID setState: NO at: 0 : 2];
  820.  
  821.     if(owner & Write)
  822.         [writeMatrixID setState: YES at: 0 : 0];
  823.     else
  824.         [writeMatrixID setState: NO at: 0 : 0];
  825.     if(group & Write)
  826.         [writeMatrixID setState: YES at: 0 : 1];
  827.     else
  828.         [writeMatrixID setState: NO at: 0 : 1];
  829.     if(other & Write)
  830.         [writeMatrixID setState: YES at: 0 : 2];
  831.     else
  832.         [writeMatrixID setState: NO at: 0 : 2];
  833.  
  834.     if(owner & Exec)
  835.         [execMatrixID setState: YES at: 0 : 0];
  836.     else
  837.         [execMatrixID setState: NO at: 0 : 0];
  838.     if(group & Exec)
  839.         [execMatrixID setState: YES at: 0 : 1];
  840.     else
  841.         [execMatrixID setState: NO at: 0 : 1];
  842.     if(other & Exec)
  843.         [execMatrixID setState: YES at: 0 : 2];
  844.     else
  845.         [execMatrixID setState: NO at: 0 : 2];
  846.  
  847.     return self;
  848. }
  849.  
  850. - clearFields
  851. {
  852.     /* Reset date to now */
  853.     [clockID now];
  854.     [calendarID today];
  855.  
  856.     /* Reset the file info Form */
  857.     [fileInfoID setStringValue: NULL at: 0];
  858.     [fileInfoID setStringValue: NULL at: 1];
  859.     [fileInfoID setStringValue: NULL at: 2];
  860.     [fileInfoID setStringValue: NULL at: 3];
  861.     [fileInfoID setStringValue: NULL at: 4];
  862.  
  863.     /* Rest permissions */
  864.     [readMatrixID setState: YES at: 0 : 0];
  865.     [readMatrixID setState: YES at: 0 : 1];
  866.     [readMatrixID setState: YES at: 0 : 2];
  867.     [writeMatrixID setState: YES at: 0 : 0];
  868.     [writeMatrixID setState: YES at: 0 : 1];
  869.     [writeMatrixID setState: YES at: 0 : 2];
  870.     [execMatrixID setState: YES at: 0 : 0];
  871.     [execMatrixID setState: YES at: 0 : 1];
  872.     [execMatrixID setState: YES at: 0 : 2];
  873.  
  874.     return self;
  875. }
  876.  
  877. /* Report the error associated with the keyString and depending on
  878.     the continue depending on the severity */
  879. - error:(int) severity key:(const char *) keyString
  880. {
  881. const char *errMessage;
  882. const char *replyRequest;
  883.  
  884. int alertResult;
  885.  
  886.     errMessage = [errStringTable valueForStringKey: keyString];
  887.     switch(severity)
  888.     {
  889.         case SORRY :
  890.             replyRequest = [errStringTable valueForStringKey: REPLY_REQUEST2];
  891.             break;
  892.         case ALERT :
  893.             replyRequest = [errStringTable valueForStringKey: REPLY_REQUEST1];
  894.             break;
  895.         case SEVERE :
  896.         default:
  897.             replyRequest = [errStringTable valueForStringKey: REPLY_REQUEST0];
  898.             break;
  899.     }
  900.  
  901.     if(severity >= SEVERE)
  902.         alertResult = NXRunAlertPanel("Error","%s\n\t%s","Quit",NULL,NULL,
  903.             errMessage,replyRequest);
  904.     else
  905.         alertResult = NXRunAlertPanel("Error","%s\n\t%s","Ok","Quit",NULL,
  906.             errMessage,replyRequest);
  907.     if(severity >= SEVERE || alertResult == NX_ALERTALTERNATE)
  908.         [NXApp terminate: self];
  909.     
  910.     return self;
  911. }
  912.  
  913. @end
  914.