ftp.nice.ch/pub/next/connectivity/mail/bundles/EnhanceMail.2.2p1.s.gnutar.gz#/EnhanceMail-2.2p1/Source/XImageURL.m

This is XImageURL.m in view mode; [Download] [Up]

/* -*-C-*-
*******************************************************************************
*
* File:         XImageURL.m
* RCS:          /usr/local/sources/CVS/EnhanceMail/XImageURL.m,v 1.6 1998/06/27 00:58:28 tom Exp
* Description:  
* Author:       Carl Edman
* Created:      Fri Oct 20 14:47:00 1995
* Modified:     Mon Jun 24 10:26:29 1996 (Carl Edman) cedman@capitalist.princeton.edu
* Language:     C
* Package:      N/A
* Status:       Experimental (Do Not Distribute)
*
* (C) Copyright 1995, but otherwise this file is perfect freeware.
*
*******************************************************************************
*/

#import <libc.h>
#import "EnhanceMail.h"
#import "XImageURL.h"
#import "Preferences.h"
#import "SimpleString.h"
#import "regexp.h"
#include <netdb.h>

#define MSG_OPEN_EXTERNAL_ATTACHMENT NXLoadLocalizedStringFromTableInBundle("Alerts", nil, "Open External Attachment", NULL)
#define MSG_RETRIEVE_HTTP NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "Retrieving %s from %s via http...", NULL, Message for HTTP retrieval)

#define LOCALCOPY(to,from,len) { to=alloca(len+1); strncpy(to,from,len); to[len]='\0'; }

BOOL imagepathExpanded = NO;

static const char *imagepath[]=
{
   "/tmp",
   "~/Library/Mail/Images",
   "/LocalLibrary/Mail/Images",
   "/NextLibrary/Mail/Images",
   "#/Images",
   0
};

@implementation NXImage(XImageURL)

+ (BOOL)grabURL:(const char *)url to:(const char *)localpath
{
   static regexp *ftprx=0;
   static regexp *httprx=0;
   BOOL proxy=NO;

   if (!url || !*url) return NO;
   
   if (ftprx==0)
      ftprx=regcomp("^ftp://([^:/ ]*(:[^/@ ]*)?@)?([^/]*/)(([^/]*/)*)([^/;]*)$");

   if (httprx==0)
      httprx=regcomp("^http://([^:/ ]*)(:[0-9]+)?(/[^;]*)$");

   // For now, assume HTTP proxy also proxies ftp requests.
   if (EnhanceHTTPProxy && *EnhanceHTTPProxy)
      proxy=YES;

   if (!proxy && regexec(ftprx,url))
   {
      char *host,*dir,*filename,*user,*pass,*userpass,*path;
      id fetcher=[MimeFetcher new];

      if (ftprx->startp[1]&&ftprx->startp[2])
      {
         LOCALCOPY(user,ftprx->startp[1],ftprx->startp[2]-ftprx->startp[1]);
         LOCALCOPY(pass,ftprx->startp[2]+1,ftprx->endp[2]-ftprx->startp[2]-1);
         userpass=alloca(strlen(user)+strlen(pass)+2);
         sprintf(userpass,"%s %s",user,pass);
      }
      else if (ftprx->startp[1])
      {
         LOCALCOPY(user,ftprx->startp[1],ftprx->endp[1]-ftprx->startp[1]-1);
         if (pass=index([fetcher anonUserPass],' ')) pass++; else pass="anonymous";
         userpass=alloca(strlen(user)+strlen(pass)+2);
         sprintf(userpass,"%s %s",user,pass);
      }
      else
      {
         const char *c=[fetcher anonUserPass];
         userpass=strcpy(alloca(strlen(c)+1),c);
      }
      
      LOCALCOPY(host,    ftprx->startp[3],ftprx->endp[3]-ftprx->startp[3]-1);
      LOCALCOPY(dir,     ftprx->startp[4],ftprx->endp[4]-ftprx->startp[4]-1);
      LOCALCOPY(filename,ftprx->startp[6],ftprx->endp[6]-ftprx->startp[6]);
      
      LOCALCOPY(path,localpath,strlen(localpath));
      
      if ([fetcher ftpFrom:host directory:dir filename:filename mode:"binary" forUserPass:userpass to:path]==NO)
         return NO;
      
      if (access(path,R_OK)!=0)
         return NO;
      
      return YES;
   }

   if (regexec(httprx,url) || (proxy && regexec(ftprx,url)))
   {
      char *hostname="localhost",*path="/",*port="80";
      char buf[1024],*pos;
      struct sockaddr_in http;
      struct hostent *hp;
      int totlen=-1,rcvlen=0,len;
      int ifd=-1,ofd=-1;
      BOOL success=NO;
      BOOL httpseen=NO;
      Progressor *progress=nil;

      if (proxy)
      {
	 // Allow different forms of proxy spec.
         if (!regexec(httprx,EnhanceHTTPProxy))
	 {
	    sprintf(buf,"%s/",EnhanceHTTPProxy);
	    if (!regexec(httprx,buf))
	    {
	       sprintf(buf,"http://%s/",EnhanceHTTPProxy);
	       if (!regexec(httprx,buf)) goto httpend;
	    }
	 }
      }
   
      if (httprx->startp[1])
         LOCALCOPY(hostname,httprx->startp[1],httprx->endp[1]-httprx->startp[1]);

      if (httprx->startp[2])
         LOCALCOPY(port,httprx->startp[2]+1,httprx->endp[2]-httprx->startp[2]-1);

      if (proxy)
	 path=(char *)url;
      else if (httprx->startp[3])
         LOCALCOPY(path,httprx->startp[3],httprx->endp[3]-(httprx->startp[3]));
      
      sprintf(buf,MSG_RETRIEVE_HTTP,strrchr(path,'/')+1,hostname);
      if ((progress=[Progressor newWithTitle:MSG_OPEN_EXTERNAL_ATTACHMENT message:buf])==nil) goto httpend;
      [progress setShowProgress:NO];
      [progress beginModalSession];
      
      if ((hp = gethostbyname(hostname)) == NULL)
      {
	 // A numeric internet address, maybe?
	 struct in_addr addr;

	 if ((addr.s_addr = inet_addr(hostname)) == -1 ||
	     (hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == NULL)
	 {
	    goto httpend;
	 }
      }
      bzero((char *)&http, sizeof(http));
      bcopy(hp->h_addr,(char *)&http.sin_addr,hp->h_length);
      http.sin_family = hp->h_addrtype;
      http.sin_port = htons(atoi(port));
      if ((ifd=socket(AF_INET, SOCK_STREAM, 0))==-1) goto httpend;
      if (connect(ifd,(struct sockaddr *) &http,sizeof(http))==-1) goto httpend;
      
      sprintf(buf,"GET %s HTTP/1.0\r\nUser-Agent: EnhanceMail/%s\r\nAccept: image/tiff\r\n\r\n",path,EnhanceVersion);
      write(ifd,buf,strlen(buf));

      pos=buf;
      while(![progress cancelled]&&((len=read(ifd,pos,(buf+sizeof(buf))-pos))>0))
      {
         char *end=pos+len,*c,*d;

         for(c=buf,d=buf;c<end;c++)
	 {
            if (*c!='\n') continue;
            c[0]='\0';
            if ((c>buf)&&(c[-1]=='\r')) c[-1]='\0';
            if (strncasecmp(d,"HTTP/1.0 ",5)==0) // [sic] Allow version != 1.0
	    {
               if (atoi(d+9)!=200) goto httpend;
	       httpseen=YES;
	    }
            if (strncasecmp(d,"Content-Length: ",16)==0)
	    {
               totlen=atoi(d+16);
               [progress setMinValue:0];
               [progress setMaxValue:totlen];
               [progress setProgress:0];
               [progress setShowProgress:YES];
	    }
            if (*d=='\0')
	    {
	       if (!httpseen) goto httpend;
               if ((ofd=open(localpath,O_WRONLY|O_CREAT|O_TRUNC,0644))==-1)
                  goto httpend;
               rcvlen=end-(c+1);
               write(ofd,c+1,end-(c+1));
               [progress setProgress:rcvlen];
               
               while(![progress cancelled]&&((len=read(ifd,buf,sizeof(buf)))>0))
	       {
                  write(ofd,buf,len);
                  rcvlen+=len;
                  if (totlen>0) [progress setProgress:rcvlen];
	       }
               success=(len==0)&&((totlen==rcvlen)||(totlen==-1));
	       goto httpend;
	    }
            d=c+1;
	 }
         
         pos=buf;
         if (d>buf) while (d<end) *pos++=*d++;
      }

    httpend:
      if (ifd!=-1) close(ifd);
      if (ofd!=-1) close(ofd);
      if (progress!=nil)
      {
	 if ([progress cancelled]) unlink(localpath);
	 [progress endModalSession];
      }
      return success;
   }
   
   return NO;
}

+ (BOOL)grabURL:(const char *)url buffer:(char *)path
{
   int i;
   char *localname;

   if (!(url && *url)) return NO;

   localname = alloca(3*strlen(url)+1);	  // Should be enough...
   [EnhanceXImageAliases getPathName:localname forURL:url];

   if (imagepathExpanded==NO) imagepathExpanded=EnhancePaths(imagepath);
   
   for(i=0;imagepath[i];i++)
   {
      sprintf(path,"%s/%s",imagepath[i],localname);
      if (access(path,R_OK)==0) return YES;
   }

   /* Ignore last path (assume it is Image dir in bundle;
      don't want to store mugshots in there.) */
   for (i-=2;i>=0;i--) if (access(imagepath[i],R_OK|W_OK|X_OK)==0) break;
   if (i<0) return NO;
   sprintf(path,"%s/%s",imagepath[i],localname);
   
   if (![self grabURL:url to:path])
   {
      int fd=open(path,O_WRONLY|O_CREAT|O_TRUNC,0644);
      if (fd!=-1) close(fd);
      return NO;
   }

   return YES;
}

+ (BOOL)grabURL:(const char *)url string:(SimpleString *)s
{
   int fd;
   char path[MAXPATHLEN+1];

   if (tmpnam(path)==0) return NO;
   if (![self grabURL:url to:path]) return NO;
   if ((fd=open(path,O_RDONLY))==-1) return NO;
   unlink(path);
   [s appendFile:fd];
   close(fd);
   return YES;
}

- initURL:(const char *)url
{
   char path[MAXPATHLEN+1];
   struct stat buf;

   if (![[self class] grabURL:url buffer:path]) return [self free];
   if ((stat(path,&buf)==-1)||(buf.st_size==0)) return [self free];
   return [self initFromFile:path];
}

- initNameInPath:(const char *)filename
{
   int i;
   char path[MAXPATHLEN+1];
   struct stat buf;
   
   if (imagepathExpanded==NO) imagepathExpanded=EnhancePaths(imagepath);

   for(i=0;imagepath[i];i++)
   {
      sprintf(path,"%s/%s",imagepath[i],filename);
      if (access(path,R_OK)==0) break;
   }

   if (!imagepath[i]) return [self free];
   if ((stat(path,&buf)==-1)||(buf.st_size==0)) return [self free];
   return [self initFromFile:path];
}

@end // NXImage(XImageURL)


@implementation EnhanceXImageAliases(XImageURL)

+ (EnhanceXImageAliases *)aliases
{
   static id aliases;
   int i;

   if (aliases) return aliases;

   // XXX reuse by copy/paste.
   if (imagepathExpanded==NO) imagepathExpanded=EnhancePaths(imagepath);

   for (i = 0; imagepath[i]; i++) ;
   /* Ignore last path (assume it is Image dir in bundle;
      don't want to store mugshots in there.) */
   for (i -= 2; i >= 0; i--) if (access(imagepath[i],R_OK|W_OK|X_OK)==0) break;
   if (i<0) return nil;

   aliases = [EnhanceXImageAliases aliasesForDirectory:imagepath[i]];
   return aliases;
}

@end // EnhanceXImageAliases(XImageURL)

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.