#!/bin/sh # MetaCard 2.4 stack # The following is not ASCII text, # so now would be a good time to q out of more exec mc $0 "$@"  evictionIon closestack set the cursor to busy save this stack end closestack b*Maladies contagieuses - Eviction scolaire UBritannic BoldUBritannic BoldU Futura Bk BTU Futura Md BTU Futura Md BTU helveticaU helveticaU helveticaU helveticaUCourierUArial*Maladies contagieuses : Eviction scolaire PZon preOpenStack start using "Execution Error" start using "libURL" end preOpenStack  @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @com2i evict.gif @.GIF89aHtHHHtHtttHHHHHHtHHHtHߜHtHtHHtHHtߜߜ!,@CH*\ȰÇ#JHŋ3jȱǏ CIɓ(S`˗0cʜI–qɳϟ@w:4NE ]AC@85*ӉU+A(MzU$N-6EUOʕaUo֝[},x/a%7svl_ȅ>6rX#!o6ddGKEj||Zsiڑߖzc^%Ofzؓ,P#LسkzuOsuӬK}rb3%9ײ絳특}./hIBp-h4%qiݲJ5Qd! 㦬]#Wr1ZF|>uS:՘c5YMֶNSs8\)}ca?Ɩ2]e3~-m/Sat}ksFP-8Gqr. o2jf3)u̝JCL ִNt <@ʶ;e1"NM]eKVLj '2UƲ$&0ɱ̖D=77{) 3IrE%̤wE@]>wJֳh@'I,B0QelW03%$*c{LԕIca['KP[grvtDi;%勞+m^1qQy>!4?htvLRs=jGO|GOЏOꓫϾ_PQ"I0Q{\[Iۄ!rS?)_%Tg "7K~?u7F~:wZ (lOƁ:gTOEBa"4DyE9@ 4Y F>8`?=8XAs 6B?(uTW< Z^i_U+|MHnhӑ!ՆW^x9zE[lHZ`CZVuY"W<'^8iw8[1XgxSW{Ӈ2E*uY2U؂%V xMSahZgvHYU\xVUR]aHVe[jCFȋEh@Ljq)WXLw „ȂJ!XxOb_f& (7{x Ґ))%ꓑ$ !yF1* )ْe0R,9 S6Ɏ2~.B &AZFHz*;) ؤRjSJZxiĈw\ڊTZ_jqo`Y`$Dp(a(jɛ ZX}D[x#a|H }zmJ`A AnڟWڙYjʥ0*nmmmZm*mllljl:lkkkjk:kZêjzj:jˊihϊh:*hg٪jg:g gffښݺJf fzl(fu8a t+3y|oo/y' u^t Vbpp2KN#K>QyץNvasdt0w 'waIQnN26!GsigL!+a#w35f18s# 1 then answer "Voulez-vous supprimer cette fiche ?" with "Oui" or "Non" if it is "Oui" then visual effect zoom in delete this card end if else answer "Impossible de supprimer cette fiche !" end if end mouseUp DPfR@0Supprimer fiche Nouvelle maladieADon mouseUp Ask "Entrez le terme recherch :" find it end mouseUp DPR@0 Recherche Nouvelle maladieAHon mouseUp visual effect barn door close go to prev card end mouseUp DPR@0Fiche prcdente Nouvelle maladieAGon mouseUp visual effect barn door open go to next card end mouseUp DP0R@0Fiche suivante Nouvelle maladieASon mouseUp Answer "Ce logiciel a t ralis par Dr. Ghazi CHERIF." end mouseUp DPrR@0 A propos...  Moved Icons@@  @H @I @J @K @ @ @ @ @ @ @ @Hi328 Dffffff00 S8`%B" 0_8ppq9px?W  p@H@D@B@A@@@@ c?6σ???Ii329 Dffffff00 QaUuJi330 Dffffff00 b 0   ``b x\ p@@@{?><<~Ki331 Dffffff00 `k`@@@@@@@@@@@@@@@@@@@@@ D````Ș``Ș0000``00  6 7o$$$$$ |||"_ @@@@@@@@@@@@@@@@   @@@o   I I I I I I!@"5 @ 0i@@@@@@@?  @?? D Ș@@@@@@Ș``````0000``00 23"P"P"PB$"`wPB"` q PB"vw PB"`qw h P""pwP"qwP"qwhP" WUWUWUwhP"whP"whP"WUWUWwhP"whP"whP"WUWUw hP"BDwhP"whP" WUuUuUwhP"wP"wP"`w h P"DvhP"`f P"P"P"P DPU D Ș@@@@@@Ș``````0000``00 23"P"P"PB$"`wPB"` q PB"vw PB"`qw h P""pwP"qwP"qwUuwhP"wWuwUwhP"wWuwUwhP"wUwhP"wWuwhP"wUwhP"wWuwhP"wWuw hP"BDwhP"wWuwhP"wWuwhP"wP"wP"`w h P"DvhP"`f P"P"P"P DPU DȘ``@@@@@@PPPPPP00 @`  00  aC‚Â  @` 00 `@X@ H @@ @@ | 008,8,<\<\>>?|?|?? ? ??j  @@:@ @ ?@@ ????? Dxxxx||xx00  @  @@@@@@   @|B?>????>?e8x`?P@>||??||>@~??? Dxx||xx00  @@@@ <x <8H @ @@@  }??????&??????????@Cp@  @    `???x8 Dxx||xx00  @@@@ <x <8[  ( @$@  |*?????@p@  @    `D0<<???x8 Dxx||xx||xx00 z  @@  @@@ ??pp(xx||~~???K@ @  @@  @@  | 0  ``00  ?????a Ask Dialogron openCard end openCard on preOpenCard end preOpenCard on closeCard end closeCard on openStack end openStack @macintoshIcons992,993,994,995 motifIcons328,329,330,331windows95Icons996,997,998,999 U HelveticaU helvetica PJon doresize local twidth, iwidth, bwidth put the width of this stack into twidth if the visible of button 1 then put 48 into bwidth else put 16 into bwidth set the width of field 1 to twidth - (bwidth + 16) set the left of field 1 to bwidth set the width of field 2 to twidth - (bwidth + 16) set the left of field 2 to bwidth set the top of field 2 to the bottom of field 1 set the top of button 1 to the height of field 1 div 2 - 8 put (twidth - 120 ) div 3 into iwidth put iwidth into twidth set the default of button 2 to false repeat with i = 2 to the number of buttons set the left of button i to twidth set the bottom of button i to the height of this stack - 12 add the width of button i + iwidth to twidth end repeat set the default of button 2 to true end doresize on star local tstring put empty into tstring repeat with i = 1 to the number of characters in field 3 put "*" after tstring end repeat put tstring into field 2 end star on preOpenStack local twidth, dtype, foffset set the itemDelimiter to numToChar(0) put word 2 of item 1 of the dialogData into dtype set the fieldmode of me to dtype if dtype is "plain" or dtype is "password" or dtype is "clear" then hide button 1 put 0 into foffset else show button 1 switch the lookAndFeel case "Motif" get the motifIcons of this stack break case "Macintosh" case "Appearance Manager" get the macintoshIcons of this stack break default get the windows95Icons of this stack end switch set the itemDelimiter to comma set the icon of button 1 to item itemOffset(dtype, "error,information,question,warning") of it set the itemDelimiter to numToChar(0) put 40 into foffset end if if item 2 of the dialogData is empty then set the title of this stack to space else set the title of this stack to item 2 of the dialogData put item 3 of the dialogData into field 1 put max(the formattedWidth of field 1 + foffset + 24,\ the formattedWidth of field 2 + foffset + 24, 320) into twidth set the width of this stack to twidth set the height of field 1 to the formattedHeight of field 1 set the top of field 1 to 8 set the height of this stack to (the height of field 1) + 100 doresize if the fieldmode of me is "password" or the fieldmode of me is "clear" then put item 4 of the dialogData into field 3 star else put item 4 of the dialogData into field 2 set the dialogData to numToChar(0) set the itemDelimiter to comma end preOpenStack on keyDown which local tpos if the name of the target contains "field" \ and (the fieldmode of me is "password" or the fieldmode of me is "clear") then put the selectedChunk into tpos put which into character (word 2 of tpos) to (word 4 of tpos) of field 3 star select after character (word 2 of tpos) of field 2 else pass keyDown end keyDown on deleteKey if the fieldmode of me is "password" or the fieldmode of me is "clear" then deleteone else pass deleteKey end deleteKey on backspaceKey if the fieldmode of me is "password" or the fieldmode of me is "clear" then deleteone else pass backspaceKey end backspaceKey on deleteone local tpos put word 2 of the selectedChunk into tpos put empty into character (tpos - 1) of field 3 star select before character (tpos - 1) of field 2 end deleteone on commandKeyDown which if the fieldmode of me is "password" or the fieldmode of me is "clear" then local tpos switch which case "D" put word 2 of the selectedChunk into tpos put empty into character tpos of field 3 star select before character tpos of field 1 break case "H" deleteone break default pass commandKeyDown end switch else pass commandKeyDown end commandKeyDown on openField select the text of the target end openField on resizeStack doresize end resizeStack on returnInField click at the loc of button "OK" end returnInField on closeStack put empty into field 1 put empty into field 2 put empty into field 3 end closeStack @ fieldmodeplaina_\]`   \OKLpon mouseUp switch the fieldmode of this card case "clear" get field 3 break case "password" get mcencrypt(field 3) break default get field 2 break end switch set the dialogData to it close this stack end mouseUp B\4 ]CancelDp+on mouseUp close this stack end mouseUp \<  _`(  ` !`b8|  a New Button@@$( Answer Dialogon resizeStack end resizeStack on openStack end openStack on preOpenCard end preOpenCard on openCard end openCard on closeCard end closeCard /dmacintoshIcons992,993,994,995 motifIcons328,329,330,331windows95Icons996,997,998,999 U HelveticaU helvetica P Ron preOpenStack local dtype, foffset, oldwidth, bwidth, twidth, iwidth, theight, curx, nchoices set the itemDelimiter to numToChar(0) put word 2 of item 1 of the dialogData into dtype if dtype is "plain" then hide button 1 put 0 into foffset else show button 1 switch the lookAndFeel case "Motif" get the motifIcons of this stack break case "Macintosh" case "Appearance Manager" get the macintoshIcons of this stack break default get the windows95Icons of this stack end switch set the itemDelimiter to comma set the icon of button "icon" to item itemOffset(dtype, "error,information,question,warning") of it set the itemDelimiter to numToChar(0) put 40 into foffset end if if item 2 of the dialogData is empty then set the title of this stack to space else set the title of this stack to item 2 of the dialogData put item 3 of dialogData into field 1 get item 4 of dialogData if it is empty then get "OK" put the number of lines in it into nchoices put 32 into bwidth if nchoices > the number of buttons - 1 then put the number of buttons - 1 into nchoices repeat with i = 2 to nchoices + 1 show button i set the name of button i to line nchoices + 2 - i of it set the width of button i to the formattedWidth of button i + 24 add the width of button i + 32 to bwidth end repeat set the dontWrap of field 1 to true put max(the formattedWidth of field 1 + foffset + 16, bwidth) into twidth if twidth > 600 then put 600 into twidth set the dontWrap of field 1 to false end if put the width of this stack into oldwidth set the width of this stack to twidth set the width of field 1 to twidth - foffset - 16 put the formattedHeight of field 1 + 68 into theight if theight > 400 then set the vScrollbar of field 1 to true put 400 into theight else set the vScrollbar of field 1 to false set the height of this stack to theight set the height of field 1 to theight - 68 set the top of button 1 to the height of field 1 div 2 - 12 set the topLeft of field 1 to foffset + 8, 8 put (twidth - bwidth) div (nchoices + 1) + 32 into iwidth put iwidth into curx if the lookAndFeel is "Macintosh" or the lookAndFeel is "Appearance Manager" then repeat with i = nchoices + 1 down to 2 set the left of button i to round(curx) add the width of button i + iwidth to curx set the bottom of button i to the height of this stack - 16 end repeat else repeat with i = 2 to nchoices + 1 set the left of button i to round(curx) add the width of button i + iwidth to curx set the bottom of button i to the height of this stack - 16 end repeat end if set the default of button 2 to true set the dialogData to empty end preOpenStack on closeStack repeat with i = 3 to the number of buttons hide button i end repeat set the default of button 2 to false end closeStack on mouseUp if the name of the target contains "button" then set the dialogData to the short name of the target close this stack end if end mouseUp /dz @  0Ce logiciel a t ralis par Dr. Ghazi CHERIF.ziconBPon mouseUp end mouseUp ((H OKD`~63  Do it for meD`'lc YesD`69 zD`4' yD`4' xD`i4' wD` 4)  Message Boxcs%go "/home/raney/cragg/liburl_1010.mc"color SU HelveticaUCleanU HelveticaW HelveticaU HelveticaU HelveticaU HelveticaW HelveticaW HelveticaU Helvetica U Helvetica W HelveticaU HelveticaUCourierWCourierU Helvetica U Helvetica U HelveticaW HelveticaU HelveticaU Helvetica@U HelveticaU HelveticaAW HelveticaW HelveticaW HelveticaPW HelveticaTW HelveticaU HelveticaU Helvetica U Helvetica UCourier UCourier UCourierU LucidaBrightUSymbolUcharter U HelveticaULucida ULucida UClean UCourierUfixedUtimes U HelveticaU Font|cleanUFontU SuperscriptUColor|-UColor Ucharter WLucida WLucida WcleanW Helvetica UClean WClean W HelveticaU HelveticaW Helvetica@U HelveticaDU HelveticaHU HelveticaWcharterUcharterU HelveticaUcharterW HelveticaUnilUcharterU HelveticaUfixedU fangsong ti!U HelveticaU helveticaU helveticaU helveticaU helveticaU helveticaU helveticaU helveticaU helvetica U helveticaMessage Box Card P,local initted on resizeStack set the rect of field 1 to the rect of me end resizeStack on preOpenCard if not initted then set the topleft of this stack to max(0, the left of the topStack -\ (the width of this stack - the width of the topStack) div 2), \ min(the bottom of the topStack + 32, item 4 of the windowBoundingRect - 32) send "init" to field 1 put true into initted end if end preOpenCard on closeCard put empty into field 1 end closeCard on changed which, old, new put new into field 1 of me end changed  Message Field)p .local MessageBoxHistory, MessageBoxIndex on init put 1 into MessageBoxIndex put empty & return into MessageBoxHistory put empty into field 1 end init on errorDialog eerror, perror if perror is not empty then set the scripterror of card 1 of stack "Script Error" to perror modeless "Script Error" else set the errorobject of card 1 of stack "Execution Error" to the long id of the target set the executionerror of card 1 of stack "Execution Error" to eerror modeless "Execution Error" send "refresh" to card 1 of stack "Execution Error" end if end errorDialog on returnInField lock error dialogs if me is empty then exit to MetaCard if the traceStack is not empty then set defaultStack to the traceStack else set defaultStack to the topStack set the cs of stack "Message Box" to me put return after MessageBoxHistory put the cs of stack "Message Box" into the last line of MessageBoxHistory if the number of lines in MessageBoxHistory > 20 then delete line 1 of MessageBoxHistory put empty into msg put 1 into MessageBoxIndex if the number of lines in field 1 of stack "Execution Contexts" is not 0 then get the hilitedLine of field 1 of stack "Execution Contexts" if it is empty then get the number of lines of field 1 of stack "Execution Contexts" set the debugContext to line it of field 1 of stack "Execution Contexts" end if if word 1 of the cs of stack "Message Box" is not among the lines of the commandNames then if word 1 of the cs of stack "Message Box" is "the" \ or word 1 of the cs of stack "Message Box" is a number \ or token 2 of the cs of stack "Message Box" is "(" then put value(the cs of stack "Message Box", this card) else send the cs of stack "Message Box" to this card else if the number of lines in field 1 of stack "Execution Contexts" is 0 then do "global" && the globals & return & the cs of stack "Message Box" \ & return & "if the result is not empty then put the result" else debugdo the cs of stack "Message Box" & return & "if the result is not empty then put the result" end if unlock error dialogs end returnInField on prevline subtract 1 from MessageBoxIndex if MessageBoxIndex is 0 then put the number of lines in MessageBoxHistory into MessageBoxIndex put line MessageBoxIndex of MessageBoxHistory into me exit to MetaCard end prevline on nextline add 1 to MessageBoxIndex if MessageBoxIndex > the number of lines in MessageBoxHistory then put 1 into MessageBoxIndex put line MessageBoxIndex of MessageBoxHistory into me exit to MetaCard end nextline on commandKeyDown which handleKey which pass commandKeyDown end commandKeyDown on controlKeyDown which handleKey which pass controlKeyDown end controlKeyDown on handleKey which if which is "P" then prevline if which is "N" then nextline if which is "U" then put empty into msg exit to MetaCard end if end handleKey on arrowKey which if which is "up" then prevline if which is "down" then nextline pass arrowKey end arrowKey @   Execution Erroron errorDialog which put which set the executionerror of card 1 of stack "Execution Error" to which modeless "Execution Error" send "refresh" to card 1 of stack "Execution Error" end errorDialog y U HelveticaU helveticaU helveticaU helveticaU helveticaU helveticaU helveticaU helveticaU helveticaeExecution Error Card p local ee, ec, er, eo, ei, et on returnInField send "mouseUp" to button "Ignore" end returnInField on returnKey send "mouseUp" to button "Ignore" end returnKey on closeCard set the errorobject of me to empty set the executionerror of me to empty put empty into ee put empty into field "Error Message" put empty into field "Object" put empty into field "Bad Token" put 0 into field "Line" put 0 into field "Column" end closeCard on preOpenCard set the loc of this stack to the screenLoc end preOpenCard on refresh local lc, em, tei, teo, ter, tec put empty into ei put empty into eo put empty into er put empty into ec put empty into et put empty into field "Error Message" put the executionerror of me & cr after ee put the number of lines in ee into lc if lc > 100 then delete line 100 to lc of ee if lc < 2 or the number of items in ee < 6 then hide button "Script..." hide button "Debug..." put "thrown error" & cr into field "Error Message" end if repeat with i = the number of lines in ee down to 1 get item 1 of line i of ee put line it of field "Messages" into em if em is "Object Name:" then put item 4 of line i of ee into tei put the long name of tei into teo else put em & cr before field "Error Message" if item 2 of line i of ee is not 0 then put item 2 of line i of ee into ter put item 3 of line i of ee into tec end if put tei & cr before ei put teo & cr before eo put ter & cr before er put tec & cr before ec put item 4 of line i of ee & cr before et end if end repeat delete last char of field "Error Message" seterror 1 set the hilitedLines of field 1 to 1 end refresh on openCard set the hilitedLines of field 1 to 1 end openCard on openStack end openStack on preOpenStack end preOpenStack on openBackground end openBackground on preOpenBackground end preOpenBackground on seterror which if line which of eo contains quote & "Message Field" & quote\ or "mctools.mc" is not in the frontscripts \ or word 1 of the mainStacks is not "Home" then hide button "Script..." hide button "Debug..." else show button "Script..." show button "Debug..." end if put line which of eo into field "Object" put line which of er into field "Line" put line which of ec into field "Column" put line which of et into field "Bad Token" set the errorobject of me to line which of ei end seterror  errorobjectexecutionerror     Messages@ | e /Handler: Running low on memory, script aborted (recursionLimit: Recursion limit reached abs: error in source expression accept: bad expression &aclip: playLoudness is not an integer !acos: error in source expression acos: domain error add: error in matrix operation -add: destination has a bad format (numeric?) add: error in source expression add: can't set destination add: can't add array to scalar )aliasReference: error in file expression %Operators and: error in left operand &Operators and: error in right operand (Operators bitAnd: error in left operand )Operators bitAnd: error in right operand $annuity: error in period expression "annuity: error in rate expression %answer: error in question expression %answer: error in response expression "answer: error in title expression split: error in expression (arrowKey: error in direction expression arrowKey: not a direction !asin: error in source expression asin: domain error "ask: error in question expression ask: error in reply expression ask: error in title expression !atan2: error in first expression "atan2: error in second expression atan2: domain error !atan: error in source expression atan: domain error $average: error in source expression )base64Decode: error in source expression )base64Encode: error in source expression "baseConvert: bad destination base (baseConvert: error in source expression baseConvert: bad source base 'baseConvert: can't convert this number (baseConvert: destination is not base 10 beep: error in expression ,binaryDecode: destination is not a variable )binaryDecode: invalid data for parameter $binaryDecode: not enough parameters )binaryDecode: error in source expression )binaryEncode: invalid data for parameter $binaryEncode: not enough parameters )binaryEncode: error in source expression !Button: bad accelerator modifier !Button: family is not an integer %Button: menuButton is not an integer &Button: menuHistory is not an integer $Button: menuLines is not an integer #Button: mnemonic is not an integer %cancel: message id is not an integer &charToNum: error in source expression choose: error in expression choose: not a tool &Chunk: error in background expression Chunk: error in card expression Chunk: error in character range *Chunk: container is not a button or field !Chunk: error in chunk expression Chunk: error in item range Chunk: error in line range "Chunk: error in object expression %Chunk: error in range end expression 'Chunk: error in range start expression !Chunk: error in stack expression Chunk: error in text string Chunk: can't separate tokens Chunk: can't separate words Chunk: can't delete object Chunk: can't find object #Chunk: can't get object attributes 0Chunk: can't get value of destination container Chunk: can't get number Chunk: can't get source string Chunk: can't get substring Chunk: can't find substring Chunk: can't set attributes ,Chunk: can't store to destination container Chunk: can't set as a number Chunk: can't find background Chunk: can't find card Chunk: no such object Chunk: can't set property Chunk: can't find stack Chunk: no target found +Chunk: can't select object that isn't open !Chunk: source is not a container 'Chunk: can't find object to store into 'Chunk: can't get source from container &Chunk: destination is not a container click: script aborted )click: expression is not a button number !click: error in point expression !click: expression is not a point click: stack is not open clone: error in name expression clone: can't clone this object clone: stack is locked "clone: can't find object to clone close: error in name expression close: can't find stack #color: error setting selectedColor "compact: can't find stack to save compact: object is not a stack &compound: error in periods expression #compound: error in rate expression %compress: error in source expression ,compress: error occurred during compression $Operators &&: error in left operand %Operators &&: error in right operand #Operators &: error in left operand $Operators &: error in right operand *Operators contains: error in left operand +Operators contains: error in right operand #convert: can't read from container convert: can't set container !copy: invalid destination object $copy: can't find destination object copy: can't copy source object copy: can't find source object "copy: stack is password protected cos: error in source expression cos: domain error 5create: error in bad parent or background expression !create: error in name expression &create: error in file name expression %create: stack is locked (cantModify) crop: error in image expression crop: object is not an image $crop: error in rectangle expression $crop: expression is not a rectangle cut: can't find or copy object 'decompress: error in source expression *decompress: string is not compressed data 'decompress: error during decompression -delete: error in file or url name expression delete: can't find object disable: can't find object ,Stack: stack has not been given a file name "divide: error in matrix operation 0divide: destination has a bad format (numeric?) #divide: error in source expression divide: can't set destination %divide: can't divide scalar by array divide: range error (overflow) divide: divide by zero )Operators div: error in matrix operation %Operators div: error in left operand &Operators div: error in right operand -Operators div: can't divide scalar by matrix &Operators div: range error (overflow) Operators div: divide by zero do: aborted do: error in source expression do: error in statement do: error in expression !do: error in language expression 0do: unexpected end of line in source expression do: can't find command do: not a command do: license limit exceeded doMenu: error in expression "doMenu: don't know this menu item drag: script aborted drag: bad "button" number drag: bad end point expression drag: end point is not a point !drag: bad start point expression !drag: start point is not a point &driverNames: error in type expression !drives: error in type expression edit: can't find object $encrypt: error in source expression Operators =: error in operand "exp10: error in source expression exp10: domain error !exp1: error in source expression exp1: domain error !exp2: error in source expression exp2: domain error 5export: error in file (or mask file) name expression 'export: can't open file (or mask file) 5export: can't write to file, mask file, or container -export: no image selected, or image not open (export: selected object is not an image $Expression: error in numeric factor #Expression: error in string factor exp: error in source expression exp: domain error &extents: error in variable expression Factor: error in left operand Factor: error in right operand Field: bad text attributes %Field: hilitedLine is not an integer (Field: scrollbarWidth is not an integer Field: shift is not an integer *Field: tabstops is not a positive integer 2files: no permission to list files or directories filter: bad source string filter: bad pattern string filter: can't set destination find: bad source string flip: can't find image flip: object is not an image flushEvents: bad event type focus: not a valid control $fontNames: error in type expression fontSizes: bad font name fontStyles: bad font name fontStyles: bad font size 0format: bad format string or parameter mismatch $Function: error in function handler %Function: error in source expression !Function: source is not a number Function: is not a number get: error in expression get: can't set destination %globalLoc: coordinate is not a point #go: error in background expression go: error in card expression go: error in stack expression go: error in window expression *go: can't attach menu to this object type go: can't find destination grab: can't find object graphic: not an integer Operators >=: error in operands Operators >: error in operands Group: backSize is not a point 'Group: hilitedButton is not an integer Group: bad object type %Operators (): error in right operand Handler: aborted Handler: error in statement 'Handler: error in parameter expression %Handler: not a valid parameter index !hasMemory: bad amount expression (hide: error in visual effect expression hide: can't find object (hostAddress: error in socket expression /hostAddressToName: error in address expression #hostName: error in name expression ,hostNameToAddress: error in name expression if-then: aborted 'if-then: error in condition expression if-then: error in statement Image: bad pixmap id !Image: hotspot is not an integer Image: id is not an integer .Image: id is already in use by another object $Image: image must be open to set id #Image: hotSpot x is not an integer #Image: hotSpot y is not an integer import: error in expression .import: can't open file, mask file or display .import: can't read file, mask file or display 1import: destination stack is locked (cantModify) insert: can't find object insert: license limit exceeded intersect: two objects required $Operators is: error in left operand %Operators is: error in right operand %Operators is: can't compare operands 6Operators is: left operand of 'within' is not a point ;Operators is: right operand of 'within' is not a rectangle %isNumber: error in source expression "isoToMac: error source expression #Operators ,: error in left operand $Operators ,: error in right operand "keys: parameter is not a variable kill: no such process kill: bad number (launch: error in application expression #length: error in source expression Operators <=: error in operands Operators <: error in operands ln1: error in source expression ln1: domain error ln: error in source expression ln: domain error load: error in url expression "load: error in message expression $localLoc: coordinate is not a point "log10: error in source expression log10: domain error !log2: error in source expression log2: domain error 'longFilePath: error in file expression "macToIso: error source expression mark: bad card expression mark: error in find expression +matchChunk: can't set destination variable %matchChunk: bad or missing parameter (matchChunk: error in pattern expression 'matchChunk: error in source expression (matrix: range error in matrix operation +matrixMultiply: error in source expression ,matrixMultiply: can't multiply these arrays max: error in source expression *MCISendString: error in source expression &MD5digest: error in source expression #median: error in source expression "merge: error in source expression .Operators -: can't subtract array from scalar #Operators -: error in left operand $Operators -: error in right operand 7Operators -: range error (overflow) in array operation $Operators -: range error (overflow) min: error in source expression )Operators mod: error in matrix operation %Operators mod: error in left operand &Operators mod: error in right operand -Operators mod: can't divide scalar by matrix &Operators mod: range error (overflow) Operators mod: divide by zero "mouse: error in source expression move: script aborted move: can't find object move: bad end point expression move: bad duration expression move: duration is not a number move: end point is not a point !move: bad start point expression !move: start point is not a point $multiply: error in matrix operation 2multiply: destination has a bad format (numeric?) %multiply: error in source expression multiply: can't set destination )multiply: can't multiply scalar by array !multiply: range error (overflow) Operators <>: error in operands &Operators not: error in right operand )Operators bitNot: error in right operand &numToChar: error in source expression !Object: bad textAlign expression Object: unknown color Object: error in colors =Object: can't set layer (card not open, or control in group) Object: not a textStyle 6Object: stack locked, or object's script is executing +Object: object does not have this property !Object: height is not an integer Object: layer is not an integer !Object: margin is not an integer /Object: value is not a boolean (true or false) Object Name: #Object: property is not an integer "Object: coordinate is not a point )Object: rectangle does not have 4 points Object: no Home stack &Object: pixel value is not an integer !Object: pixmap is not an integer /Object: can't set script while it is executing Object: can't set this property %Object: textheight is not an integer #Object: textsize is not an integer )offset: error in start offset expression !offset: error in part expression "offset: error in whole expression "open: error in message expression open: error in name expression /open: no permission to open files or processes $Operators or: error in left operand %Operators or: error in right operand 'Operators bitOr: error in left operand (Operators bitOr: error in right operand 'Operators /: error in matrix operation #Operators /: error in left operand $Operators /: error in right operand +Operators /: can't divide scalar by matrix $Operators /: range error (overflow) Operators /: divide by zero param: error in expression param: bad parameter index "param: error in source expression param: is not a number $paste: stack is locked (cantModify) (peerAddress: error in socket expression =place: group is not in this stack or is already on this card place: can't find group place: can't find card place: source is not a group !place: destination is not a card $play: can't get sound or movie name play: bad movie location play: bad movie options #Operators +: error in left operand $Operators +: error in right operand $Operators +: range error (overflow) pop: can't set destination post: can't get source post: can't get destination pow: error in left operand pow: error in right operand pow: range error (overflow) ,print: can't get 'from' or 'to' coordinates !print: can't get number of cards print: can't get rectangle print: error printing 'print: error writing file (disk full?) print: coordinate not a point %print: expression is not a rectangle print: not a card .print: card or stack must be open to print it print: no card specified arcAngle: not an integer blinkRate: not a number penColor: bad color "colormap: bad color name or value )Object: error counting objects as number 'Object: error counting objects as text dragSpeed: not a number effectRate: not a number extendKey: not a number Property: bad array expression gridSize: not an integer idleRate: not a number lineSize: not an integer moveSpeed: not a number multiSpace: not a number polySides: not an integer repeatDelay: not a number repeatRate: not a number !doubleClickDelta: not an integer doubleClickTime: not a number roundRadius: not an integer slices: not an integer startAngle: not an integer traceDelay: not a number traceStack: not a stack name print: bad property value syncRate: not a number tooltipDelay: not a number typeRate: not a number userLevel: not an integer beep: not an integer brush: not an integer brush: can't find image #brushPattern: not a valid image id brushPattern: can't find image "Object: no object to set property "Object: can't set object property cursor: not an integer cursor: can't find image 5Property: value is not a boolean ("true" or "false") Property: value is not a number defaultStack: can't find stack !defaultMenuBar: can't find group $Object: does not have this property #Object: property is not an integer !penPattern: not a valid image id penPattern: can't find image 'randomSeed: property is not an integer socketTimeout: not a number "umask: property is not an integer push: object is not a card push: can't find card put: error in expression put: can't set destination put: can't put into destination *queryRegistry: error in source expression #random: error in source expression read: aborted read: error in 'at' expression $read: error in condition expression read: error in count expression read: error reading read: count is not an integer "read: error in 'until' expression read: file is not open read: error in 'for' expression read: process is not open !record: error in file expression -recordCompression: type must be 4 characters 'recordInput: type must be 4 characters remove: can't find object remove: object is not a group remove: object is not a card #rename: error in source expression (rename: error in destination expression repeat: aborted ,repeat: error in 'for' condition expression repeat: error in statement .repeat: error in 'until' condition expression .repeat: error in 'while' condition expression 1repeat: error in 'with' end condition expression 3repeat: error in 'with' start condition expression 2repeat: error in 'with' step condition expression &repeat: error setting 'with' variable replace: can't set container %replace: error in pattern expression )replace: error in replacement expression 'replace: error in container expression replaceText: bad parameter replaceText: bad source string #reply: error in keyword expression #reply: error in message expression %request: error in keyword expression %request: error in message expression %request: error in program expression 'request: no permission to request that "getResources: error in expression (getResources: no permission to get that return: error in expression revert: can't revert Home stack #rotate: error in object expression (rotate: object is not an editable image "rotate: error in angle expression +round: error in source or digit expression $save: error in file name expression save: saving disabled save: can't find stack to save save: object is not a stack $seek: error in file name expression !seek: error in offset expression seek: file is not open select: can't select target 3selectedChunk: error in button or field expression &selectedButton: bad family expression -selectedButton: bad parent object expression )send: error in message handler execution "send: error in message expression send: error in 'in' expression "send: error in program expression send: bad target expression !send: no permission to send that set: error in source expression set: can't set property 2setRegistry: no permission to get or set registry (setRegistry: error in source expression shell: aborted shell: can't run shell command "shell: error in source expression %shell: no permission to run commands (shortFilePath: error in file expression (show: error in visual effect expression #show: error in location expression *show: error in number of cards expression )show: location is not in proper x,y form show: can't find object sin: error in source expression sin: domain error sort: can't find object to sort sort: error sorting sort: can't find field ,specialFolderPath: error in type expression !sqrt: error in source expression sqrt: domain error Stack: bad decoration 4Stack: invalid id (must be greater than current id) Stack: invalid key Stack: bad substack name ,Stack: can't set mainStack (has substacks?) "Stack: deskIcon is not an integer #Stack: userLevel is not an integer Stack: size is not an integer #Stack: stack is password protected Stack: can't find mainStack Stack: stack is not a mainStack *Stack: error in external function handler start: can't find object start: stack is locked !start: expression is not a group start: license limit exceeded $Handler: error in source expression Handler: can't find handler stdDev: error in expression stop: error in expression stop: target is not a group $subtract: error in matrix operation 2subtract: destination has a bad format (numeric?) %subtract: error in source expression subtract: can't set destination +subtract: can't subtract array from scalar subwindow: error in expression &subwindow: can't find stack or button sum: error in source expression &switch: error in condition expression !switch: error in case expression switch: error in statement !textHeightSum: can't find object tan: error in source expression tan: domain error "there: error in source expression "throw: error in source expression 'Operators *: error in matrix operation #Operators *: error in left operand $Operators *: error in right operand $Operators *: range error (overflow) $toLower: error in source expression %topStack: error in source expression $toUpper: error in source expression $transpose: source is not a variable &transpose: can't transpose this array "trunc: error in source expression try: error in statement type: script aborted type: bad string expression ungroup: can't find group ungroup: target is not a group (uniDecode: error in language expression &uniDecode: error in source expression (uniEncode: error in language expression &uniEncode: error in source expression unload: error in url expression *unlock: expression is not a visual effect &urlDecode: error in source expression &urlEncode: error in source expression #urlStatus: error in url expression "value: error in source expression "value: error executing expression value: can't find object Array: bad index expression Chunk: source is not a number !Chunk: source is not a character visual: bad effect expression wait: aborted wait: error in expression !wait: expression is not a number within: can't find control within: not a point write: error in expression (Operators bitXor: error in left operand )Operators bitXor: error in right operand  Ignore pfon mouseUp close this stack set the traceAbort to true set the traceReturn to true end mouseUp 0|D e Perror Field 0H   8< e Object: Script...p7on mouseUp get the long id of the errorobject of this card set the history[it] of stack "Script Editor" to \ format("char %d of line %d of field \"Editor Field\"", field "Column", field "Line") editScript it close this stack set the traceAbort to true set the traceReturn to true end mouseUp |O e Object @8$ e Helppon mouseUp help end mouseUp |D e Debug...pon mouseUp MCdebugScript the long id of the errorobject of this card, empty, field "Line", field "Column" close this stack end mouseUp $|P e Error Message)pon mouseDoubleUp which if which is 3 and there is a file "eetext" then set the cursor to watch open file "eetext" read from file "eetext" until eof put it into field "Messages" close file "eetext" beep 1 else local term put item 1 of the clickText into term if there is a card term of stack "MetaTalk Reference" then go to card term of stack "MetaTalk Reference" end if end mouseDoubleUp on mouseUp seterror the hilitedlines of me end mouseUp (  ` &  Bad Token N\ e  \ e Processing Token:  `\@ e Column: Line 0\0 e 0  \, e Line: Column \' e 0CursorsEU Helvetica @ @ @ @  @  @ @ @ @ @ @ @ @ @ @ @ @ @c5 D00 dĂNw @A@`` 0p0 88^8  <8>>O?">߀>? `ǂpjw0?? c11 D00 [ 5[ @ AH0J $p>|x[?? c12 D00 Y> ?0@ A.>|xpY> ?c16 D88K!AA?02>>~~B D? P   ?B c17 D88I0 px<~~x<p 0<A?P   ?B c18 D88K0?AA!2~~>>B D? P   ?B c19 D88K?_O‚‚O_?- 0x<|~|x<0 B D? P   ?B c20 D88K!AA?02>>~~B D? P   ?B c21 D88I0 px<~~x<p 0<B D? P   ?B c22 D88K0?AA!2~~>>B D? P   ?B c23 D88K?_O‚‚O_?- 0x<|~|x<0 B D? P   ?B c1 D88B@ 7@`px|~|lLJ`pXpE0E Ec8 D88J      踂* `0 G@gPwԂ?C5%%%%?c24 D88A D@`px|A~AA|AlALAAACHP AAAAAAc25 D88I>>666> >D@`px|A~AIɂ|]lILIAABHPc26 D88N@ p@@@@p @FC@hu@@c27 D88H@@2LRJy@@yRJ2L@@>!aa!>@h3us@s3@c25 D88P8<pxÂ`f`6p<8>02)$"D!$H D@?x>h|f@ǂpp~|bT HelpDpon mouseUp help end mouseUp bT  Find)`D  @D In stack: Stack Name4)eH@Dialog Box HelpMC Stack Menu case sensitiveD(x elibURLwBlackwhiteU%Q cVersion1.0.10cDefaultHeader'METHOD --- HTTP/1.1 Host: User-Agent: customHTTPHeaders##libUrl v1.0.10 --------------------------------------------------------------------- ##shared locals local lvCount,lvBlockingUrl,lvBlockBypass, lvLogField, lvTickle local lvJumpOut ##used by libUrlResetAll to make sure "wait for messages" loops exit cleanly local laLoadReq,laLoadedUrls,laStatus,laUrl,laLength,laData local laAction,laUrlLoadStatus,laUrlErrorStatus,laLoadQ, laLoadingUrls local laUser,laPasswd,laAuth,laBytes,laLongFileName,laHost local laMessg,laPostData,laTemp local laCancelled,lvStatusCallback local laFile,laReadBytes,laWriteBytes local laConnectHost, laConnectID, laSocketUser local lvSocketToken, lvSocketOpenStart, lvSocketOpenMessageID ##for socket opening --------------------------------------------------------------------- ##http locals local laConn,laCode,laChunk,laRhHeader, laHaveHeader, laNeedChunk local laStatusCode, laStatusMessage local laLineNum,laTmpData local laHttpDataDone local laCurrentHttpHeaders ----------------------------------------------------------------------- ##ftp locals local lvFtpMode, lvFtpStopTime, lvDataPortCount, lvFtpListCommand local laFtpDataDone local laControlXDataMap ##control sockets keyed by data sockets local laHome,lvNeedDir local laControlXLocalMap,laTransPasvIP,laTransActvIP,laMode local laStopUnit, laStopSec local laFTPCommandStatus local lvFtpCommandSocket ##socket used by libUrlFtpCommand local laUrlByFile ##used by libUrlUploadFile to track which files go to which url #######Engine Calls############################################# ####### load url ############################################# ------------------------------------------------ on loadUrl x,y put false into lvJumpOut put ulStripUrl(x) into newUrl if lvCount is empty then put "6923" into lvCount end if switch case newUrl is among the lines of the keys of laLoadingUrls ##don't allow loads if the same url is waiting to load return "error URL is currently loading" ##with empty break case newUrl is not among the lines of the keys of laLoadedUrls OR laUrlLoadStatus[newUrl] is not "cached" put the long id of the target &","& item 2 of the params into laMessg[newUrl] put true into laLoadReq[newUrl] put 1 into laLoadingUrls[newUrl] #for tracking put "getData" into laAction[newUrl] put empty into laUrlErrorStatus[newUrl] put empty into laUrlLoadStatus[newUrl] put empty into laLoadedUrls[newUrl] ulGetFormat newUrl,lvCount if laUrlLoadStatus[newUrl] is "error" and not laCancelled[newurl] then ulSendMessage newUrl ##send message now only if error occurred befoe block point return "error" ---------------------- else if laCancelled[newUrl] then ##user cancelled after starting but before blocking point delete local laLoadedUrls[newUrl] delete local laUrlLoadStatus[newUrl] delete local laUrlErrorStatus[newUrl] delete local laStatus[newUrl] delete local laCancelled[newUrl] delete local laCurrentHttpHeaders[newUrl] else return empty end if ----------------------- break case newUrl is among the lines of the keys of laLoadedUrls and laUrlLoadStatus[newUrl] is "cached" #url is in cache put the long id of the target &","& item 2 of the params into laMessg[newUrl] ulSendMessage newUrl ##send message return empty end switch end loadUrl #############unload url############ on unloadUrl pUrl put ulStripUrl(pUrl) into pUrl ##need to check if it is loading or in loadQ if pUrl is among the lines of keys(laLoadingUrls) then delete local laLoadingUrls[pUrl] ulCancelRequest pUrl ##stop any current downloads delete local laData[pUrl] ##in case download hasn't started return empty else if pUrl is among the lines of keys(laUrlLoadStatus) then delete local laLoadedUrls[pUrl] delete local laUrlLoadStatus[pUrl] delete local laUrlErrorStatus[pUrl] delete local laStatus[pUrl] return empty else ##not loaded return "can't find url" end if end unloadUrl ############# get url ############ on getUrl x put false into lvJumpOut put ulStripUrl(x) into newUrl if newUrl is among the lines of the keys of laLoadedUrls and laUrlLoadStatus[newUrl] is "cached" then if "2.4.1" is in the version then return empty with laLoadedUrls[newUrl] else return empty with cachedUrl laLoadedUrls[newUrl] end if end if if newUrl is among the lines of keys(laLoadingUrls) then return "error URL is currently loading" with empty end if if lvBlockingUrl is empty or lvBlockBypass is true then put newUrl into lvBlockingUrl if lvCount is empty then put "6923" into lvCount end if put empty into laUrlErrorStatus[newUrl] put "getData" into laAction[newUrl] put empty into laData[newUrl] ulGetFormat newUrl,lvCount # convert url to components ##final clean up here delete local laStatus[newUrl] put laUrlErrorStatus[newUrl] into tRetResult delete local laUrlErrorStatus[newUrl] if "2.4.1" is in the version then ##for mc 2.4.1 engine only put laData[newUrl] into tRetData ##swap data before deleting laData delete local laData[newUrl] put empty into lvBlockingUrl ##clear return tRetResult with tRetData else put empty into lvBlockingUrl ##clear return tRetResult with url laData[newUrl] end if else ##blocked by previous request return "error Previous request not completed" with empty end if end getUrl ############### post Url ################### on postUrl y,x put false into lvJumpOut put ulStripUrl(x) into newUrl if newUrl is among the lines of keys(laLoadingUrls) then return "error URL is currently loading" with empty end if if lvBlockingUrl is empty or lvBlockBypass is true then put newUrl into lvBlockingUrl if lvCount is empty then put "6923" into lvCount end if put y into laPostData[newUrl] put "postData" into laAction[newUrl] put empty into laUrlErrorStatus[newUrl] put empty into laData[newUrl] ulGetFormat newUrl,lvCount # convert url to components ---------------------------------- ##final clean up here delete local laStatus[newUrl] put laUrlErrorStatus[newUrl] into tRetResult delete local laUrlErrorStatus[newUrl] if "2.4.1" is in the version then ##for mc 2.4.1 engine only put laData[newUrl] into tRetData delete local laData[newUrl] put empty into lvBlockingUrl ##clear return tRetResult with tRetData else put empty into lvBlockingUrl ##clear return tRetResult with url laData[newUrl] end if ----------------------------------- else ##blocked by previous request put "error Previous request not completed" into tRetResult return tRetResult with empty end if end postUrl ############### put x into url ################ on putUrl y,x put false into lvJumpOut put ulStripUrl(x) into newUrl if newUrl is among the lines of keys(laLoadingUrls) then return "error URL is currently loading" with empty end if if lvBlockingUrl is empty or lvBlockBypass is true then put newUrl into lvBlockingUrl if lvCount is empty then put "6923" into lvCount end if put y into laPostData[newUrl] put "putData" into laAction[newUrl] put empty into laUrlErrorStatus[newUrl] put empty into laData[newUrl] ulGetFormat newUrl,lvCount # convert url to components ---------------------------------- ##final clean up here delete local laStatus[newUrl] put laUrlErrorStatus[newUrl] into tRetResult delete local laUrlErrorStatus[newUrl] if "2.4.1" is in the version then ##for mc 2.4.1 engine only put laData[newUrl] into tRetData delete local laData[newUrl] put empty into lvBlockingUrl ##clear return tRetResult with tRetData else put empty into lvBlockingUrl ##clear return tRetResult with url laData[newUrl] end if ----------------------------------- else ##blocked by previous request put "error Previous request not completed" into tRetResult return tRetResult with empty end if end putUrl ###############delete url######################## on deleteUrl x put false into lvJumpOut put ulStripUrl(x) into newUrl if newUrl is among the lines of keys(laLoadingUrls) then return "error URL is currently loading" with empty end if if lvBlockingUrl is empty or lvBlockBypass is true then put newUrl into lvBlockingUrl if lvCount is empty then put "6923" into lvCount end if put "deleteData" into laAction[newUrl] put empty into laUrlErrorStatus[newUrl] ulGetFormat newUrl,lvCount # convert url to components ---------------------------------- ##final clean up here delete local laStatus[newUrl] put laUrlErrorStatus[newUrl] into tRetResult delete local laUrlErrorStatus[newUrl] if "2.4.1" is in the version then ##for mc 2.4.1 engine only put laData[newUrl] into tRetData delete local laData[newUrl] put empty into lvBlockingUrl ##clear return tRetResult with tRetData else put empty into lvBlockingUrl ##clear return tRetResult with url laData[newUrl] end if ----------------------------------- else ##blocked by previous request put "error Previous request not completed" into tRetResult return tRetResult with empty end if end deleteUrl ######## cachedUrls ################################################ on getCachedUrls #ensure url has "cached" status #there may be urls with data but with "error" status #for example, with a 404 error, the "courtesy page" may appear in the data put keys(laUrlLoadStatus) into tLoadedKeys repeat for each line tKey in tLoadedKeys if laUrlLoadStatus[tKey] is "cached" then put tKey & cr after tRes end if end repeat if char -1 of tRes is cr then delete char -1 of tRes return tRes end getCachedUrls ######## UrlStatus ################################################### on getUrlStatus x #x is url put ulStripUrl(x) into x return laUrlLoadStatus[x] end getUrlStatus ####################breaks down the url into components#################### on ulGetFormat pUrl,pCount local tPre,tUser,tPass,tHost,tPort,tFileName switch ##http with authorization name and password ( port specified) case matchText (pUrl, "^(http)://(.+):(.+)@(.[^/]+)(:.[^/]+)(/.*)",tPre,tUser,tPass,tHost,tPort,tFileName) is true ##with auth and special port break ##http with authorization name and password (no port specified) case matchText (pUrl, "^(http)://(.+):(.+)@(.[^/]+)(/.*)",tPre,tUser,tPass,tHost,tFileName) is true break ##http ( port specified) case matchText (pUrl, "^(http)://(.[^/]+)(:.[^/]+)(/.*)",tPre,tHost,tPort,tFileName) is true break ##http ( port specified) no filename case matchText (pUrl, "^(http)://(.[^/]+)(:.[^/]+)()",tPre,tHost,tPort,tFileName) is true break ##http ( no port specified) case matchText (pUrl, "^(http)://(.[^/]+)(/.*)",tPre,tHost,tFileName) is true break ##http ( no port specified) no file case matchText (pUrl, "^(http)://(.[^/]+)()",tPre,tHost,tFileName) is true #+# break ##ftp with authorization name and password (port specified) case matchText (pUrl, "^(ftp)://(.+):(.+)@(.[^/]+)(:.[^/]+)(/.*)",tPre,tUser,tPass,tHost,tPort,tFileName) is true break ##ftp with authorization name and password (no port specified) case matchText (pUrl, "^(ftp)://(.+):(.+)@(.[^/]+)(/.*)",tPre,tUser,tPass,tHost,tFileName) is true break ##ftp without name and password (port specified) case matchText (pUrl,"^(ftp)://(.[^/]+)(:.[^/]+)(/.*)",tPre, tHost,tPort,tFileName) is true break ##ftp without name and password (no port specified) case matchText (pUrl,"^(ftp)://(.[^/]+)(/.*)",tPre, tHost,tFileName) is true break default put "invalid URL: " & quote & pUrl & quote into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "error" into laUrlLoadStatus[pUrl] exit "ulGetFormat" end switch ##set connection IP switch tPre case "http" if the httpProxy <> empty then put the httpproxy into tIPAddress replace "http://" with "" in tIPAddress ##not sure if this is possible but just in case if tPort <> empty then put tPort into tUrlPort ##save this for setting laFilename below else put ":80" into tUrlPort end if #get the proxy port put the itemdel into tSavedDel set the itemdel to ":" if the number of items of tIPAddress > 1 and item -1 of tIPAddress is a number then put ":" & item -1 of tIPAddress into tPort delete item -1 of tIPAddress #remove port for now else put ":80" into tPort end if set the itemDel to tSavedDel else if tPort <> empty then put tHost into tIPAddress else put tHost into tIPAddress put ":80" into tPort end if put tIPAddress into tTempIPAddress replace "." with empty in tTempIPAddress replace ":" with empty in tTempIPAddress if tTempIPAddress is not a number then get hostNameToAddress(tIPAddress) if the result is empty then put line 1 of it & tPort into tConnectHost else put true into tBadAddress end if else put tIPAddress & tPort into tConnectHost end if break case "ftp" put tHost into tTempHost if tPort is empty then put ":21" into tPort replace "." with empty in tTempHost replace ":" with empty in tTempHost if tTempHost is not a number then get hostnameToAddress(tHost) if the result is empty then put line 1 of it & tPort into tConnectHost else put true into tBadAddress end if else put tHost & tPort into tConnectHost end if if tUser is empty then put "anonymous" into tUser put "guest" into tPass end if break default put "invalid URL: " & quote & pUrl & quote into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "error" into laUrlLoadStatus[pUrl] exit "ulGetFormat" break end switch if tBadAddress then put "invalid host address" into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "error" into laUrlLoadStatus[pUrl] delete local laLoadingUrls[pUrl] end if ##need better clean up here exit "ulGetFormat" end if ##dc 080702 ##need to keep separate reference for ftp IPs by user ## in case we need to connect to two accounts simultaneously ##so just keep user + host ref for all urls ##so laConnectHost has format host:port|user put tConnectHost & "|" & tUser into laConnectHost[pUrl] if tUser is not empty then put urlDecode(tUser) into laUser[pUrl] if tPass is not empty then put urlDecode(tPass) into laPasswd[pUrl] put "true" into laAuth[pUrl] end if put tHost into laHost[pUrl] if tFileName is empty then put "/" into tFileName if tPre = "http" and the httpProxy <> empty then ----changed for 1.0.10 Remove username:password from url when sending request through a proxy put "http://" & tHost & tUrlPort & tFilename into laLongFileName[pUrl] ## put pUrl into laLongFileName[pUrl] ##must request full url when using http proxy else put tFileName into laLongFileName[pUrl] end if put "booked" into laUrlErrorStatus[pUrl] if tPre is "http" then ##store current state of httpHeaders ad use when request is actually processed put the httpHeaders into laCurrentHttpHeaders[pUrl] ulHttpRequest pUrl else ulFtpRequest pUrl end if end ulGetFormat #################choose http method#################### #on ulHttpRequest x on ulHttpRequest pUrl switch case laAction[pUrl] is "getData" if(laLoadReq[pUrl]) is true then ulHttpLoad pUrl else ulGetHttp pUrl end if break case laAction[pUrl] is "sendData" ulPutHttp pUrl break case laAction[pUrl] is "deleteData" ulDeleteHttp pUrl break case laAction[pUrl] is "putData" ulPutHttp pUrl break case laAction[pUrl] is "postData" ulPostHttp pUrl end switch end ulHttpRequest -------------------------------------------------- ##set up queue for http load requests on ulHttpLoad pUrl put laConnectHost[pUrl] into tIP put keys(laLoadQ) into tLoadingKeys if tIP is among the lines of tLoadingKeys then put true into tHaveConnection else put false into tHaveConnection end if put pUrl & cr after laLoadQ[tIP] put "queued" into laUrlLoadStatus[pUrl] if not tHaveConnection then ulNextHttpLoadRequest tIP end if end ulHttpLoad ------------------------------------------------ ##dispatch next load request on ulNextHttpLoadRequest pIP put line 1 of laLoadQ[pIP] into tUrl if tUrl <> empty then if tUrl = lvBlockingUrl then ##the same URL is being requested in a blocking call repeat until lvBlockingUrl <> tUrl if lvJumpOut then exit to top wait for messages end repeat end if ##in case url was "unloaded" during any wait, check that it's still in the queue if tUrl is among the lines of keys(laLoadingUrls) then delete line 1 of laLoadQ[pIP] ##added in 1.0.8r4 ulGetHttp tUrl else ##modified dc 00202 Delete current rquest if not in laLoadingUrls ----------------------------------- ## CLEAN UP POINT if user cancelled while in queue delete line 1 of laLoadQ[pIP] ##delete this item ulCleanUpHttpLocals tUrl delete local laLoadReq[tUrl] ##added dc 210702 delete local laLoadedUrls[tUrl]##added dc 210702 delete local laMessg[tUrl]##added dc 210702 delete local laUrlErrorStatus[tUrl] delete local laUrlLoadStatus[tUrl] delete local laCancelled[tUrl] if the number of lines of laLoadQ[pIP] = 0 then delete local laLoadQ[pIP] delete local laConnectID[pIP] else ##use send to ensure this thread finishes before next request send "ulNextHttpLoadRequest" && quote & pIP & quote to me in 1 milliseconds end if ------------------------------ end if end if end ulNextHttpLoadRequest ##############method GET######################### on ulGetHttp pUrl try put empty into laStatus[pUrl] ##set wait flag here put "started" into laUrlErrorStatus[pUrl] put ulWhichSocket(pUrl) into tSocket put pUrl into laUrl[tSocket] #ref the url to the used socket##KEY REFERENCE if tSocket is not among the lines of the openSockets then ulStartTickle ##safeguard routine get ulOpenSocket(tSocket) if not it then throw it ##error opening socket end if put "contacted" into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "contacted" into laUrlLoadStatus[pUrl] ulSendCallback pUrl,"contacted" ##CALLBACK FEATURE put ulBuildHttpRequest(pUrl) into tRequest ulLogit tRequest & cr ##LOG write tRequest & crlf to socket tSocket with message "ulStartRead" --------------------- if the result is not empty then throw the result #early exit end if -------------------------- ##blocking point "get url" #If we got here by "load url" then we don't block, otherwise we do if laLoadReq[pUrl] is empty then repeat while laStatus[pUrl] is empty if lvJumpOut then exit to top wait for messages end repeat end if catch pErr ##clean up point ulHttpEarlyCleanUp tSocket,pUrl,pErr exit ulGetHttp end try end ulGetHttp ---------------------------------- on ulHttpEarlyCleanUp x, pUrl, pErr put "error" && pErr into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "error" into laUrlLoadStatus[pUrl] put false into laStatus[pUrl] ##to unblock waits put laLoadReq[pUrl] into tLoadReq ##holder put laConnectHost[pUrl] into tConnectHost ulCleanUpHttp x if tLoadReq then ulSendMessage pUrl ##added 091002 ##use send to ensure this thread finishes before next request starts send "ulNextHttpLoadRequest" && quote & tConnectHost & quote to me in 1 milliseconds end if end ulHttpEarlyCleanUp ---------------------------------------------------------- on ulStartRead x,y if laUrl[x] <> empty then ##carry on ----------------------------------- ##set the httpHeaders to empty ##commented out in 1.0.8r4 put "requested" into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "requested" into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"requested" ##CALLBACK FEATURE if laLoadReq[laUrl[x]] then put empty into laLoadedUrls[laUrl[x]] else put empty into laData[laUrl[x]] end if put empty into laTmpData[laUrl[x]] put empty into laTemp[laUrl[x]] read from socket x with message "ulReadmore" -------------------------------- if the result <> empty then put "error" && the result into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock wait end if ---------------------------------- ##The wait in the getHttp handler allows "load" requests to pass ## we wait here for ALL requests so we can clean up --------------------------------------- repeat while laStatus[laUrl[x]] is empty if lvJumpOut then exit to top wait for messages end repeat ---------------------------------------- ## CLEAN UP POINT if laStatus[laUrl[x]] is false then close socket x ##if user unloaded else if laConn[laUrl[x]] is "close" then close socket x ##if user unloaded end if ulHttpLateCleanUp x end if end ulStartRead --------------------------------------- on ulHttpLateCleanUp x if laFile[laUrl[x]] <> empty then close file laFile[laUrl[x]] ##close here?? end if put laLoadReq[laUrl[x]] into tLoadReq ##holder put laUrl[x] into tUrlHolder #so we can delete in cleanUp put laConnectHost[laUrl[x]] into tConnectHost #holder so we can delete in clean up ulCleanUpHttp x if tLoadReq and laCancelled[tUrlHolder] then delete local laLoadedUrls[tUrlHolder] delete local laUrlLoadStatus[tUrlHolder] delete local laUrlErrorStatus[tUrlHolder] delete local laStatus[tUrlHolder] end if if not laCancelled[tUrlHolder] then ulSendMessage tUrlHolder else delete local laMessg[tUrlHolder] end if delete local laFile[tUrlHolder] delete local laCancelled[tUrlHolder] if tLoadReq then ##use send to ensure current request finishes completely send "ulNextHttpLoadRequest" && quote & tConnectHost & quote to me in 1 milliseconds end if end ulHttpLateCleanUp ------------------------------------------------------------------ on ulReadmore x,y #separate the header from body put false into laHaveHeader[laUrl[x]] put y after laTmpData[laUrl[x]] put y after laTemp[laUrl[x]] put lineOffset(crlf & crlf, laTmpData[laUrl[x]]) into tHeaderOffSet ##proper header structure ##added to catch irregularly formed headers 1.0.7b1 if tHeaderOffset is 0 then ##for irregularly formed headers put lineOffset(cr & crlf, laTmpData[laUrl[x]]) into tHeaderOffSet if tHeaderOffset is 0 then put lineOffset(cr & cr, laTmpData[laUrl[x]]) into tHeaderOffSet end if end if if tHeaderOffSet is not 0 then#1 put tHeaderOffSet into laLineNum[laUrl[x]] put line 1 to laLineNum[laUrl[x]] of laTmpData[laUrl[x]] into laRhHeader[laUrl[x]] repeat ##be sure we have a header if char 1 to 4 of laRhHeader[laUrl[x]] = "HTTP" then exit repeat delete line 1 of laRhHeader[laUrl[x]] if laRhHeader[laUrl[x]] is empty then ##we don't have a header put "error" && "No header received" into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock wait exit "ulReadmore" end if end repeat put length (laRhHeader[laUrl[x]]) into hLen switch case word 2 of line 1 of laRhHeader[laUrl[x]] is "100" ##Is this handled right?? delete line 1 to laLineNum[laUrl[x]]+1 of laTmpData[laUrl[x]] delete line 1 to laLineNum[laUrl[x]]+1 of laTemp[laUrl[x]] get lineOffset(crlf & crlf, laTmpData[laUrl[x]]) if it is not "0" then put it into laLineNum[laUrl[x]] put line 1 to laLineNum[laUrl[x]] of laTmpData[laUrl[x]] into laRhHeader[laUrl[x]] ulDoProcess x,y else read from socket x with message "ulReadmore" end if break case word 2 of line 1 of laRhHeader[laUrl[x]] is not "100" ulDoProcess x,y end switch else#1 if laStatus[laUrl[x]] is empty then read from socket x with message "ulReadmore" ##how often should we do this reading for a header?? ------------------------------------ if the result <> empty then put "error" && the result into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock wait below end if ------------------------------------ end if end if#1 end ulReadmore ------------------------------------------- on ulDoProcess x,y #handles reading data depending on whether transfer method is streamed, chunked or "until socket closes" if not laHaveHeader[laUrl[x]] then ##pick up header first time only ulLogIt laRhHeader[laUrl[x]] & cr & cr --LOG set the lastRhHeaders of me to laRhHeader[laUrl[x]] ##set property put lineOffset("Location:",laRhHeader[laUrl[x]]) into tLocLine put lineOffset("Content-Length:",laRhHeader[laUrl[x]]) into tLenLine put lineOffset("Content-Type:",laRhHeader[laUrl[x]]) into tContentLine put lineOffset("Transfer-Encoding:",laRhHeader[laUrl[x]]) into tCodeLine put lineOffset("Connection:",laRhHeader[laUrl[x]]) into tConnectionLine put lineOffset("Proxy-Connection:",laRhHeader[laUrl[x]]) into ptConnLine #get status code put word 2 of line 1 of laRhHeader[laUrl[x]] into laStatusCode[laUrl[x]] #get status message for error results put word 2 to -1 of line 1 of laRhHeader[laUrl[x]] into laStatusMessage[laUrl[x]] if laStatusCode[laUrl[x]] is not a number then ##no point hanging around put "error" && "Unable to resolve server response." into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock wait exit "ulDoProcess" end if if tConnectionLine is not "0" then put last word of line tConnectionLine of laRhHeader[laUrl[x]] into laConn[laUrl[x]] end if if ptConnLine is not "0" then put last word of line tConnectionLine of laRhHeader[laUrl[x]] into laConn[laUrl[x]] end if if tLenLine is not "0" and last word of (line tLenLine of laRhHeader[laUrl[x]]) is a number then put last word of (line tLenLine of laRhHeader[laUrl[x]]) into laLength[laUrl[x]] else put empty into laLength[laUrl[x]] put empty into laHttpDataDone[laUrl[x]] ##flag for detecting end of download end if if tCodeLine <> "0" then put last word of line tCodeLine of laRhHeader[laUrl[x]] into laCode[laUrl[x]] end if delete line 1 to laLineNum[laUrl[x]]+1 in laTmpData[laUrl[x]] put true into laHaveHeader[laUrl[x]] else put y after laTmpData[laUrl[x]] end if ------------------------------------- switch case laStatusCode[laUrl[x]] is among the items of "301,302" #we are redirected to a different url if tLocLine is not empty then put last word of (line tLocLine of laRhHeader[laUrl[x]]) into tNewLoc -------------------------------- put true into lvBlockBypass ##to allow another blocking call get url tNewLoc if the result is empty then ulStoreData laUrl[x],it put empty into laUrlErrorStatus[laUrl[x]] if laFile[laUrl[x]] is empty then put "cached" into tStatus else put "downloaded" into tStatus end if if laLoadReq[laUrl[x]] is "true" then put tStatus into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"downloaded" ##CALLBACK FEATURE else put "error" && "Redirect failed" && tNewLoc into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] is "true" then put "error" into laUrlLoadStatus[laUrl[x]] put empty into laLoadedUrls[laUrl[x]] else put empty into laData[laUrl[x]] end if end if put false into lvBlockBypass##to disallow another blocking call ----------------------- put true into laStatus[laUrl[x]] end if break ##normal case case laLength[laUrl[x]] is not empty put laTmpData[laUrl[x]] into tData ulStoreData laUrl[x],tData put length(tData) into laReadBytes[laUrl[x]] if laStatus[laUrl[x]] is empty then ulDoProcessLength x break #### chunked ###################################### case laCode[laUrl[x]] is "chunked" put true into laNeedChunk[laUrl[x]] put empty into laReadBytes[laUrl[x]] ulDoProcessChunked x break ##########No length header ##typically from CGI request #Handle both cases together case laLength[laUrl[x]] is empty and laConn[laUrl[x]] is "close" case laLength[laUrl[x]] is empty and laConn[laUrl[x]] is empty put laTmpData[laUrl[x]] into tData ulStoreData laUrl[x],tData put length(tData) into laReadBytes[laUrl[x]] put empty into laTmpData[laUrl[x]] ##clear buffer ulDoProcessNoLength x break end switch end ulDoProcess ------------------------------------------------------------------ on ulDoProcessLength x,y ##normal http case if y <> empty then ulStoreData laUrl[x],y add length(y) to laReadBytes[laUrl[x]] end if if laReadBytes[laUrl[x]] >= laLength[laUrl[x]] then put "true" into laStatus[laUrl[x]] if char 1 of laStatusCode[laUrl[x]] = 2 then ##in 200 range--OK if laFile[laUrl[x]] is empty then put "cached" into tStatus else put "downloaded" into tStatus end if put empty into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] is "true" then put tStatus into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"downloaded" ##CALLBACK FEATURE else put "error" && laStatusMessage[laUrl[x]] into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] is "true" then put "error" into laUrlLoadStatus[laUrl[x]] end if end if delete local laHaveHeader[laUrl[x]] -------------------------- else ##need more data put "loading," & laReadBytes[laUrl[x]] & "," & laLength[laUrl[x]] into tStatus put tStatus into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put tStatus into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],tStatus ##CALLBACK FEATURE if laStatus[laUrl[x]] is empty then read from socket x with message "ulDoProcessLength" --------------------- if the result <> empty then put "error" && the result into laUrlErrorStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock waits above if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put empty into laLoadedUrls[laUrl[x]] ##empty any data here else put empty into laData[laUrl[x]] ##empty any data here end if end if exit "ulDoProcessLength" ------------------------------ end if end if end ulDoProcessLength ------------------------------------------------------------ on ulDoProcessChunked x,y if y <> empty then put y after laTmpData[laUrl[x]] end if repeat while laStatus[laUrl[x]] is empty if laNeedChunk[laUrl[x]] then get the number of chars of line 1 of laTmpData[laUrl[x]] if not ((char it of laTmpData[laUrl[x]] is numtochar(13)) and\ (char it+1 of laTmpData[laUrl[x]] is numtochar(10))) then read from socket x with message "ulDoProcessChunked" --------------------- if the result <> empty then put "error" && the result into laUrlErrorStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock wait above if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put empty into laLoadedUrls[laUrl[x]] ##empty any data here else put empty into laData[laUrl[x]] ##empty any data here end if end if exit "ulDoProcessChunked" end if put offset(numtochar(13), laTmpData[laUrl[x]]) into wOffset[laUrl[x]] ----get chunk size value (store in laChunk) put char 1 to wOffset[laUrl[x]]-1 of laTmpData[laUrl[x]] into tRead[laUrl[x]] set the itemDel to ";" put item 1 of tRead[laUrl[x]] into tRead[laUrl[x]] ##remove any chunk extension set the itemdel to comma replace space with empty in tRead[laUrl[x]] put baseConvert(tRead[laUrl[x]],16,10) into laChunk[laUrl[x]] --------- delete char 1 to wOffset[laUrl[x]]+1 of laTmpData[laUrl[x]] if tRead[laUrl[x]] is "0" then ##completed delete local laNeedChunk[laUrl[x]] delete local laHaveHeader[laUrl[x]] put "true" into laStatus[laUrl[x]] ##to break out of wait if char 1 of laStatusCode[laUrl[x]] = 2 then ##in 200 range --OK if laFile[laUrl[x]] is empty then put "cached" into tStatus else put "downloaded" into tStatus end if put empty into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] is "true" then put tStatus into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"downloaded" ##CALLBACK FEATURE else put "error" && laStatusMessage[laUrl[x]] into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] is "true" then put "error" into laUrlLoadStatus[laUrl[x]] end if end if exit "ulDoProcessChunked" end if end if switch case length(laTmpData[laUrl[x]])=laChunk[laUrl[x]] + 2 put char 1 to laChunk[laUrl[x]] of laTmpData[laUrl[x]] into tData ulStoreData laUrl[x],tData add length(tData) to laReadBytes[laUrl[x]] put "loading," & laReadBytes[laUrl[x]] & "," into tStatus put tStatus into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put tStatus into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],tStatus ##CALLBACK FEATURE delete char 1 to laChunk[laUrl[x]] + 2 of laTmpData[laUrl[x]] put true into laNeedChunk[laUrl[x]] if laStatus[laUrl[x]] is empty then read from socket x with message "ulDoProcessChunked" --------------------- if the result <> empty then put "error" && the result into laUrlErrorStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock wait above if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put empty into laLoadedUrls[laUrl[x]] ##empty any data here else put empty into laData[laUrl[x]] ##empty any data here end if end if exit "ulDoProcessChunked" ----------------------- end if break case length(laTmpData[laUrl[x]])>laChunk[laUrl[x]] + 2 put char 1 to laChunk[laUrl[x]] of laTmpData[laUrl[x]] into tData ulStoreData laUrl[x],tData add length(tData) to laReadBytes[laUrl[x]] put "loading," & laReadBytes[laUrl[x]] & "," into tStatus put tStatus into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put tStatus into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],tStatus ##CALLBACK FEATURE delete char 1 to laChunk[laUrl[x]] + 2 of laTmpData[laUrl[x]] put true into laNeedChunk[laUrl[x]] next repeat break case length(laTmpData[laUrl[x]]) < laChunk[laUrl[x]] + 2 put false into laNeedChunk[laUrl[x]] if laStatus[laUrl[x]] is empty then read from socket x with message "ulDoProcessChunked" --------------------------- if the result <> empty then put "error" && the result into laUrlErrorStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock wait above if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put empty into laLoadedUrls[laUrl[x]] ##empty any data here else put empty into laData[laUrl[x]] ##empty any data here end if end if ---------------------------- end if exit "ulDoProcessChunked" end switch end repeat end ulDoProcessChunked --------------------------------------- on ulDoProcessNoLength x,y if y <> empty then ulStoreData laUrl[x],y add length(y) to laReadBytes[laUrl[x]] end if if x is among the lines of the openSockets then ##test for closure here if laStatus[laUrl[x]] is empty and laHttpDataDone[laUrl[x]] is empty then read from socket x with message "ulDoProcessNoLength" ---------------------------------------- if the result <> empty then put the result into tResult if tResult is not "socket is not open" then put "error" && the result into laUrlErrorStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock wait if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]]##not likely put empty into laLoadedUrls[laUrl[x]] ##empty any data here else put empty into laData[laUrl[x]] ##empty any data here end if else ##assume that we've got all the data ##treat as "completed" as below put "true" into laStatus[laUrl[x]] if char 1 of laStatusCode[laUrl[x]] = 2 then if laFile[laUrl[x]] is empty then put "cached" into tStatus else put "downloaded" into tStatus end if put empty into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] is "true" then put tStatus into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"downloaded" ##CALLBACK FEATURE else put "error" && laStatusMessage[laUrl[x]] into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] is "true" then put "error" into laUrlLoadStatus[laUrl[x]] end if delete local laHaveHeader[laUrl[x]] end if end if --------------------------------------------- end if else ##completed put "true" into laStatus[laUrl[x]] if char 1 of laStatusCode[laUrl[x]] = 2 then if laFile[laUrl[x]] is empty then put "cached" into tStatus else put "downloaded" into tStatus end if put empty into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] is "true" then put tStatus into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"downloaded" ##CALLBACK FEATURE else put "error" && laStatusMessage[laUrl[x]] into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] is "true" then put "error" into laUrlLoadStatus[laUrl[x]] end if delete local laHaveHeader[laUrl[x]] end if end ulDoProcessNoLength ##################HTTP DELETE############################### on ulDeleteHttp pUrl try put empty into laStatus[pUrl] put ulWhichSocket(pUrl) into tSocket put pUrl into laUrl[tSocket] #ref the url to the used socket if tSocket is not among the lines of the openSockets then ulStartTickle ##safeguard routine get ulOpenSocket(tSocket) if not it then throw it ##error opening socket end if put "contacted" into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "contacted" into laUrlLoadStatus[pUrl] ulSendCallback pUrl,"contacted" ##CALLBACK FEATURE put ulBuildHttpRequest(pUrl) into tRequest ulLogit tRequest & cr ##LOG write tRequest & crlf to socket tSocket if the result is not empty then throw the result end if put "requested" into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "requested" into laUrlLoadStatus[pUrl] ulSendCallback pUrl,"requested" ##CALLBACK FEATURE read from socket tSocket until crlf & crlf with message "ulReadMore" if the result is not empty then throw the result repeat while laStatus[pUrl] is empty if lvJumpOut then exit to top wait for messages end repeat ------------------------------------- ulHttpLateCleanUp tSocket --------------------------- catch pErr ulHttpEarlyCleanUp tSocket,pUrl,pErr exit ulDeleteHttp end try end ulDeleteHttp ########################HTTP POST######################### on ulPostHttp pUrl try put empty into laStatus[pUrl] ##set wait flag here put ulWhichSocket(pUrl) into tSocket put pUrl into laUrl[tSocket] #ref the url to the used socket if tSocket is not among the lines of the openSockets then ulStartTickle ##safeguard routine get ulOpenSocket(tSocket) if not it then throw it ##error opening socket end if put "contacted" into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "contacted" into laUrlLoadStatus[pUrl] ulSendCallback pUrl,"contacted" ##CALLBACK FEATURE put ulBuildHttpRequest(pUrl) into tRequest put empty into laData[pUrl] put empty into laTmpData[pUrl] ulLogit tRequest & cr #LOG write tRequest & crlf to socket tSocket with message "ulWriteSome" -------------------------- if the result is not empty then throw the result end if -------------------------- ## blocking point repeat while laStatus[pUrl] is empty if lvJumpOut then exit to top wait for messages end repeat ##added for 1.0.8.b4 , was previously in ulWriteSome which wasn't good ulHttpLateCleanUp tSocket catch pErr ulHttpEarlyCleanUp tSocket,pUrl,pErr exit ulPostHttp end try end ulPostHttp ----------------------------------------------------- on ulWriteSome x if laUrl[x] <> empty then ##in case an error was encountered when writing if the length of laPostData[laUrl[x]] <= 4096 then ##don't forget to get tBytes write laPostData[laUrl[x]] & crlf to socket x put "requested" into laUrlErrorStatus[laUrl[x]] read from socket x with message "ulReadmore" ---------------------------------- if the result <> empty then put "error" && the result into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##to unblock wait above end if ---------------------------------- repeat while laStatus[laUrl[x]] is empty if lvJumpOut then exit to top wait for messages end repeat else put char 1 to 4096 of laPostData[laUrl[x]] into tChunk ##laChunk[laUrl[x]] delete char 1 to 4096 in laPostData[laUrl[x]] write tChunk to socket x with message "ulWriteSome" end if end if end ulWriteSome ###################HTTP PUT########################## on ulPutHttp pUrl try put empty into laStatus[pUrl]##flag put ulWhichSocket(pUrl) into tSocket put pUrl into laUrl[tSocket] #ref the url to the used socket if tSocket is not among the lines of the openSockets then ulStartTickle ##safeguard routine get ulOpenSocket(tSocket) if not it then throw it ##error opening socket end if put "contacted" into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "contacted" into laUrlLoadStatus[pUrl] ulSendCallback pUrl,"contacted" ##CALLBACK FEATURE put ulBuildHttpRequest(pUrl) into tRequest ulLogit tRequest & cr ##LOG ##just the same as ulPostHttp from this point write tRequest & crlf to socket tSocket with message "ulWriteSome" --------------------------- if the result is not empty then throw the result end if -------------------------- ##top blocking point repeat while laStatus[pUrl] is empty if lvJumpOut then exit to top wait for messages end repeat ##added for 1.0.8.b4 , was previously in ulWriteSome which wasn't good ulHttpLateCleanUp tSocket catch pErr ulHttpEarlyCleanUp tSocket,pUrl,pErr exit ulPutHttp end try end ulPutHttp -------------------------------------------- function ulWhichSocket pUrl ##build socket ref including Connection ID number ## re-use sockets for blocking requests if open ##load request sequences will always use same socket ##new sequence gets new socket put laConnectHost[pUrl] into tConnectHost set the itemDel to "|" if loadReq[pUrl] then if laConnectID[tConnectHost] <> empty then put laConnectID[tConnectHost] into tConnID else add 1 to lvCount put lvCount into tConnID put lvCount into laConnectID[tConnectHost] end if else ##blocking request put empty into tConnID put char 1 to 4 of pUrl is "ftp:" into tIsFtp repeat for each line i in the openSockets if tIsFtp then ##makes sure we have the same username before re-using an FTP socket if laSocketUser[i] <> laUser[pUrl] then next repeat end if end if if item 1 of tConnectHost is item 1 of i and i is not among the lines of keys(laUrl) then #OK to use put last item of i into tConnID exit repeat end if end repeat if tConnID is empty then ##need new socket ref add 1 to lvCount put lvCount into tConnID end if end if ##swap out user name for connection ID put item 1 of tConnectHost & "|" & tConnID into tSocket if laUser[pUrl] <> empty then ##for ftp sockets, we need to keep reference to user name put laUser[pUrl] into laSocketUser[tSocket] ## here or when connection is made?? end if set the itemDel to comma return tSocket end ulWhichSocket --------------------------------------------- function ulBuildHttpRequest pUrl ##build the httpRequest including ##request line and basic headers if the customHTTPHeaders of me <> empty then#a put the customHTTPHeaders of me into tRequest set the customHTTPHeaders of me to empty else ##get template put the cDefaultHeader of me into tRequest ##get method put laAction[pUrl] into tAction switch tAction case "getData" put "GET" into tMethod break case "deleteData" put "DELETE" into tMethod break case "putData" put "PUT" into tMethod break case "postData" put "POST" into tMethod break end switch replace "METHOD" with tMethod in tRequest ---------------------------- ##fill in url resource put laLongFileName[pUrl] into word 2 of line 1 of tRequest ## fill in host put laHost[pUrl] after line 2 of tRequest ## fill in User-Agent if "rev" is in the short name of me then put "Revolution" into tAgent else put "Metacard" into tAgent end if put tAgent && "(" & the platform & ")" after line 3 of tRequest if tMethod is among the items of "PUT,POST" then put cr & "Content-Length:" && length(laPostdata[pUrl]) after tRequest put cr & "Content-Type: application/x-www-form-urlencoded" after tRequest end if if laAuth[pUrl] is not empty then put base64Encode(laUser[pUrl] & ":" & laPasswd[pUrl]) into tLogin put cr & "Authorization: Basic" && tLogin after tRequest end if ##customize according to httpHeaders ## if the httpHeaders is not empty then if laCurrentHttpHeaders[pUrl] is not empty then ##repeat for each line tHeader in the httpHeaders repeat for each line tHeader in laCurrentHttpHeaders[pUrl] put lineOffset((word 1 of tHeader),tRequest) into tHeaderLine if tHeaderLine is not 0 then ##replace header value put tHeader into line tHeaderLine of tRequest else ##add new field put cr & tHeader after tRequest end if end repeat end if end if ##set the lastHTTPHeaders## set the lastHTTPHeaders of me to tRequest ##separate lines with crlf in header repeat for each line i in tRequest put i & crlf after tRequest2 end repeat return tRequest2 end ulBuildHttpRequest ################################################### ################ FTP LOGIN#################### ######################################## on ulFtpRequest pUrl if laLoadReq[pUrl] then ulFtpLoad pUrl else if laAction[pUrl] = "postdata" then ##don't handle this put "error Post command not handled for FTP" into laUrlErrorStatus[pUrl] ulCleanUpFtpLocals pUrl exit "ulFtpRequest" else ulFtpSocket pUrl end if end ulFtpRequest ----------------------------- ##set up queue for http load requests on ulFtpLoad pUrl put laConnectHost[pUrl] into tIP put keys(laLoadQ) into tLoadingKeys if tIP is among the lines of tLoadingKeys then put true into tHaveConnection else put false into tHaveConnection end if put pUrl & cr after laLoadQ[tIP] put "queued" into laUrlLoadStatus[pUrl] if not tHaveConnection then ulNextFtpLoadRequest tIP end if end ulFtpLoad ------------------------------------------------ ##dispatch next request on ulNextFtpLoadRequest pIP put line 1 of laLoadQ[pIP] into tUrl if tUrl <> empty then if tUrl = lvBlockingUrl then ##the same URL is being requested in a blocking call repeat until lvBlockingUrl <> tUrl if lvJumpOut then exit to top wait for messages end repeat end if ##in case url was "unloaded" during any wait, check that it's still in the queue if tUrl is among the lines of keys(laLoadingUrls) then delete line 1 of laLoadQ[pIP] ##delete this item ##added for 1.0.8r4 ulFtpSocket tUrl else ##Delete current rquest if not in laLoadingUrls ----------------------------------- ## CLEAN UP POINT if user cancelled while in queue delete line 1 of laLoadQ[pIP] ##delete this item ulCleanUpFtpLocals tUrl delete local laLoadReq[tUrl] ##added dc 210702 delete local laLoadedUrls[tUrl]##added dc 210702 delete local laMessg[tUrl]##added dc 210702 delete local laUrlErrorStatus[tUrl] delete local laUrlLoadStatus[tUrl] delete local laCancelled[tUrl] if the number of lines of laLoadQ[pIP] = 0 then delete local laLoadQ[pIP] delete local laConnectID[pIP] else ##use send .. in send "ulNextFtpLoadRequest" && quote & pIP & quote to me in 1 milliseconds end if ---------------------------------- end if end if end ulNextFtpLoadRequest -------ulFtpSocket------------------------------------------------------ -------Establishes connection for all ftp calls------------------- on ulFtpSocket pUrl put empty into laStatus[pUrl] ##set main wait flag here put ulWhichSocket(pUrl) into tSocket put pUrl into laUrl[tSocket] ##reference the url to the used socket put "0" into laStopUnit[tSocket] put "0" into laStopSec[tSocket] if tSocket is not among the lines of the openSockets then ulStartTickle ##safeguard routine get ulOpenSocket(tSocket) if not it then ulFtpEarlyExit tSocket,pUrl,it exit ulFtpSocket end if ------------------------get server response (220) put ulFtpWaitResponse(tSocket) into tReply if not ulFtpGoodReply(tReply, "connect") then ulFtpEarlyExit tSocket,pUrl,tReply exit "ulFtpSocket" end if --------------- put "connecting" into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "connecting" into laUrlLoadStatus[pUrl] ulSendCallback pUrl,"connecting" ##CALLBACK FEATURE --------------- put "USER " & laUser[pUrl] into tCmd put ulFtpCommand(tCmd,tSocket) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpEarlyExit tSocket,pUrl,tReply exit "ulFtpSocket" end if ---------------------- put "PASS " & laPasswd[pUrl] into tCmd put ulFtpCommand(tCmd,tSocket) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpEarlyExit tSocket,pUrl,tReply exit "ulFtpSocket" end if end if ---------------------------- write "PWD" & crlf to socket tSocket with message "ulFtpStartPoint" ##BRANCH TO ALLOW NON BLOCKING load if the result <> empty then put the result into tErr ulFtpEarlyExit tSocket,pUrl,tErr exit ulFtpSocket end if ---------------------------------------- ##let non-blocking requests exit put pUrl into tUrlHolder ##so we can delete laUrl and in ulFtpStartPoint on return if laLoadReq[tUrlHolder] is empty then repeat until laStatus[tUrlHolder] is not empty if lvJumpOut then exit to top wait for messages end repeat end if end ulFtpSocket -------------------------------------------- on ulFtpEarlyExit pSocket,pUrl,pErr #### ##clean up when exiting before first blocking point #### put laConnectHost[pUrl] into tConnectHost replace "ftpErr," with empty in pErr put "error" && pErr into laUrlErrorStatus[pUrl] if laLoadReq[pUrl] then put "error" into laUrlLoadStatus[pUrl] put false into laStatus[pUrl] close socket pSocket delete local laSocketUser[pSocket] delete local laStopUnit[pSocket] delete local laStopSec[pSocket] put laLoadReq[pUrl] into tLoadReq ##holder ulCleanUpFtp pSocket if tLoadReq then ulSendMessage pUrl ##added 091002 send "ulNextFtpLoadRequest" && quote & tConnectHost & quote to me in 1 milliseconds end if end ulFtpEarlyExit -------------------------- on ulFtpSetError x, pErr replace "ftpErr," with empty in pErr put "error " && pErr into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put false into laStatus[laUrl[x]] ##set flag to get past waits end ulFtpSetError -------ulFtpStartPoint------------------------------------------------------ -------Continues after load calls have passed on------------------- on ulFtpStartPoint x set the itemdel to "|" put item -1 of x into tNum set the itemdel to comma put ulFtpWaitResponse(x) into tReply replace "ftpErr," with empty in tReply if not ulFtpGoodReply(tReply, "PWD") then ##command sent in ftpSocket ulFtpSetError x,tReply close socket x delete local laSocketUser[x] else ##051202 next 5 lines repair bug introduced in 1.0.8a1 ## and ensure home directory is only set once per session ##otherwise CWD calls put us out of kilter if laHome[laUrl[x]] is empty then set the itemDel to quote put item 2 of tReply into laHome[laUrl[x]] set the itemDel to comma end if put "connected" into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "connected" into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"connected" ##CALLBACK FEATURE switch case laAction[laUrl[x]] is "getData" ulFtpGet x,tNum break case laAction[laUrl[x]] is "putData" ulFtpSend x,tNum break case laAction[laUrl[x]] is "deleteData" ulFtpDelete x break default put false into laStatus[laUrl[x]] put "error Command not handled" into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] end switch end if ##block ALL requests here until everything finished ##load requests already got past in ulFtpSocket repeat while laStatus[laUrl[x]] is empty if lvJumpOut then exit to top wait for messages end repeat ## CLEAN UP POINT ------------------------------------- ##Pass message here on return put laUrlLoadStatus[laUrl[x]] into tLoadStatus ------------------------------------- #start timer routine for closing ftp connection if laStopUnit[x] = 0 then put "1" into laStopUnit[x] send "ulFtpStopWatch " & x to me in 50 milliseconds end if ##do cleanup here ##first close file if necessary if laFile[laUrl[x]] <> empty then if laUrlByFile[laFile[laUrl[x]]] = laUrl[x] then ##hasn't been opened by new request close file laFile[laUrl[x]] ##close here?? delete local laUrlByFile[laFile[laUrl[x]]] else seek to 0 in file laFile[laUrl[x]] ##reset position for subsequent reads end if end if delete local laFile[laUrl[x]] put laLoadReq[laUrl[x]] into tLoadReq ##holder put laUrl[x] into tUrlHolder #so we can delete in cleanUp put laConnectHost[laUrl[x]] into tConnectHost #holder so we can delete in clean up ulCleanUpFtp x if tLoadReq and laCancelled[tUrlHolder] then delete local laLoadedUrls[tUrlHolder] delete local laUrlLoadStatus[tUrlHolder] delete local laUrlErrorStatus[tUrlHolder] delete local laStatus[tUrlHolder] end if if not laCancelled[tUrlHolder] then ulSendMessage tUrlHolder else delete local laMessg[tUrlHolder] end if delete local laCancelled[tUrlHolder] #change dc 210702 if tLoadReq then send "ulNextFtpLoadRequest" && quote & tConnectHost & quote to me in 1 milliseconds end if end ulFtpStartPoint #####################FTP GET################## on ulFtpGet x,z if lvFtpMode is "active" then put "active" into laMode[laUrl[x]] else put "passive" into laMode[laUrl[x]] end if put "contacted" into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "contacted" into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"contacted" ##CALLBACK FEATURE -----TYPE-------------------- put "TYPE I" into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpSetError x,tReply close socket x delete local laSocketUser[x] exit "ulFtpGet" end if ---------------------- ##sort out file path if laHome[laUrl[x]] is not "/" then ##otherwise laFileName should already be OK if laHome[laUrl[x]] is not char 1 to length(laHome[laUrl[x]]) of laLongFileName[laUrl[x]] then put laHome[laUrl[x]] before laLongFileName[laUrl[x]] end if end if ##SIZE get file size or CWD if a directory put empty into laLength[laUrl[x]] ##set up if last char of laLongFileName[laUrl[x]] is not "/" then ##file not directory put "SIZE " & laLongFileName[laUrl[x]] into tCmd put false into tNeedCWDReset put ulFtpCommand(tCmd,x) into tReply ## 191002 changed following; can't use 550 response from SIZE command to assume file can't be transferred ## if item 1 of tReply is "ftpErr" or word 1 of tReply is 550 then if item 1 of tReply is "ftpErr" then ulFtpSetError x,tReply close socket x delete local laSocketUser[x] exit "ulFtpGet" end if if word 1 of tReply = 213 then ##good reply get word 2 of tReply if it is an integer then put it into laLength[laUrl[x]] end if end if else ##need directory listing so we must CWD before getting listing put laLongFileName[laUrl[x]] into tTempPath if the length of tTempPath >1 then ##remove final forward slash delete last char of tTempPath end if put "CWD " & tTempPath into tCmd put true into tNeedCWDReset put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpSetError x,tReply close socket x delete local laSocketUser[x] exit "ulFtpGet" end if end if -------------------------------------- if laMode[laUrl[x]] is "active" then ulTransferActive x else ulTransferPassive x end if if laStatus[laUrl[x]] <> empty then ##failed to set up data connection close socket x delete local laSocketUser[x] exit ulFtpGet end if ---------------------------------------------------- ##prepare for reading data put empty into laFtpDataDone[laUrl[x]] ##flag for checking transfer is over put empty into laReadBytes[laUrl[x]] if laLoadReq[laUrl[x]] then put empty into laLoadedurls[laUrl[x]] else put empty into laData[laUrl[x]] end if -----RETR or LIST------------------- if last char of laLongFileName[laUrl[x]] is not "/" then put "RETR " & laLongFileName[laUrl[x]] into tCmd else ##need directory listing if lvFtpListCommand = "NLST" then put "NLST" into tCmd else put "LIST" into tCmd end if end if put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpSetError x,tReply exit "ulFtpGet" else put "requested" into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "requested" into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"requested" ##CALLBACK FEATURE end if ------------------------------------- ##blocking point ACTIVE?? if laMode[laUrl[x]] is "active" then repeat while laFtpDataDone[laUrl[x]] is empty and laStatus[laUrl[x]] is empty if lvJumpOut then exit to top wait for messages end repeat end if ##blocking point PASSIVE?? if laMode[laUrl[x]] is not "active" then read from socket laTransPasvIP[laUrl[x]] with message "ulGetData" repeat while laFtpDataDone[laUrl[x]] is empty and laStatus[laUrl[x]] is empty if lvJumpOut then exit to top wait for messages end repeat end if if laStatus[laUrl[x]] is not empty then ##error occurred if laUrlErrorStatus[laUrl[x]] is empty then put "error" into laUrlErrorStatus[laUrl[x]] end if if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] delete local laLoadedUrls[laUrl[x]] ##clear data else delete local laData[laUrl[x]] ##clear data end if close socket x delete local laSocketUser[x] else #now check for 226 completion put ulFtpWaitResponse(x) into tReply if word 1 of tReply <> 226 then replace "ftperr," with empty in tReply put "error" && tReply into laUrlErrorStatus[laUrl[x]] put empty into laData[laUrl[x]] ##clear data if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] delete local laLoadedurls[laUrl[x]] ##don't need anymore end if close socket x delete local laSocketUser[x] else ##download successful if tNeedCWDReset then ##051202 reset current directory to original put "CWD " & laHome[laUrl[x]] into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpSetError x,tReply close socket x delete local laSocketUser[x] exit "ulFtpGet" end if end if put empty into laUrlErrorStatus[laUrl[x]] if laFile[laUrl[x]] is empty then put "cached" into tStatus else put "downloaded" into tStatus end if if laLoadReq[laUrl[x]] then put tStatus into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"downloaded" ##CALLBACK FEATURE end if put true into laStatus[laUrl[x]] ##break wait end if end ulFtpGet ############get data port from ftp server-answer to PASV############## on ulTransferPassive x set the itemDel to "|" put last item of x into y set the itemDel to comma put "PASV" into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpSetError x,tReply exit "ulTransferPassive" end if if last char of tReply is "." then delete last char of tReply replace ")" with empty in tReply set the itemDel to "(" put item 2 of tReply into n1 set itemDel to "," put item 1 to 4 of n1 into transPasvIP replace "," with "." in transPasvIP put (item -2 of n1)*256 into a1 put item -1 of n1 into a2 put a1+a2 into tPort put transPasvIP & ":" & tPort & "|" & y into laTransPasvIP[laUrl[x]] get ulOpenSocket(laTransPasvIP[laUrl[x]]) if not it then put "error Couldn't open passive transfer connection" into tErr ulFtpSetError x,tErr exit "ulTransferPassive" end if put x into laControlXDataMap[laTransPasvIP[laUrl[x]]] ## end ulTransferPassive ------------------------------------------ ####################Send port to server for Active transfer and listen for data############### on ulTransferActive x if lvDataPortCount is empty or lvDataPortCount >= 65535 then ##put 49152 into lvDataPortCount put 6923 into lvDataPortCount else add 1 to lvDataPortCount end if set the itemDel to "|" put last item of x into y set the itemDel to comma put x into laControlXLocalMap[lvDataPortCount] put hostAddress(x) into thisIP replace "." with "," in thisIP put lvDataPortCount into laTransActvIP[x] if laAction[laUrl[x]] is "putData" then accept connections on port laTransActvIP[x] with message "ulPortMessageSend" else accept connections on port laTransActvIP[x] with message "ulPortMessageGet" end if if the result <> empty then put "error Couldn't open transfer port" into tErr ulFtpSetError x,tErr exit "ulTransferActive" end if put laTransActvIP[x] div 256 into i1 put laTransActvIP[x] mod 256 into i2 put "PORT " & thisIP & "," & i1&","& i2 into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpSetError x,tReply exit "ulTransferActive" end if end ulTransferActive ------------------------------------------ on ulPortMessageGet x,y ##active transfer message received put laControlXLocalMap[y] into tControlSock put tControlSock into laControlXDataMap[x] if x is among the lines of the openSockets then read from socket x with message "ulGetData" if the result <> empty then put the result into tReply ulFtpSetError tControlSock,tReply end if end if end ulPortMessageGet #################the ftp download routine################## on ulGetData x,y put laControlXDataMap[x] into mSock ulStoreData laUrl[mSock],y add length(y) to laReadBytes[laUrl[mSock]] put "loading," & laReadBytes[laUrl[mSock]] & "," & laLength[laUrl[mSock]] into tStatusString put tStatusString into laUrlErrorStatus[laUrl[mSock]] if laLoadReq[laUrl[mSock]] then put tStatusString into laUrlLoadStatus[laUrl[mSock]] ulSendCallback laUrl[mSock],tStatusString ##CALLBACK FEATURE if x is among the lines of the openSockets then read from socket x with message "ulGetData" if the result <> empty then put false into laStatus[laUrl[mSock]] end if end if end ulGetData ##############FTP PUT ######################### on ulFtpSend x,z if lvFtpMode is "active" then put "active" into laMode[laUrl[x]] else put "passive" into laMode[laUrl[x]] end if set the itemDel to "|";put last item of z into y set the itemDel to comma put "contacted" into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "contacted" into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"contacted" ##CALLBACK FEATURE ---------------------------------------------------------------------- ##sort out file path if laHome[laUrl[x]] is not "/" then ##otherwise laFileName should already be OK if laHome[laUrl[x]] is not char 1 to length(laHome[laUrl[x]]) of laLongFileName[laUrl[x]] then put laHome[laUrl[x]] before laLongFileName[laUrl[x]] end if end if ## check for valid filename if last char of laLongFileName[laUrl[x]] is "/" or laLongFileName[laUrl[x]] is empty then put "File not specified" into tErr ulFtpSetError x,tErr exit "ulFtpSend" end if ### CWD to directory if it exists put false into tNeedCWDReset set the itemDel to "/" put laLongFileName[laUrl[x]] into tTempPath put empty into item -1 of tTempPath if tTempPath <> laHome[laUrl[x]] then delete char -1 of tTempPath put "CWD " & tTempPath into tCmd put true into tNeedCWDReset put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulMakeDirectory x,tTempPath,1 ##1 = first try if the result <> empty then ulFtpSetError x,the result exit "ulFtpSend" end if end if end if if tNeedCWDReset then ##RESET working directory put "CWD " & laHome[laUrl[x]] into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpSetError x,tReply close socket x delete local laSocketUser[x] exit "ulFtpSend" end if end if ---------------------------------------------------------------------- put "TYPE I" into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpSetError x,tReply exit "ulFtpSend" end if if laFile[laUrl[x]] is empty then put length(laPostData[laUrl[x]]) into laLength[laUrl[x]] else put ulFileLength(laFile[laUrl[x]]) into laLength[laUrl[x]] end if put empty into laWriteBytes[laUrl[x]] put empty into laFtpDataDone[laUrl[x]] ##used below to control exit from ulFtpSend if laMode[laUrl[x]] is "active" then ulTransferActive x else ulTransferPassive x end if if laStatus[laUrl[x]] is not empty then ##couldn't make data connection exit "ulFtpSend" end if put "STOR " & laLongFileName[laUrl[x]] into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then ulFtpSetError x,tReply exit "ulFtpSend" end if put "requested" into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "requested" into laUrlLoadStatus[laUrl[x]] ulSendCallback laUrl[x],"requested" ##CALLBACK FEATURE ##Block here while sending data if laMode[laUrl[x]] is not "active" then ulSendDataP x repeat while laFtpDataDone[laUrl[x]] is empty and laStatus[laUrl[x]] is empty##waiting for write to complete if lvJumpOut then exit to top wait for messages end repeat if laStatus[laUrl[x]] <> empty then ##error occurred if laUrlErrorStatus[laUrl[x]] is empty then put "error" into laUrlErrorStatus[laUrl[x]] end if put empty into laData[laUrl[x]] ##clear data if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] delete local laData[laUrl[x]] ##clear data end if close socket x delete local laSocketUser[x] else ##look for 226 response put ulFtpWaitResponse(x) into tReply if word 1 of tReply <> 226 then replace "ftperr," with empty in tReply put "error" && tReply into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] delete local laData[laUrl[x]] ##clear data end if close socket x delete local laSocketUser[x] else put empty into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "uploaded" into laUrlLoadStatus[laUrl[x]] delete local laData[laUrl[x]] ##clear data end if ulSendCallback laUrl[x],"uploaded" ##CALLBACK FEATURE end if put true into laStatus[laUrl[x]] end if end ulFtpSend -------------------------------------------- on ulMakeDirectory x, pDir -- first we CWD to the parent directory set the itemDel to "/" put pDir into tTempPath delete item -1 of tTempPath ##parent directory if tTempPath is empty then put "/" into tTempPath ## root directory put empty into lvNeedDir put "CWD " & tTempPath into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then if tTempPath = laHome[laUrl[x]] then return "error Unable to create directory path" else ulMakeDirectory x,tTempPath if the result <> empty then return the result end if end if end if put "MKD " & pDir into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then return "error Unable to create directory path" else ##now CWD to the created directory put "CWD " & pDir into tCmd put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then return tReply else return empty end if end if end ulMakeDirectory ############ACTIVE UPLOAD############ on ulPortMessageSend x,y ##active transfer message received put laControlXLocalMap[y] into tControlSock put tControlSock into laControlXDataMap[x] put ulNextData(laUrl[tControlSock]) into nData if nData <> empty then add length(nData) to laWriteBytes[laUrl[tControlSock]] put "uploading, " & laWriteBytes[laUrl[tControlSock]] & "," & laLength[laUrl[tControlSock]] into tStatusString put tStatusString into laUrlErrorStatus[laUrl[tControlSock]] write nData to socket x with message "ulWriteMoreA" if the result <> empty then put "error" && the result into laUrlErrorStatus[laUrl[tControlSock]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[tControlSock]] put false into laStatus[laUrl[tControlSock]] end if else put false into laStatus[laUrl[tControlSock]] end if end ulPortMessageSend ------------------------------------------- on ulWriteMoreA x put laControlXDataMap[x] into tId put ulNextData(laUrl[tId]) into nData if nData <> empty then add length(nData) to laWriteBytes[laUrl[tId]] put "uploading," & laWriteBytes[laUrl[tId]] & "," & laLength[laUrl[tId]] into tStatusString put tStatusString into laUrlErrorStatus[laUrl[tId]] if laLoadReq[laUrl[tId]] then put tStatusString into laUrlLoadStatus[laUrl[tId]] ulSendCallback laUrl[tId],tStatusString ##CALLBACK FEATURE write nData to socket x with message "ulWriteMoreA" if the result <> empty then put false into laStatus[laUrl[tId]] end if else put true into laFtpDataDone[laUrl[tId]] put empty into laUrlErrorStatus[laUrl[tId]] close socket x close socket laTransActvIP[tID] ##local port delete local laControlXDataMap[x] end if end ulWriteMoreA ##########PASSIVE UPLOAD############ on ulSendDataP x put ulNextData(laUrl[x]) into nData if nData <> empty then add length(nData) to laWriteBytes[laUrl[x]] put "uploading," & laWriteBytes[laUrl[x]] & "," & laLength[laUrl[x]] into tStatusString put tStatusString into laUrlErrorStatus[laUrl[x]] write nData to socket laTransPasvIP[laUrl[x]] with message "ulWriteMoreP" if the result <> empty then put false into laStatus[laUrl[x]] end if else put false into laStatus[laUrl[x]] end if end ulSendDataP --------------------------------------------------------------------- on ulWriteMoreP x put laControlXDataMap[x] into mSock put ulNextData(laUrl[mSock]) into nData if nData <> empty then add length(nData) to laWriteBytes[laUrl[mSock]] put "uploading, " & laWriteBytes[laUrl[mSock]] & "," & laLength[laUrl[mSock]] into tStatusString put tStatusString into laUrlErrorStatus[laUrl[mSock]] if laLoadReq[laUrl[mSock]] then put tStatusString into laUrlLoadStatus[laUrl[mSock]] ulSendCallback laUrl[mSock],tStatusString ##CALLBACK FEATURE if laStatus[laUrl[mSock]] is empty then write nData to socket x with message "ulWriteMoreP" end if if the result <> empty then put false into laStatus[laUrl[mSock]] end if else close socket x ##close data socket here delete local laControlXDataMap[x] put empty into laUrlErrorStatus[laUrl[mSock]] put true into laFtpDataDone[laUrl[mSock]] #set flag before closing socket end if end ulWriteMoreP ####################FTP DELETE################ on ulFtpDelete x ###########make sure we use the full path ##sort out file path if laHome[laUrl[x]] is not "/" then ##otherwise laFileName should already be OK if laHome[laUrl[x]] is not char 1 to length(laHome[laUrl[x]]) of laLongFileName[laUrl[x]] then put laHome[laUrl[x]] before laLongFileName[laUrl[x]] end if end if if last char of laLongFileName[laUrl[x]] is "/" then #delete directory put "RMD " & laLongFileName[laUrl[x]] into tCmd put "directory" into mType else #delete file put "DELE " & laLongFileName[laUrl[x]] into tCmd put "file" into mType end if put ulFtpCommand(tCmd,x) into tReply if not ulFtpGoodReply(tReply, tCmd) then replace "ftpErr," with empty in tReply put "error" && tReply into laUrlErrorStatus[laUrl[x]] else put empty into laUrlErrorStatus[laUrl[x]] end if put true into laStatus[laUrl[x]] end ulFtpDelete ######################################################### on socketClosed x ulLogIt "CLOSED" && x & cr##LOG delete local laSocketUser[x] ##reference for allocating sockets for FTP logons ##need to check whether ftp data port or not if x is among the lines of keys(lvSocketToken) then ##trying to open a socket put "socket closed" into lvSocketToken[x] else if x is lvFtpCommandSocket then ##handling libUrlFtpCommand if x is among the lines of keys(laFTPCommandStatus) then ##may be waiting for a server reply put "socket closed" into laFTPCommandStatus[x] ##unblock waits end if else if x is among the lines of keys(laUrl) then ##http or ftp control socket ## check for two situations here ## first is a premature close on a socket when we know the data length ## second is for cases when we don't know the data length ## a normal close when we know the data length isn't handled here if laLength[laUrl[x]] > laReadBytes[laUrl[x]] then ##fixed dc 250103 put "Socket closed before end of file" into laUrlErrorStatus[laUrl[x]] if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put "false" into laStatus[laUrl[x]] ##unblock waits if x is among the lines of keys(laFTPCommandStatus) then ##may be waiting for a server reply put "socket closed" into laFTPCommandStatus[x] ##unblock waits end if else if laLength[laUrl[x]] is empty and char 1 to 4 of laUrl[x] is "http" then ##when we don't have a length if laStatus[laUrl[x]] is empty then ##assume download completed put empty into laUrlErrorStatus[laUrl[x]] end if put true into laStatus[laUrl[x]] ##unblock waits put "true" into laHttpDataDone[laUrl[x]] ##unblock waits end if else if x is among the lines of keys(laControlXDataMap)then##must be ftp remote data socket put laControlXDataMap[x] into tControlSocket put true into laFtpDataDone[laUrl[tControlSocket]] if laTransActvIP[tControlSocket] is among the lines of the openSockets then close socket laTransActvIP[tControlSocket] ##local data port during active transfers end if delete local laControlXDataMap[x] end if end socketClosed ------------------------------------------- ##SocketTimeout defaults to 10000 milliseconds. ##To change that one can set the "socketTimeoutInterval" to a different value. on socketTimeout x ulLogit "socket timeout" && x & cr ##LOG ##need to check whether data port or not if x is among the lines of keys(lvSocketToken) then ##trying to open a socket put "socket timeout" into lvSocketToken[x] delete local laSocketUser[x] else if x is lvFtpCommandSocket then ##handling libUrlFtpCommand if x is among the lines of keys(laFTPCommandStatus) then ##may be waiting for a server reply put "socket timeout" into laFTPCommandStatus[x] ##unblock waits end if else if x is among the lines of keys(laUrl) then ##http or ftp control socket if laLoadReq[laUrl[x]] then put "timeout" into laUrlLoadStatus[laUrl[x]] put "socket timeout" && x into laUrlErrorStatus[laUrl[x]] put "false" into laStatus[laUrl[x]] ##unblock waits if x is among the lines of keys(laFTPCommandStatus) then ##may be waiting for a server reply put "socket timeout" into laFTPCommandStatus[x] ##unblock waits end if close socket x delete local laSocketUser[x] else if x is among the lines of keys(laControlXDataMap)then##must be ftp remote data socket put laControlXDataMap[x] into tControlSocket put false into laStatus[laUrl[tControlSocket]] ##unblock waits put "socket timeout" into laFTPCommandStatus[tControlSocket] if laLoadReq[laUrl[x]] then put "timeout" into laUrlLoadStatus[laUrl[tControlSocket]] put "socket timeout" && x into laUrlErrorStatus[laUrl[tControlSocket]] else if x is a number then##local port for active ftp transfer put laControlXLocalMap[x] into tControlSocket if tControlSocket <> empty then put false into laStatus[laUrl[tControlSocket]] ##unblock waits put "socket timeout" into laFTPCommandStatus[tControlSocket] if laLoadReq[laUrl[tControlSocket]] then put "timeout" into laUrlLoadStatus[laUrl[tControlSocket]] put "socket timeout" && x into laUrlErrorStatus[laUrl[tControlSocket]] end if end if end socketTimeout -------------------------------------------- on socketError x, pErr ulLogit "socket error" && x & cr & pErr & cr ##LOG ##need to check whether data port or not if pErr is empty then put "unknown error" into pErr if x is among the lines of keys(lvSocketToken) then ##trying to open a socket put pErr into lvSocketToken[x] else if x is lvFtpCommandSocket then ##handling libUrlFtpCommand if x is among the lines of keys(laFTPCommandStatus) then ##may be waiting for a server reply put "socket error" into laFTPCommandStatus[x] ##unblock waits end if else if x is among the lines of keys(laUrl) then ##http or ftp control socket if laLoadReq[laUrl[x]] then put "error" into laUrlLoadStatus[laUrl[x]] put "error" && pErr into laUrlErrorStatus[laUrl[x]] put "false" into laStatus[laUrl[x]] ##unblock waits if x is among the lines of keys(laFTPCommandStatus) then ##may be waiting for a server reply put pErr into laFTPCommandStatus[x] ##unblock waits end if else if x is among the lines of keys(laControlXDataMap)then##must be ftp passive data socket put laControlXDataMap[x] into tControlSocket put false into laStatus[laUrl[tControlSocket]] ##unblock waits put pErr into laFTPCommandStatus[tControlSocket] if laLoadReq[laUrl[tControlSocket]] then put "error" into laUrlLoadStatus[laUrl[tControlSocket]] put "error" && pErr into laUrlErrorStatus[laUrl[tControlSocket]] else if x is a number then##local port for active ftp transfer put laControlXLocalMap[x] into tControlSocket if tControlSocket <> empty then put false into laStatus[laUrl[tControlSocket]] ##unblock waits put pErr into laFTPCommandStatus[tControlSocket] if laLoadReq[laUrl[tControlSocket]] then put "error" into laUrlLoadStatus[laUrl[tControlSocket]] put "error" && pErr into laUrlErrorStatus[laUrl[tControlSocket]] end if end if end socketError ---------------------------------------------- on libUrlResetAll if there is a stack "libUrl" then put empty into fld "log1" of stack "libURL" repeat for each line i in the openSockets close socket i end repeat ulDeleteLocals put true into lvJumpOut send "ulDeleteLocals" to me in 5 milliseconds end libUrlResetAll -------------------------------------------- on ulDeleteLocals repeat for each item e in line 3 of the localNames get "delete" && "local" && e do it end repeat end ulDeleteLocals ---------------------------------------------- on resetAll ## included for compatibility with previous versions ##ibUrlResetAll should be used instead libUrlResetAll end resetAll ----------------------------------------------- on ulFtpStopWatch x if x is among the lines of the OpenSockets then if lvFtpStopTime is empty or lvFtpStopTime is not a number then put 15 into lvFtpStopTime end if switch case laStopSec[x] >= lvFtpStopTime delete local laStopSec[x] delete local laStopUnit[x] put "QUIT" into tCmd get ulFtpCommand(tCmd,x) delete local laFtpCommandStatus[x] # write "QUIT" & CRLF to socket x ##tidy finish close socket x delete local laSocketUser[x] break case laStopUnit[x]=1 add laStopUnit[x] to laStopSec[x] send "ulFtpStopWatch " & x to me in 1 sec break case laStopUnit[x] = 0 break end switch else delete local laStopSec[x] delete local laStopUnit[x] end if end ulFtpStopWatch ---------------------------------------------- on libUrlFtpUpload pData,pUrl,pMessage put false into lvJumpOut put ulStripUrl(pUrl) into newUrl if char 1 to 3 of newUrl <> "ftp" then return "invalid url" end if if lvCount is empty then put "6923" into lvCount else #add 1 to lvCount end if switch case newUrl is among the lines of the keys of laLoadingUrls ##don't allow loads if the same url is waiting to load return "error URL is currently loading" with empty break default put pData into laPostData[newUrl] if pMessage <> empty then put the long id of the target &","& pMessage into laMessg[newUrl] end if put true into laLoadReq[newUrl] put 1 into laLoadingUrls[newUrl] #for tracking put "putData" into laAction[newUrl] put empty into laUrlErrorStatus[newUrl] put empty into laUrlLoadStatus[newUrl] put empty into laData[newUrl] ulGetFormat newUrl,lvCount if laUrlLoadStatus[newUrl] is "error" and not laCancelled[newUrl] then ulSendMessage newUrl ##send message now only if error occurred return "error" else if laCancelled[newUrl] then ##user cancelled after starting but before blocking point delete local laLoadedUrls[newUrl] delete local laUrlLoadStatus[newUrl] delete local laUrlErrorStatus[newUrl] delete local laStatus[newUrl] delete local laCancelled[newUrl] else return empty end if break end switch end libUrlFtpUpload ---------------------------------------------- on libUrlFtpUploadFile pFile,pUrl,pMessage put false into lvJumpOut put ulStripUrl(pUrl) into newUrl if char 1 to 3 of newUrl <> "ftp" then return "invalid url" end if open file pFile for binary read if the result is not empty then return the result end if put newUrl into laUrlByFile[pFile] if lvCount is empty then put "6923" into lvCount else #add 1 to lvCount end if switch case newUrl is among the lines of the keys of laLoadingUrls ##don't allow loads if the same url is waiting to load return "error URL is currently loading" with empty break #case newUrl is not among the lines of the keys of laLoadedUrls OR laUrlLoadStatus[newUrl] is not "cached" default if pMessage <> empty then put the long id of the target &","& pMessage into laMessg[newUrl] end if put true into laLoadReq[newUrl] put pFile into laFile[newUrl] put 1 into laLoadingUrls[newUrl] #for tracking put "putData" into laAction[newUrl] put empty into laUrlErrorStatus[newUrl] put empty into laUrlLoadStatus[newUrl] #put empty into laData[newUrl] ulGetFormat newUrl,lvCount if laUrlLoadStatus[newUrl] is "error" and not laCancelled[newUrl] then ulSendMessage newUrl ##send message now only if error occurred return "error" else if laCancelled[newUrl] then ##user cancelled after starting but before blocking point delete local laLoadedUrls[newUrl] delete local laUrlLoadStatus[newUrl] delete local laUrlErrorStatus[newUrl] delete local laStatus[newUrl] delete local laCancelled[newUrl] else return empty end if break end switch end libUrlFtpUploadFile ----------------------------------------------- on libUrlDownloadToFile pUrl,pFile,pMessage put false into lvJumpOut put ulStripUrl(pUrl) into newUrl open file pFile for binary write if the result is not empty then return the result end if if lvCount is empty then put "6923" into lvCount else #add 1 to lvCount end if switch case newUrl is among the lines of the keys of laLoadingUrls ##don't allow loads if the same url is waiting to load return "error URL is currently loading" with empty break #case newUrl is not among the lines of the keys of laLoadedUrls OR laUrlLoadStatus[newUrl] is not "cached" default if pMessage <> empty then put the long id of the target &","& pMessage into laMessg[newUrl] end if put true into laLoadReq[newUrl] put pFile into laFile[newUrl] put 1 into laLoadingUrls[newUrl] #for tracking put "getData" into laAction[newUrl] put empty into laUrlErrorStatus[newUrl] put empty into laUrlLoadStatus[newUrl] ulGetFormat newUrl,lvCount if laUrlLoadStatus[newUrl] is "error" and not laCancelled[newUrl] then ulSendMessage newUrl ##send message now only if error occurred return "error" else if laCancelled[newUrl] then ##user cancelled after starting but before blocking point delete local laLoadedUrls[newUrl] delete local laUrlLoadStatus[newUrl] delete local laUrlErrorStatus[newUrl] delete local laStatus[newUrl] delete local laCancelled[newUrl] else return empty end if break end switch end libUrlDownloadToFile ----------------------------------------------- function libUrlErrorData pUrl return laUrlErrorStatus[pUrl] end libUrlErrorData ----------------------------------------------- on libUrlSetFtpMode pMode ##default to passive if pMode is "active" or pMode is "a" then put "active" into lvFtpMode else put "passive" into lvFtpMode end if end libUrlSetFtpMode ---------------------------- on libUrlSetFtpListCommand pCommand if pCommand is "NLST" then put "NLST" into lvFtpListCommand else put "LIST" into lvFtpListCommand end if end libUrlSetFtpListCommand ----------------------------- function libUrlVersion return the cVersion of me end libUrlVersion ------------------------------ on libUrlSetLogField pField if word 1 of pField is "field" then put pField into tField else if pField is a number then put "field" && pField into tField else if word 1 of pField is "id" then put "field" && pField into tField else put "field" && quote & pField & quote into tField end if end if end if if exists(tField) then put the long ID of tField into tField##standardise put tField into lvLogField else put empty into lvLogField end if end libUrlSetLogField --------------------------- on libUrlSetStatusCallback pMessage,pObject ##pObject must be a long ID if pMessage <> empty and exists(pObject) then put pMessage & comma & pObject into lvStatusCallback else put empty into lvStatusCallback end if end libUrlSetStatusCallback --------------------------- function libUrlLastHttpHeaders return the lastHttpHeaders of me end libUrlLastHttpHeaders -------------------------- on libUrlSetCustomHttpHeaders pHeaders set the customHTTPHeaders of me to pHeaders end libUrlSetCustomHttpHeaders --------------------------- function libUrlLastRhHeaders return the lastRhHeaders of me end libUrlLastRhHeaders ---------------------------- on libUrlSetFtpStopTime pSecs if pSecs is empty or pSecs < 1 or pSecs is not a number then put 15 into lvFtpStopTime else put pSecs into lvFtpStopTime end if end libUrlSetFtpStopTime --------------------------- on ulSendMessage pUrl ##send any requested message on completion if laMessg[pUrl] is not empty then if item 2 of laMessg[pUrl] is not quote & "" & quote then put item 1 of laMessg[pUrl] into xmessg put item 2 of laMessg[pUrl] into omessg replace quote with empty in omessg send omessg && quote & pUrl & quote & "," & laUrlLoadStatus[pUrl] to xmessg in 0 milliseconds end if end if delete local laMessg[pUrl] end ulSendMessage ---------------------------- on ulSendCallback pUrl, pStatus if lvStatusCallback is empty then exit ulSendCallback put item 1 of lvStatusCallback into tMessage put item 2 of lvStatusCallback into tObject if exists(tObject) then #put laUrlErrorStatus[pUrl] into tStatus send tMessage && quote & pUrl & quote & comma & quote & pStatus & quote to tObject in 0 milliseconds end if end ulSendCallback ----------------------------- function ulFileLength pFile if there is a file pFile then put the directory into tSavedDir put pFile into tDir set the itemDel to "/" put item -1 of pFile into tFileName delete item -1 of tDir set the directory to tDir put the detailed files into tFileData set the directory to tSavedDir set the itemDel to comma split tFileData by cr and "," return item 1 of tFileData[urlEncode(tFileName)] else return "no file" end if end ulFileLength ------------------------------ on ulLogIt pMessage if exists(lvLogField) then put "put pMessage after fld" && word 2 to -1 of lvLogField into tExp do tExp end if end ulLogIt ------------------------------- on ulStartTickle ## safeguard against possible hangs in "wait for messages" loops if lvTickle is empty then put true into lvTickle send "ulTickleMe" to me in 1 seconds end if end ulStartTickle -------------------------- on ulTickleMe ## safeguard against possible hangs in "wait for messages" loops if the openSockets <> empty then send "ulTickleMe" to me in 1 seconds else put empty into lvTickle end if end ulTickleMe --------------------------- function isIPNumber pHost replace "." with empty in pHost replace ":" with empty in pHost replace "|" with empty in pHost return pHost is a number end isIPNumber ---------------------------- on ulCleanUpHttp x #x is socket put laLoadReq[laUrl[x]] into tlLoadReq ##holder put laConnectHost[laUrl[x]] into tConnectHost ulCleanUpHttpLocals laUrl[x] ## remove url referenced locals delete local laLoadReq[laUrl[x]] ##OK here?? ##delete socket referenced locals put laUrl[x] into tempUrl delete local laUrl[x] --prepare for next request if tlLoadReq then delete local laLoadingUrls[tempUrl] ## delete line 1 of laLoadQ[tConnectHost] ##commented out for 1.0.8r4 -- now done in ulNextHttpLoadRequest if the number of lines of laLoadQ[tConnectHost] = 0 then delete local laLoadQ[tConnectHost] ##important delete local laConnectID[tConnectHost] end if end if end ulCleanUpHttp ------------------------- on ulCleanUpHttpLocals pUrl ##crude clean up delete local laLength[pUrl] delete local laConnectHost[pUrl] delete local laAuth[pUrl] delete local laUser[pUrl] delete local laPasswd[pUrl] delete local laHost[pUrl] delete local laLongFileName[pUrl] delete local laLineNum[pUrl] delete local laTmpData[pUrl] delete local laTemp[pUrl] delete local laAction[pUrl] delete local laConn[pUrl] delete local laRhHeader[pUrl] delete local laNeedChunk[pUrl] delete local laStatusCode[pUrl] delete local laStatusMessage[pUrl] delete local laCode[pUrl] delete local laChunk[pUrl] delete local laHaveHeader[pUrl] delete local laHttpDataDone[pUrl] delete local laPostData[pUrl] delete local laReadBytes[pUrl] delete local laCurrentHttpHeaders[pUrl] end ulCleanUpHttpLocals ------------------------------ on ulCleanUpFtp x put laLoadReq[laUrl[x]] into tlLoadReq ##holder put laConnectHost[laUrl[x]] into tConnectHost #holder ulCleanUpFtpLocals laUrl[x] ## remove url referenced locals delete local laLoadReq[laUrl[x]] ##OK here?? ##close any data ports ##should be closed already, but if error occurred if laTransPasvIP[laUrl[x]] is among the lines of the openSockets then close socket laTransPasvIP[laUrl[x]] end if if laTransActvIP[x] is among the lines of the openSockets then ##local port close socket laTransActvIP[x] end if delete local laControlXLocalMap[laTransActvIP[x]] delete local laControlXDataMap[laTransPasvIP[laUrl[x]]] delete local laTransPasvIP[laUrl[x]] delete local laTransActvIP[x] ##delete socket referenced locals put laUrl[x] into tempUrl delete local laUrl[x] delete local laFtpCommandStatus[x] --prepare for next request if tlLoadReq then delete local laLoadingUrls[tempUrl] -- delete line 1 of laLoadQ[tConnectHost] ##commented out for 1.0.8r4 -- now done in ulNextFtpLoadRequest if the number of lines of laLoadQ[tConnectHost] = 0 then delete local laLoadQ[tConnectHost] ##important delete local laConnectID[tConnectHost] end if end if end ulCleanUpFtp ------------------------------ on ulCleanUpFtpLocals pUrl ##clean up locals delete local laConnectHost[pUrl] delete local laLength[pUrl] delete local laAuth[pUrl] delete local laUser[pUrl] delete local laPasswd[pUrl] delete local laHost[pUrl] delete local laLongFileName[pUrl] delete local laAction[pUrl] delete local laHome[pUrl] delete local laFtpDataDone[pUrl] delete local laMode[pUrl] delete local laPostData[pUrl] delete local laReadBytes[pUrl] delete local laWriteBytes[pUrl] end ulCleanUpFtpLocals ------------------------------ on ulCancelRequest pUrl put true into laCancelled[pUrl] put "error cancelled" into tError ulStopRequest pUrl,tError end ulCancelRequest ----------------------------- on ulStopRequest pUrl, pErrMessage put keys(laUrl) into tSocketKeys##test repeat for each line tKey in tSocketKeys if laUrl[tKey] = pUrl then put tKey into tItsSocket exit repeat end if end repeat if tItsSocket is among the lines of the openSockets then put false into laStatus[pUrl] ##should cause everything to wind up cleanly put pErrMessage into laUrlErrorStatus[pUrl] put empty into laData[pUrl] end if if laLoadReq[pUrl] then put "error" into laUrlLoadStatus[pUrl] delete local laData[pUrl] end if end ulStopRequest ----------------------------- on ulStoreData pUrl,@pData if laFile[pUrl] <> empty then write pData to file laFile[pUrl] if the result is not empty then put "error" && the result into tErr ulStopRequest pUrl,tErr end if else if laLoadReq[pUrl] <> empty then put pData after laLoadedUrls[pUrl] else put pData after laData[pUrl] end if end ulStoredata ----------------------------- function ulNextData pUrl if laFile[pUrl] is empty then put char 1 to 4096 of laPostdata[pUrl] into tData delete char 1 to 4096 of laPostData[pUrl] else read from file laFile[pUrl] for 4096 if the result <> empty and the result <> "eof" then put "error" && the result into tErr ulStopRequest pUrl,tErr else put it into tData end if end if return tData end ulNextData ------------------------------ function ulStripUrl pUrl ## clean out any whitespace before and after url put space & tab & cr into tString repeat while char 1 of pUrl is in tString delete char 1 of pUrl end repeat repeat while char -1 of pUrl is in tString delete char -1 of pUrl end repeat return pUrl end ulStripUrl -------------------------------- function ul_TraceLocals ##DEBUG ROUTINE, used in development repeat for each item e in line 3 of the localNames put e & cr after tRetVal put "put keys(" & e & ") & cr after tRetVal" into tDoString do tDoString end repeat return tRetVal end ul_TraceLocals -------------------------------- function ulFtpCommand pCommandString, pSocket ##executes ftp commands ##returns the response from the server (or ftpErr if error occurs) if pSocket is not among the lines of the openSockets then return "ftpErr, socket not open" end if if pCommandString is empty then return "ftpErr, no command to send" end if put empty into laFTPCommandStatus[pSocket] write pCommandString & CRLF to socket pSocket if the result <> empty then return "ftpErr," & the result read from socket pSocket for 1 line with message "ulGetFtpReply" if the result <> empty then return "ftpErr," & the result repeat while laFTPCommandStatus[pSocket] is empty if lvJumpOut then exit to top wait for messages end repeat return laFTPCommandStatus[pSocket] end ulFTPCommand ------------------------------------ function ulFtpWaitResponse pSocket ##used for collecting server responses ##that are not in response to a direct command ##for example when opening a connection to the server, and when transfers complete put empty into laFTPCommandStatus[pSocket] read from socket pSocket for 1 line with message "ulGetFtpReply" repeat while laFTPCommandStatus[pSocket] is empty if lvJumpOut then exit to top wait for messages end repeat return laFTPCommandStatus[pSocket] end ulFtpWaitResponse ------------------------------------ on ulGetFtpReply pSocket,pReply ##reads data from the command port ##generally called by ulFTPCommand, but also by ulFtpWaitResponse ulLogIt pReply##LOG put line -1 of pReply into tReply ##should only be one line get char 1 to 3 of tReply if it is an integer and it >= 100 then put it into tReplyNum if char 4 of tReply <> "-" then put tReply into laFTPCommandStatus[pSocket] else read from socket pSocket for 1 line with message "ulGetFtpReply" if the result <> empty then put "ftpErr," & the result into laFTPCommandStatus[pSocket] end if end if else read from socket pSocket for 1 line with message "ulGetFtpReply" if the result <> empty then put "ftpErr," & the result into laFTPCommandStatus[pSocket] end if end if end ulGetFtpReply --------------------------------- function ulFtpGoodReply pReply, pCommand ##compares a reply code against a predetermined list ##of "good" reply codes for a particular command if item 1 of pReply is "ftpErr" then return false put the cFtpGoodCodes[word 1 of pCommand] of me into tGoodCodes if word 1 of pReply is among the items of tGoodCodes then return true else return false end if end ulFtpGoodReply ------------------------------------- function libUrlFtpCommand pCommand, pHost, pUser, pPass local tHost,tPort put false into lvJumpOut if lvCount is empty then put "6923" into lvCount end if ##separate host and port put "([^:]*)(.*)" into tRegEx if not matchText(pHost,tRegEx,tHost,tPort) then return "error Invalid host address" put tHost into tTempHost if tPort is empty then put ":21" into tPort ##get IP address replace "." with empty in tTempHost replace ":" with empty in tTempHost if tTempHost is not a number then get hostnameToAddress(tHost) if the result is empty then put line 1 of it & tPort into tConnectHost else return "error" && the result end if else put tHost & tPort into tConnectHost end if ##set anonymous user if needed if pUser is empty then put "anonymous" into pUser put "guest" into pPass end if ##make dummy url to use other parts of libUrl put "ftp:" & pCommand into tDummyUrl ## make laUser and laPasswd entries put pUser into laUser[tDummyUrl] put pPass into laPasswd[tDummyUrl] ##make laConnectHost entry so we can use ulWhichSocket ##laConnectHost has format host:port|user put tConnectHost & "|" & pUser into laConnectHost[tDummyUrl] ##do we have an open socket for this user/host combination? put ulWhichSocket(tDummyUrl) into tSocket put tSocket into lvFtpCommandSocket ##don't need any more delete local laUser[tDummyUrl] delete local laPasswd[tDummyUrl] delete local laConnectHost[tDummyUrl] put ulFtpLogon(tSocket, pUser,pPass) into tLogonReply if tLogonReply is empty then put ulFtpCommand(pCommand, tSocket) into tFtpReply if laStopUnit[tSocket] = 0 then put "1" into laStopUnit[tSocket] send "ulFtpStopWatch " & tSocket to me in 50 milliseconds end if delete local lvFtpCommandSocket return tFtpReply else delete local lvFtpCommandSocket return tLogonReply end if end libUrlFtpCommand --------------------------- function ulFtpLogon pSocket, pUser, pPass put "0" into laStopUnit[pSocket] put "0" into laStopSec[pSocket] ulStartTickle ##safeguard routine if pSocket is not among the lines of the openSockets then get ulOpenSocket(pSocket) if not it then return it ##error opening socket ------------------------get server response (220) put ulFtpWaitResponse(pSocket) into tReply if not ulFtpGoodReply(tReply, "connect") then return tReply end if --------------- put "USER " & pUser into tCmd put ulFtpCommand(tCmd,pSocket) into tReply if not ulFtpGoodReply(tReply, tCmd) then return tReply end if ---------------------- put "PASS " & pPass into tCmd put ulFtpCommand(tCmd,pSocket) into tReply if not ulFtpGoodReply(tReply, tCmd) then return tReply end if end if return empty end ulFtpLogon ------------------------------ ########################################### ######socket opening routines################## ########################################### --------------------------------------------------------------- function ulOpenSocket x put empty into lvSocketToken[x] put the milliseconds into lvSocketOpenStart[x] open socket to x with message "ulGotSocket" if the result is not empty then return the result end if send "ulSocketTimeout" && x to me in 500 milliseconds put the result into lvSocketOpenMessageID[x] repeat until lvSocketToken[x] is not empty if lvJumpOut then exit to top wait for messages end repeat cancel lvSocketOpenMessageID[x] delete local lvSocketOpenStart[x] delete local lvSocketOpenMessageID[x] put lvSocketToken[x] into tSocketToken ##swap out so we can delete persistent local delete local lvSocketToken[x] if not tSocketToken then if x is among the lines of the openSockets then close socket x end if end if return tSocketToken end ulOpenSocket ------------------------------------------------- on ulGotSocket x put true into lvSocketToken[x] end ulGotSocket ------------------------------------------------ on ulSocketTimeout x if the milliseconds - lvSocketOpenStart[x] > the socketTimeoutInterval then put "timeout" into lvSocketToken[x] else send "ulSocketTimeout" && x to me in 500 milliseconds put the result into lvSocketOpenMessageID[x] end if end ulSocketTimeout ' U@U HelveticaU Helvetica @U W @W UArial WArialUUW@U@U@WW@UUUArialWArial U Helvetica U W U AU Uarial UarialUarial @U UGenevaUGeneva@UGeneva@WGenevaU helveticaU helveticaW helveticaU helveticaW helveticaW helveticaU helveticacFtpGoodCodesPASV227SIZE213PWD257LIST125,150MKD257PORT200CWD250transferComplete226STOR125,150NLST125,150Connect220DELE250RMD250MODE200USER230,331TYPE200QUIT221ABOR225,226RETR125,150PASS230,202 Pon resizeStack get the rect of this card add 8 to item 1 of it add 48 to item 2 of it subtract 8 from item 3 of it subtract 8 from item 4 of it set the rect of field 1 to it set the right of button 2 to item 3 of it end resizeStack %Q`a Pon preOpenCard resizeStack end preOpenCard on resizeStack get the rect of this card add 8 to item 1 of it add 8 to item 2 of it subtract 8 from item 3 of it subtract 8 from item 4 of it set the rect of field 1 to it end resizeStack %QbResetEp#on mouseUp resetAll end mouseUp  @ log1)j0  e` 1da 8`HelpEp"on mouseUp go next end mouseUp @ b p"on mouseUp go next end mouseUp A a  LibUrl "  LibUrl is the script library used by Revolution and Metacard to implement the Transcript/Metatalk commands and functions that use HTTP and FTP urls. o o y nIt is used when the following Transcript/Metatalk commands and functions are called with HTTP or FTP urls: - load url [with message ]  unload url  get url  put into url  post to url  delete url  the cachedUrls  urlStatus() ?It also recognizes and implements the following properties:  the httpheaders  the httpProxy qIn addition, the library contains a few handlers and functions that can be called directly from your scripts: 1 libUrlFtpUpload , [, ]  libUrlErrorData()  libUrlSetFtpMode  libUrlResetAll % libUrlSetFtpStopTime  libUrlSetLogField  libUrlVersion()  Notes: " +load url [with message ] $*  load downloads the url and places it into a cache. The cached data will then be used in subsequent references to that url instead of it being downloaded again. Be sure to unload the url (using unload url) when you no longer need it. %   %  The optional message parameter will cause that message to be called when the download completes (or when an error occurs). Two parameters are passed to the message: the url and its urlStatus. The message should be in the same script as the load command.  on mouseUp ; put "http://www.xx.com/images/mykids.jpg" into tUrl - load url tUrl with message "loadDone"  end mouseUp  on loadDone pUrl, pStatus # if pStatus is "cached" then - put url pUrl into image 1 of card 1 else " answer "Download failed"  end if  end loadDone  wload is a "non-blocking" command. This means the url will load in the background while the script continues to run. %  r HThis allows you to monitor downloads, for example with a progress bar. 2 2 9  on mouseUp A put "http://www.xxxxxx.com/images/mykids2.jpg" into tUrl  load url tUrl  showStatus  end mouseUp  on showStatus A put "http://www.xxxxxx.com/images/mykids2.jpg" into tUrl ) put urlStatus(tUrl) into tStatus * put tStatus ##show in message box I if tStatus is not among the items of "cached,error,timeout" then 5 send "showStatus" to me in 50 milliseconds  end if  end showStatus  3See below for more information about urlStatus. Note that because the load url command is now executed in a script, you must be careful not to include any "wait" commands in your script before the load has completed. "wait" will stop all scripts running, including libUrl. The following script will not work:  % %      %K  on mouseUp %     A put "http://www.xxxxxx.com/images/mykids2.jpg" into tUrl  load url tUrl 5 wait until urlStatus(tUrl) is "cached" ##BAD  @,  end mouseUp  unload url $  unload removes a previously loaded url from the cache and thus frees up memory. You should unload urls when you no longer need them. %   get url $  /get url downloads the url or, if the url is cached from a previous load command, retrieves it from the cache. If it completes successfully, the downloaded data will be in the variable it , and the result function will return empty. If an error occurs, the result function will return an error message. %   %   %  1 %# % %%  on mouseUp     @ put "http://www.xxxxxx.com/images/mykids.jpg" into tUrl  get url tUrl $ if the result is empty then  put it into image 1 else  answer the result  end if  end mouseUp   Typically the error message will consist of the word "error" followed by a string containing more information about the error. Where appropriate, the error string will be the string returned by the http or ftp server including the server response code. For example:  error 404 File not found Note that the variable it will not always be empty when an error occurs. Http servers typically return an "error page" for certain errors (401, 404, etc.) libUrl will try to download such data as well, and return it in the it variable. Because of this, you should always check the result function after a get url command. You can't assume that because it is not empty no error occurred.  %   %  4 %  ! %3  <( %d  f#  get url is a "blocking" command. This means that the script lines following the get command will not continue until get url completes. However, because of the nature of libUrl, it doesn't block other scripts or user actions. If the get url command is in a button, the user could feasibly click the button again before the first mouseUp has completed. Or he or she may click another button that gets another url. In cases when a url is currently downloading from a get url command, subsequent get url commands will return the error "error Previous request has not completed." Because of this, you may want to disable interface elements while a get url command is completing, or take some other action that is appropriate to your application. %  m %t  {m %  %   %   %  ] ((similar script in a series of buttons)    global gUrlBlocking  on mouseUp ? put "http://www.xxxxxx.com/images/mykids1.jpg" into tUrl # if gUrlBlocking is true then beep else # put true into gUrlBlocking  get url tUrl $ put false into gUrlBlocking $ if the result is empty then  put it into image 1 else  answer the result  end if end if  end mouseUp  The same is true for the other "blocking" commands (post, put, delete). Basically only one url can be handled at a time with any of these commands. W %W  Z< put into url $   The put command will save the data to the specified url on an ftp server. If it completes successfully, the result function will return empty. If an error occurs, the result function will return an error message. In the same way as for get url the error message will consist of the word "error" followed by a string containing more information about the error. Where appropriate, the error string will be the string returned by the ftp server including the server response code. For example: error 530 Login incorrect.  %   % Example  on mouseUp M put "ftp://dave:evad345@ftp.xxxxxx.com/images/mykids.txt" into tUrl put field 1 into tData ! put tData into url tUrl % if the result is empty then & answer "Upload successful"  else 4 answer "Upload failed" & cr & the result  end if  end mouseUp  I*See below about including user names and passwords for authorization NSee get url for information about the "blocking" behavior of this command.  %  A post to url $  The post command is used to post data to an http server process such as cgi. If it completes successfully, the result function will return empty and the response from the server will be in the variable it. If an error occurs, the result function will return an error message.  %  c %k  uU %   %  * NSee get url for information about the "blocking" behavior of this command.  %  A  on mouseUp @ put "http://www.xxxxxx.co.uk/cgi-bin/sendform" into tUrl , put "subject=Post text" into tString 2 put "&to=dave@xxxxxxx.co.uk" after tString H put "&message=This is a test message from libUrl." after tString F put "&page=http://www.xxxx.co.uk/submitted.html" after tString  put crlf after tString post tString to url tUrl # if the result is empty then  put it into field 1 else  answer the result  end if  end mouseUp  delete url $  delete url will delete the file from an ftp server. If it completes successfully, the result function will return empty. If an error occurs, the result function will return an error message. %  H %R  \1 %  * the cachedUrls $ ) $  The urlStatus function returns the status of urls that have previously been referenced with a load url command. It will return one of the following:  %  O  \ %^ g. queued %   contacted  requested A loading,x,y (where x = downloaded bytes and y = total bytes) timeout error cached  The function can be used to monitor files as they download (see load url above for an example), or to check the status of a url after the load has completed. @ %@  HX Note that if you upload data with libUrlFtpUpload (see below), instead of "loading" and "cached", urlStatus will return "uploading" and "uploaded" respectively. " %"  1r Also note that "queued" is a new possible value. This is returned when a load url request has been made, and the url is placed on a queue while previous requests to the same host are completed. L %L  Ts  Library interface "  The following library routines can be accessed directly from your scripts. More routines may be added from time to time. It's also possible that some of these routines may be incorporated into the Transcript/Metatalk language at some stage, although with different syntax. /libUrlFtpUpload , [, ] $.  This handler is basically the upload equivalent of the load url command and can be used to upload data to an ftp server. It is a "non-blocking" routine, so your script will continue to execute as the upload takes place in the background which allows the urlStatus to be monitored as the file is uploading. The optional message parameter lets you denote a message that will be called when the upload completes. 7 %7  ?] aNote that urlStatus will return "uploading,x, y" and "uploaded" in replace of "loading,x,y" and "cached" when libUrlFtpLoad is used. Also note that urlStatus will continue to return "uploaded" for this url until you unload it with the unload url command. For this reason, you are advided to unload the url when you no longer need to know its status.  %   %  N %  k on mouseUp B put "ftp://ftp.xxxxxx.com/literature/sadlife.txt" into tUrl  put field 1 into tData " libUrlFtpUpload tData, tUrl  showStatus  end mouseUp  on showStatus B put "ftp://ftp.xxxxxx.com/literature/sadlife.txt" into tUrl ' put urlStatus(tUrl) into tStatus ( put tStatus ##show in message box I if tStatus is not among the items of "uploaded,error,timeout" then 2 send "showStatus" to me in 50 milliseconds end if  end showStatus  libUrlErrorData() $  This function allows you to get further error data about a url whose urlStatus is "error". It will return the same string as the result of a get url command. Typically, this will be the response string returned by an http or ftp server. For example: "404 File not found"  %  | @ put "ftp://ftp.xxxxxx.com/literature/sadlife.txt" into tUrl ; ; ' if urlStatus(tUrl) is "error" then get libUrlErrorData(tUrl) ; put "An error occurred" & cr & it into field "error" end if  libUrlSetFtpMode $  6This command allows you to switch between passive and active FTP data transfers. can be either "active" or "passive". Actually, as passive is now the default, anything except "active" will cause the transfer to use passive mode. Any change will persist for the remainder of the session (i.e. until you application exits) or until you issue the command again. When your application starts, passive transfers will be used by default. So if you know you are going to be using active transfers, you should include this command before initiating any transfers.  If you don't know the difference between passive and active transfers, don't worry. Nine times out of ten, either will work fine. However, if you find that you are having trouble with ftp transfers, you might want to try switching to see if it makes a difference.  libUrlSetFtpMode "active"  libUrlResetAll $ Warning: Don't use this command lightly. In fact, you should never have to use it at all. It closes all open sockets and clears all variables used by libUrl, including any cached data. It's basically the "panic buton" when things go wrong, so it may be useful in development. d %d  g "libUrlSetFtpStopTime $!  This command lets you set the number of seconds that a socket used for an ftp control connection remains open after a transaction completes. must be an integer greater than 0. The default value is 15 seconds. If a new request to the same host is made while the socket is open, the connection is re-used. Note that libUrl makes no attempt to keep the connection open, so the server may close the connection first. libUrlSetLogField $  This command lets you set a field that will collect log data. The field parameter should be the long id of the field you wish to use. libUrlVersion() $ This returns the current version of the libUrl library. There is no special significnce to the numbers, but will be useful for reference when reporting any problems or difficulties. Authorization $  If an http or ftp url requires authorization with a user name and password, these can be included in the url in the following way: ://:@ Examples B http://dave:evad123@www.xxxxxx.com/secrets/thetruth.html = ftp://daphne:enhp456@ftp.xxxxxx.com/gossip/really.jpg For anonymous ftp, no name or password is required. The library will add the "anonymous" user name and a dummy password automatically. If the user name or password contains non-alphanumeric characters (specifically the ":", "@", "/" , "." or "|" characters if these are allowed), then these should be urlEncoded before being put into the url.  put "jim" into tName $ put "jsmith@abc.com" into tPass W put "ftp://" & tName & ":" & urlEncode(tPass) & "@ftp.xxx.com/title.txt" into tUrl  get url tUrl   Acknowledgements $  gDevelopment of libUrl for use with both Revolution and Metacard is sponsored by Runtime Revolution. The major credit must go to Andu Novac who put together the first versions from scratch. This project would be going nowhere without his efforts, especially in implementing the contents of the various rfc's for ftp and http. ;Thanks also to contributors Reed Martin and John Kuehne PThe library is currently maintained by Dave Cragg (dcragg@lacscentre.co.uk).  February 24, 2002  &    ` ?