home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / MyOOSIVC.p < prev    next >
Encoding:
Text File  |  1996-06-01  |  14.1 KB  |  545 lines  |  [TEXT/CWIE]

  1. unit MyOOSIVC;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types;
  7.  
  8.     const
  9.         PC_UseSIVC = 'SIVC';
  10.         PC_FirstCheckSIVC = 'SIVd';
  11.         PC_LastCheckSIVCQuantum = 'SICl';
  12.         PC_CheckSIVCPeriod = 'SIVc';
  13.         PC_LastSIVC = 'SIVL';
  14.         PC_SIVCUsers = 'SIVU';
  15.         
  16.     type
  17.         SIVCNewVersionCallBack = procedure(data:Handle; latest_version:Str31);
  18.         SIVCGetSOCKSServerCallBack = procedure(var server:Str255);
  19.         SIVCManualQueryCallBack = procedure(err:OSErr; newversion:Boolean; data:Handle; latest_version:Str31);
  20.     
  21.     var
  22.         first_ever_sivc: Boolean; { if this is the first time - warn the user! }
  23.         
  24.     procedure StartupSIVC;
  25.     procedure ConfigureSIVC(newversion : SIVCNewVersionCallBack; getsocks:SIVCGetSOCKSServerCallBack);
  26.         
  27.     procedure ManualQuery(mcresult: SIVCManualQueryCallBack);
  28.     function CanManualQuery:Boolean;
  29.     
  30. implementation
  31.  
  32.     uses
  33.         Errors, Resources, MyNewPreferences, TCPOOConnections, DNR, MyMathUtils, TranslateISO,
  34.         MyTypes, MyHandleFile, MySocks, MyStrings, MyVersionResource, MyUtils, MyStartup;
  35.         
  36.     const
  37.         sivc_id = 932;
  38.         sivc_default_port = 7124;
  39.         idle_til_period = 10 * 60 *60; { only even consider checking every 10 minutes }
  40.         timeout_period = 120 * 60;
  41.  
  42.     type
  43.         SIVCStrings = (SS_None, SS_Server, SS_SOCKSServer);
  44.         SIVCState = (ST_None, ST_SOCKS_DNR, ST_Connecting, ST_SendSOCKS, ST_SendQuery, ST_WaitClose, ST_Finished);
  45.         SIVCMaunalState = (MS_None, MS_Want, MS_Doing);
  46.     
  47.     var
  48.         newversion_callback : SIVCNewVersionCallBack;
  49.         getsocks_callback : SIVCGetSOCKSServerCallBack;
  50.         mcresult_callback : SIVCManualQueryCallBack;
  51.         state : SIVCState;
  52.         idle_til:longint;
  53.         use_socks:boolean;
  54.         sivc_dnr:Ptr;
  55.         sivc_port:integer;
  56.         sivc_addr: ipAddr;
  57.         socks_port: integer;
  58.         vers:versionRecord;
  59.         app_creator: string[4];
  60.         query_result:Handle;
  61.         manual_state:SIVCMaunalState;
  62.         timeout:longint;
  63.     
  64.     procedure ServerToHostPort(s:Str255; defport:integer; var host:Str255; var port:integer);
  65.         var
  66.             portstr:Str255;
  67.             n:longint;
  68.     begin
  69.         if Split(':', s, host, portstr) | Split(' ', s, host, portstr) then begin
  70.             StringToNum(portstr,n);
  71.             port := n;
  72.         end else begin
  73.             host := s;
  74.             port := defport;
  75.         end;
  76.     end;
  77.     
  78.     procedure GetSOCKSServer(var server:Str255);
  79.     begin
  80.         server := '';
  81.         if getsocks_callback <> nil then begin
  82.             getsocks_callback(server);
  83.         end;
  84.         if server = '' then begin
  85.             GetIndString(server,sivc_id,ord(SS_SOCKSServer));
  86.         end;
  87.     end;
  88.     
  89.     procedure ReleaseConnection;
  90.     begin
  91.         TransportAbortDNR(sivc_dnr);
  92.         TransportDestroy(tref);
  93.     end;
  94.  
  95.     function SendQuery:OSErr;
  96.         var
  97.             query:Str255;
  98.             count:integer;
  99.             err: OSErr;
  100.     begin
  101.         if (manual_state = MS_Doing) then begin
  102.             query := 'Query: ProductInfoManual';
  103.         end else begin
  104.             query := 'Query: ProductInfoAuto';
  105.         end;
  106.         query := concat(query, cr,
  107.                                 'Product: ', vers.name, cr,
  108.                                 'ProductID: macos:APPL/',app_creator,cr,
  109.                                 'Version: ',HexNN(longint(vers.numericVersion),8),cr,
  110.                                 cr);
  111.         count := MacToNet(@query[1],length(query));
  112.         
  113.         err := TransportSend(tref, @query[1], count);
  114.         SendQuery := err;
  115.     end;
  116.     
  117.     function SendSocks:OSErr;
  118.         var
  119.             query:SocksRecordSmall;
  120.     begin
  121.         query.version := socks_version;
  122.         query.cmd := socks_connect;
  123.         query.port := sivc_port;
  124.         query.ip := sivc_addr;
  125.         SendSocks := TransportSend(tref, @query, SizeOf(query));
  126.     end;
  127.     
  128.     function IsField(field:Str255; var line:Str255):Boolean;
  129.         var
  130.             s:Str255;
  131.     begin
  132.         IsField := false;
  133.         if IsPrefix(line, field) then begin
  134.             s := Trim(TPcopy(line, length(field)+1, 255));
  135.             if (s<>'') & (s[1] = ':') then begin
  136.                 line := Trim(TPcopy(s, 2, 255));
  137.                 IsField := true;
  138.             end;
  139.         end;
  140.     end;
  141.     
  142.     procedure ProcessResult;
  143.         var
  144.             hf:HandleFile;
  145.             line:Str255;
  146.             latest_version:longint;
  147.             query_interval, users:longint;
  148.             ver:NumVersion;
  149.             new:boolean;
  150.     begin
  151.         hf.data := query_result;
  152.         hf.pos := 0;
  153.         hf.crlf := CL_CR;
  154.         hf.error := noErr;
  155.         latest_version := -1;
  156.         while ReadFromHandleFile(hf, line) do begin
  157.             if IsField('ReleaseVersion', line) then begin
  158.                 latest_version := HexToNum(line);
  159.             end else if IsField('AutoQueryIntervalM', line) then begin
  160.                 StringToNum(line, query_interval);
  161.                 if (query_interval >= 1440) & (query_interval < 136800) then begin { 1 to 95 days }
  162.                     prefs.SetTagLong(PC_CheckSIVCPeriod, query_interval);
  163.                 end;
  164.             end else if IsField('UserCount',line) then begin
  165.                 StringToNum(line, users);
  166.                 prefs.SetTagLong(PC_SIVCUsers, users);
  167.             end;
  168.         end;
  169.         new := (latest_version > longint(vers.numericVersion));
  170.         line := '';
  171.         if (latest_version <> -1) then begin
  172.             ver := NumVersion(latest_version);
  173.             line:=concat(NumToStr(ver.majorRev),'.',
  174.                                 NumToStr(BAND(ver.minorAndBugRev div 16,$0F)),'.',
  175.                                 NumToStr(BAND(ver.minorAndBugRev,$0F))
  176.                                 );
  177.             if (ver.stage<>$80) or (ver.nonRelRev<>0) then begin
  178.                 case ver.stage of 
  179.                     $20:begin
  180.                         line:=concat(line,'d');
  181.                     end;
  182.                     $40:begin
  183.                         line:=concat(line,'a');
  184.                     end;
  185.                     $60:begin
  186.                         line:=concat(line,'b');
  187.                     end;
  188.                     $80:begin
  189.                         line:=concat(line,'f');
  190.                     end;
  191.                     otherwise begin
  192.                         line:=concat(line,'<',NumToStr(ver.stage),'>');
  193.                     end;
  194.                 end;
  195.                 if ver.nonRelRev <> 0 then begin
  196.                     line:=concat(line,NumToStr(ver.nonRelRev));
  197.                 end;
  198.             end;
  199.         end;
  200.         if (manual_state = MS_Doing) then begin
  201.             if mcresult_callback <> nil then begin
  202.                 mcresult_callback(noErr, new, query_result, line);
  203.                 mcresult_callback := nil;
  204.             end;
  205.         end else begin
  206.             if new & (newversion_callback <> nil) then begin
  207.                 newversion_callback(query_result, line);
  208.             end;
  209.         end;
  210.     end;
  211.     
  212.     function GetThisQuantum:longint;
  213.         var
  214.             date,first_checked_date,check_period: longint;
  215.     begin
  216.         GetDateTime(date);
  217.         prefs.GetTagLong(PC_FirstCheckSIVC,first_checked_date);
  218.         prefs.GetTagLong(PC_CheckSIVCPeriod,check_period);
  219.         GetThisQuantum := (date - first_checked_date) div 60 div check_period;
  220.     end;
  221.     
  222.     procedure IdleSIVC;
  223.         var
  224.             last_quantum:longint;
  225.             s:Str255;
  226.             err:OSErr;
  227.             socksresult:SocksRecordSmall;
  228.             space: packed array[1..256] of Byte;
  229.             count: integer;
  230.             tstate :TCPStateType;
  231.             date:longint;
  232.             received:longint;
  233.             result: OSStatus;
  234.             junk: OSErr;
  235.     begin
  236.         if (state <> ST_Finished) & ((manual_state <> MS_None) | (TickCount > idle_til)) then begin
  237.             err := noErr;
  238.             if (manual_state = MS_Want) & (state = ST_None) then begin
  239.                 manual_state := MS_Doing;
  240.             end;
  241.             if (state <> ST_None) & (state <> ST_SOCKS_DNR) & (TickCount > timeout) then begin
  242.                 err := -8;
  243.             end else if not prefs.GetTagBoolean(PC_UseSIVC) & (manual_state <> MS_Doing) then begin
  244.                 err := -4;
  245.             end else begin
  246.                 case state of
  247.                     ST_None: begin
  248.                         prefs.GetTagLong(PC_LastCheckSIVCQuantum,last_quantum);
  249.                         if (GetThisQuantum <> last_quantum) or (manual_state = MS_Doing) then begin
  250.                             SetHandleSize(query_result,0);
  251.                             GetSOCKSServer(s);
  252.                             use_socks := s<>'';
  253.                             GetIndString(s,sivc_id,ord(SS_Server));
  254.                             ServerToHostPort(s,sivc_default_port,s,sivc_port);
  255.                             if use_socks then begin
  256.                                 err := TransportNameToAddr(s, sivc_dnr);
  257.                                 state := ST_SOCKS_DNR;
  258.                             end else begin
  259.                                 timeout := TickCount + timeout_period;
  260.                                 err := TransportOpenActiveConnection(tref, concat(s, ':', NumToStr(sivc_port)), 0, 0);
  261.                                 if err = noErr then begin
  262.                                     err := TransportHandleTransfers(tref);
  263.                                 end;
  264.                                 state := ST_Connecting;
  265.                             end;
  266.                         end else begin
  267.                             err := -1;
  268.                         end;
  269.                     end;
  270.                     ST_SOCKS_DNR:begin
  271.                         TransportGetNameToAddrResult(sivc_dnr, result, nil, @sivc_addr, 1);
  272.                         case result of
  273.                             inProgress: begin
  274.                                 err := noErr;
  275.                             end;
  276.                             noErr: begin
  277.                                 timeout := TickCount + timeout_period;
  278.                                 GetSOCKSServer(s);
  279.                                 ServerToHostPort(s, socks_default_port, s, socks_port);
  280.                                 err := TransportOpenActiveConnection(tref, concat(s, ':', NumToStr(socks_port)), 0, 0);
  281.                                 if err = noErr then begin
  282.                                     err := TransportHandleTransfers(tref);
  283.                                 end;
  284.                                 state := ST_Connecting;
  285.                             end;
  286.                             otherwise begin
  287.                                 err := result;
  288.                             end;
  289.                         end;
  290.                     end;
  291.                     ST_Connecting:begin
  292.                         if not (TransportGetConnectionState(tref) in [T_WaitingForOpen, T_Bored, T_Opening]) then begin
  293.                             if TransportGetConnectionState(tref) = T_Established then begin
  294.                                 if use_socks then begin
  295.                                     err := SendSOCKS;
  296.                                     state := ST_SendSOCKS;
  297.                                 end else begin
  298.                                     err := SendQuery;
  299.                                     state := ST_SendQuery;
  300.                                 end;
  301.                             end else begin
  302.                                 err := -6;
  303.                             end;
  304.                         end;
  305.                     end;
  306.                     ST_SendSOCKS:begin
  307.                         if TransportGetConnectionState(tref) = T_Established then begin
  308.                             if TransportCharsAvailable(tref) >= SizeOf(socksresult) then begin
  309.                                 err := TransportReceive(tref, @socksresult, SizeOf(socksresult), received);
  310.                                 if (err = noErr) & (received <> SizeOf(socksresult)) &  (socksresult.cmd <> socks_result) then begin
  311.                                     err := -2;
  312.                                 end;
  313.                                 if err = noErr then begin
  314.                                     err := SendQuery;
  315.                                     state := ST_SendQuery;
  316.                                 end;
  317.                             end;
  318.                         end else begin
  319.                             err := -72;
  320.                         end;
  321.                     end;
  322.                     ST_SendQuery:begin
  323.                         tstate := TransportGetConnectionState(tref);
  324.                         count := Min(TransportCharsAvailable(tref),SizeOf(space));
  325.                         if (tstate <> T_Dead) & (tstate <> T_Bored) & ((tstate <> T_PleaseClose) | (count > 0))then begin
  326.                             if count>0 then begin
  327.                                 err := TransportReceive(tref, @space, count, received);
  328.                                 if err = noErr then begin
  329.                                     count := NetToMac(@space,received);
  330.                                     err:=PtrAndHand(@space,query_result,count);
  331.                                 end;
  332.                             end;
  333.                         end else begin
  334.                             if tstate = T_PleaseClose then begin
  335.                                 TransportSendClose(tref);
  336.                             end;
  337.                             GetDateTime(date);
  338.                             prefs.SetTagLong(PC_LastSIVC,date);
  339.                             ProcessResult;
  340.                             if (manual_state <> MS_Doing) then begin
  341.                                 prefs.SetTagLong(PC_LastCheckSIVCQuantum, GetThisQuantum);
  342.                             end;
  343.                             state := ST_WaitClose;
  344.                             junk := WritePrefsData;
  345.                         end;
  346.                     end;
  347.                     ST_WaitClose:begin
  348.                         tstate := TransportGetConnectionState(tref);
  349.                         if (tstate = T_Dead) or (tstate = T_Bored) then begin
  350.                             err := -3;
  351.                         end;
  352.                     end;
  353.                 end;
  354.             end;
  355.             if err <> noErr then begin
  356.                 ReleaseConnection;
  357.                 idle_til := TickCount + idle_til_period;
  358.                 state := ST_None;
  359.                 if (manual_state = MS_Doing) then begin
  360.                     manual_state := MS_None;
  361.                     if mcresult_callback <> nil then begin
  362.                         mcresult_callback(err, false, nil, '');
  363.                         mcresult_callback := nil;
  364.                     end;
  365.                 end;
  366.             end;
  367.         end;
  368.     end;
  369.     
  370.     procedure DieBadly(err:OSErr);
  371.     begin
  372.         if manual_state = MS_Doing then begin
  373.             manual_state := MS_None;
  374.             if mcresult_callback <> nil then begin
  375.                 mcresult_callback(err, false, nil, '');
  376.                 mcresult_callback := nil;
  377.             end;
  378.         end;
  379.         state := ST_None;
  380.     end;
  381.     
  382.     type
  383.         SIVCConnectionObject = object(ConnectionObject)
  384.             procedure Destroy;
  385.             override;
  386.             procedure Established;
  387.             override;
  388.         end;
  389.     
  390.     procedure SIVCConnectionObject.Established;
  391.         var
  392.             err:OSErr;
  393.     begin
  394.         if use_socks then begin
  395.             err := SendSOCKS;
  396.         end else begin
  397.             err := SendQuery;
  398.         end;
  399.         if err <> noErr then begin
  400.             DieBadly( err );
  401.             timetodie := true;
  402.         end;
  403.     end;
  404.     
  405.     procedure SIVCConnectionObject.Destroy;
  406.     begin
  407.         DieBadly(-3);
  408.         inherited Destroy;
  409.     end;
  410.     
  411.     type
  412.         SIVCAddressSearchObject = object(AddressSearchObject)
  413.             procedure FoundAddress (ip: longint);
  414.             override;
  415.             procedure Failed (oe: OSErr);
  416.             override;
  417.         end;
  418.     
  419.     procedure SIVCAddressSearchObject.FoundAddress (ip: longint);
  420.         var
  421.             s:Str255;
  422.             conn_obj:SIVCConnectionObject;
  423.     begin
  424.         GetSOCKSServer(s);
  425.         ServerToHostPort(s, socks_default_port, s, socks_port);
  426.         new(conn_obj);
  427.         conn_obj.NewActiveConnection( 0, s, socks_port );
  428.     end;
  429.     
  430.     procedure SIVCAddressSearchObject.Failed (oe: OSErr);
  431.     begin
  432.         DieBadly(oe);
  433.     end;
  434.     
  435.     procedure DoQuery( manual: Boolean );
  436.         var
  437.             s:Str255;
  438.             addr_obj:SIVCAddressSearchObject;
  439.             conn_obj:SIVCConnectionObject;
  440.     begin
  441.         if manual then begin
  442.             manual_state := MS_Doing;
  443.         end;
  444.         SetHandleSize(query_result,0);
  445.         GetSOCKSServer(s);
  446.         use_socks := s<>'';
  447.         GetIndString(s,sivc_id,ord(SS_Server));
  448.         ServerToHostPort(s,sivc_default_port,s,sivc_port);
  449.         if use_socks then begin
  450.             new(addr_obj);
  451.             addr_obj.FindAddress( s );
  452.         end else begin
  453.             new(conn_obj);
  454.             conn_obj.NewActiveConnection( 0, s, sivc_port );
  455.         end;
  456.         state := ST_Doing;
  457.     end;
  458.     
  459.     function CanManualQuery:Boolean;
  460.     begin
  461.         CanManualQuery := (manual_state = MS_None) & (state <> ST_Finished);
  462.     end;
  463.     
  464.     procedure ManualQuery(mcresult: SIVCManualQueryCallBack);
  465.     begin
  466.         if CanManualQuery then begin
  467.             mcresult_callback := mcresult;
  468.             if (state = ST_None) then begin
  469.                 DoQuery(true);
  470.             end else begin
  471.                 manual_state := MS_Want;
  472.             end;
  473.         end else begin
  474.             if mcresult <> nil then begin
  475.                 mcresult(aspServerBusy,false,nil,'');
  476.             end;
  477.         end;
  478.     end;
  479.  
  480.     procedure IdleSIVC;
  481.     begin
  482.         if (state = ST_None) then begin
  483.             if (manual_state = MS_Want) then begin
  484.                 DoQuery(true);
  485.             end else if prefs.GetTagBoolean( PC_UseSIVC ) then begin
  486.                 prefs.GetTagLong(PC_LastCheckSIVCQuantum,last_quantum);
  487.                 if (GetThisQuantum <> last_quantum) or (manual_state = MS_Doing) then begin
  488.                     DoQuery(false);
  489.                 end;
  490.             end;
  491.         end;
  492.     end;
  493.     
  494.     function InitSIVC(var msg: integer): OSStatus;
  495.         var
  496.             bndl:Handle;
  497.             date:longint;
  498.             junk: OSErr;
  499.     begin
  500. {$unused(msg)}
  501.         sivc_dnr := nil;
  502.         state := ST_None;
  503.         tref := nil;
  504.         idle_til := TickCount;
  505.         GetVersion(vers);
  506.         app_creator := '????';
  507.         bndl := Get1Resource('BNDL', 128);
  508.         if (bndl <> nil) & (bndl^ <> nil) & (GetHandleSize(bndl) >= 4) then begin
  509.             BlockMove(bndl^, @app_creator[1], 4);
  510.         end;
  511.         query_result:= NewHandle(0);
  512.         GetDateTime(date);
  513.         SetDefaultLong(PC_FirstCheckSIVC,date);
  514.         SetDefaultLong(PC_LastCheckSIVCQuantum,-1234);
  515.         SetDefaultLong(PC_CheckSIVCPeriod,10080); { 1 week }
  516.         SetDefaultLong(PC_LastSIVC,bad_date);
  517.         SetDefaultLong(PC_SIVCUsers,-1);
  518.         first_ever_sivc := not prefs.ExistsTag(PC_UseSIVC);
  519.         junk := WritePrefsData;
  520.         InitSIVC := noErr;
  521.     end;
  522.     
  523.     procedure FinishSIVC;
  524.     begin
  525.         ReleaseConnection;
  526.         state := ST_Finished;
  527.         DisposeHandle(query_result);
  528.     end;
  529.         
  530.     procedure ConfigureSIVC(newversion : SIVCNewVersionCallBack; getsocks:SIVCGetSOCKSServerCallBack);
  531.     begin
  532.         StartupSIVC;
  533.         newversion_callback := newversion;
  534.         getsocks_callback := getsocks;
  535.     end;
  536.     
  537.     procedure StartupSIVC;
  538.     begin
  539.         StartupTransport;
  540.         StartupTranslateISO;
  541.         SetStartup(InitSIVC, IdleSIVC, 10, FinishSIVC);
  542.     end;
  543.     
  544. end.
  545.