[comp.windows.news] ftpface.ps

don@TUMTUM.CS.UMD.EDU (Don Hopkins) (05/26/89)

Here's a really gross hack to display the Usenix "FaceSaver" images
that are on uunet's anonymous ftp directory. It's a PostScript program
that opens a socket to uunet's ftp server, logs in as anonymous,
retreives the face that you want, uncompresses it if necessary, and
converts it into a canvas, which it returns to you to do with what you
please. It also caches faces in /tmp, where it checks before trying
uunet.

NeWS might have problems connecting to uunet, and you may have to try
several times in a row to get it to work. (If you can get an regular
ftp connection there reliably, then keep trying.) No guarentee this
will be usable over anything less than a T1 link. Alternativly, you
could get the FaceSaver database by some other means and put on a
local ftp directory, and change the string in the program.  Or just
use the part of the program that reads in a FaceSaver format image as
a canvas.

Tell me if you get it to work! (Don't tell me if you print it out and
wrap fish with it! ;-)

	-Don

%!
%
% NeWS program to suck faces from uunet's ftp server.
% Don Hopkins
% Lots of code Stoken from Stan Switzer
%
% Copyright (C) 1989 by Don Hopkins. All rights reserved.
% This program is provided for unrestricted use, provided that this 
% copyright message is preserved. There is no warranty, and no author 
% or distributer accepts responsibility for any damage caused by this 
% program. 
%

% USER anonymous
% PASS suck_face
% CWD <FaceDir>/<Place>
% TYPE I
% PORT 128,8,128,49,4,238
% RETR <Person>[.Z]
% QUIT

systemdict begin

/GetFace { % Host FaceDir Place Person => can / null
  { 40 dict begin
      /Person exch def % File name of person's face
      /Place exch def % Directory name of person's place
      /FaceDir exch def % Ftp server's faces directory
      /Host exch def % Ftp server's host name
      /User (anonymous) def % Ftp server login
      /Pass (suck_face) def % Ftp login password
      /Cache (/tmp) def
      Place Cache (%/%) sprintf (r) { file } errored {
        pop (mkdir ) exch append forkunix
	.25 60 div sleep
      } { closefile } ifelse
      /TmpFile Person Place Cache (%/%/%) sprintf def
      TmpFile (r) { file } errored {
	pop pop
      } {
	closefile 
(Face file % already cached!\n) [TmpFile] dbgprintf
	TmpFile readface
	currentprocess killprocess
      } ifelse
      /Server (%socketc21.) Host append (rw)
	{ file } errored {
	  null
(Can't connect to ftp server on %!\n) [Host] dbgprintf
	  currentprocess killprocess
	} if
      def
      /LocalPort Server getsocketlocaladdress
        (;) search { exch pop exch pop } if
	(.) search { pop pop } if
	cvi
      def
      LocalPort 0 le LocalPort 65535 gt or {
	null
(Can't figure local socket address: %\n) 
[Server getsocketlocaladdress] dbgprintf
        currentprocess killprocess
      } if
      /R { % str => str -- read from socket
	Server exch readline pause
	dup { (<--- %\n) [3 index] } { (<--- EOF\n) [] } ifelse dbgprintf
      } def
      /W { % str => - -- write socket
	(---> %) [2 index] dbgprintf
	Server exch writestring Server flushfile 
      } def
      /SR { % (good) (bad) timeoutsec => good? true -or- false -- srch
	/Time exch 60 div def
	/Interest createevent dup begin
	    /Name /DoneEvent def
	end dup expressinterest def
	/Bad exch def
	/Good exch def
	/Match1 { 
	  anchorsearch { pop pop true } { pop false } ifelse 
        } def
	/Match {
	  dup type /arraytype eq {
	    false exch
	    { 2 index exch Match1 { pop true exit } if
	    } forall
	    exch pop
	  } {
	    Match1
	  } ifelse
	} def
	/Str 200 string def
	/Proc { % fork
	  { % loop
	    Str R not { /Ugly exit } if
	    dup Good Match { pop /Good exit } if
	    dup Bad Match { pop /Bad exit } if
	    pop
	  } loop
	  Interest createevent copy dup /Action 4 -1 roll put sendevent
	} fork def
	/Timer Interest createevent copy dup begin
	  /Action /TimeOut def
	  /TimeStamp currenttime Time add def
	end dup sendevent def
	awaitevent /Action get
	dup /TimeOut eq {
	  Proc killprocess
	  pop /Ugly
	} if
	dup /Ugly eq {
	  Timer recallevent
	  pop false
	} {
	  /Good eq true
	} ifelse
	Interest revokeinterest
      } def
      /Sucker null def
      /StartSucking {
	/Listener null def
	6 {
	  /PortNumber LocalPort def
(Trying port %...\n) [PortNumber] dbgprintf
	  (%socketl) PortNumber 10 string cvs append (r) { file } errored {
	    pop pop
	  } {
	    /Listener exch def
	    exit
	  } ifelse
	} repeat
	Listener null eq { null } {
(Got it!\n) [] dbgprintf
	  { Listener acceptconnection } errored { 
	    null 
(Drat! Doesn't accept!\n) [] dbgprintf
	  } {
            /Out TmpFile Uncompress? { (.Z) append } if (w) file def
	    /Bytes 0 def
	    /StartTime currenttime def
	    /In exch def
(Accepted %!\n) [In] dbgprintf
	    { pause
	      In 256 string readstring 
	      exch
	      /Bytes 1 index length Bytes add def
	      Out exch writestring
	      (#) [] dbgprintf
	      not { exit } if
	    } loop
	    Out flushfile
	    Out closefile In closefile
	    ( Done.\nTransfered % bytes in % seconds (% bytes/sec).\n)
	    [ Bytes  currenttime StartTime sub 60 mul  2 copy div
	    ] dbgprintf
	    /In null def /Out null def
	    Uncompress? {
	      (Uncompressing...\n) [] dbgprintf
	      { 25 dict begin % fork (to keep events from being confused)
		  /Interest createevent dup begin
		    /Name [ /TimeOut /Done ] def
		    /Action TmpFile def
		  end dup expressinterest def
		  /Timer Interest createevent copy dup begin
		    /Name /TimeOut def
		    /TimeStamp currenttime 30 60 div add def
		    /Action TmpFile def
		  end dup sendevent def
		  TmpFile dup
		  (rm -f % ; uncompress %.Z ; ) sprintf
		  (echo "createevent dup begin /Name /Done def ) append
		  (/Action \() append TmpFile append (\) def ) append
		  (end sendevent" | psh) append forkunix
		  awaitevent /Name get /TimeOut eq {
		    false
		  } {
		    Timer recallevent
		    true
		  } ifelse
	        end
	      } fork waitprocess % => success?
	      { TmpFile readface } { null } ifelse
	    } {
	      TmpFile readface
	    } ifelse
	  } ifelse
	  Listener closefile
	  /Listener null def
	} ifelse
      } def

      /Sucker null def
      { % only once through:
	(220 ) (xxx ) 15 SR
	not { null exit } if not { null exit } if
	(USER ) User append (\n) append W
	(331 ) [ (530 ) (500 ) ] 15 SR
	not { null exit } if not { null exit } if
	(PASS ) Pass append (\n) append W
	(230 ) [ (530 ) (500 ) ] 20 SR 
	not { null exit } if not { null exit } if 
	Place FaceDir (CWD %/%\n) sprintf W
	(250 ) (550 ) 20 SR
	not { null exit } if not { null exit } if 
	(TYPE I\n) W
	(200 ) (500 ) 20 SR
	not { null exit } if not { null exit } if 
	/Uncompress? false def
	/Sucker { StartSucking } fork def pause
	Person (RETR %\n) sprintf W
	(150 ) [ (550 ) ] 20 SR
	not { null exit } if { % got it
	  (226) (xxx ) 100 SR
	  not { null exit } if not { null exit } if
	} { %  try .Z
	  /Uncompress? true def
	  Person (RETR %.Z\n) sprintf W
	  (150 ) [ (550 )  ] 20 SR
	  not { null exit } if { % got it
	    (226 ) (xxx ) 200 SR
	    not { null exit } if not { null exit } if 
	  } { null exit } ifelse
	} ifelse
	Sucker waitprocess
	/Sucker null def
	exit
      } loop
      Sucker null ne { Sucker killprocess /Sucker null def } if
      (QUIT\n) W
      Server closefile
    end
  } fork
  5 1 roll pop pop pop pop
  waitprocess
} def

% ----------------------------------------------------------------------

% This should probably image into the area given by the "Image: x y d"
% field, but I'm lazy.

/HeaderDict 20 dict def
HeaderDict begin
  /PicData: {
    cvx exec /Depth exch def /Height exch def /Width exch def
  } def
end % HeaderDict

/readface { % filename => can
  20 dict begin
  mark exch { % mark filename
    /File exch (r) file def
    /Width 96 def /Height 128 def /Depth 8 def % Defaults
    0
    { File 256 string readline not { barf! } if
      /Line exch def
(Header: % <%>\n) [Line dup length exch] dbgprintf
      Line length 0 eq { exit } if
      Line token {
	HeaderDict 1 index known {
	  HeaderDict exch get exec
	} {
	  pop pop
	} ifelse
      } if
    } loop

    % NeWS seems to ignore the matrix...
    Width Height Depth [Width 0 0 Height neg 0 Height] {
      File 256 string readhexstring not { pop (Barf?! ) } if
    } buildimage
    /Can exch def
    File closefile
    /File null def
    % ...So we have to flip it by hand.
    Can setcanvas
    0 Height translate  Width Height neg scale
    Can imagecanvas
    cleartomark
    Can
  } stopped { cleartomark null } if
  end
} def

/showcan { % can => -
  gsave
    framebuffer setcanvas
    gsave dup setcanvas clippath pathbbox grestore
    scale pop pop
    4 4 scale
    imagecanvas
  grestore
} def

/Host (uunet.uu.net) def
/FaceDir (faces) def
/f {
  Host FaceDir 4 2 roll
  GetFace dup null eq { pop } { showcan } ifelse
} def

end % systemdict

(well.uucp) (bandy)
f