diff -ru pine4.58.ori/imap/Makefile pine4.58/imap/Makefile --- pine4.58.ori/imap/Makefile Tue Jul 15 03:35:29 2003 +++ pine4.58/imap/Makefile Thu Oct 2 22:14:19 2003 @@ -215,6 +215,8 @@ # years. The Orthodox and Gregorian calendars diverge by 1 day for # gradually-increasing intervals, starting at 2800-2900, and becoming # permanent at 48,300. +# -DIPv6 +# Enables IPv6 support EXTRACFLAGS= diff -ru pine4.58.ori/imap/src/c-client/mail.c pine4.58/imap/src/c-client/mail.c --- pine4.58.ori/imap/src/c-client/mail.c Tue Sep 9 19:18:53 2003 +++ pine4.58/imap/src/c-client/mail.c Thu Oct 2 22:10:07 2003 @@ -626,9 +626,21 @@ /* initialize structure */ memset (mb,'\0',sizeof (NETMBX)); /* have host specification? */ +#ifdef IPv6 +/* + IPv6 : Should accept new inbox names like [2003:4033:200a::1] + So ":" is compromised under certain circunstances... + name -> 10.0.0.2 , [10.0.0.2] , [2003:4033:200a::1] +*/ + if (!((*name++ == '{') && (((v = strchr (name,']'))?v++:NULL) || (v = strpbrk (name,"/:}"))) && + (i = v - name) && + (i < NETMAXHOST) && (t = strchr (v,'}')) && ((j = t - v)host,name,i); /* set host name */ strncpy (mb->orighost,name,i); mb->host[i] = mb->orighost[i] = '\0'; Only in pine4.58/imap/src/c-client: mail.c~ diff -ru pine4.58.ori/imap/src/osdep/unix/tcp_unix.c pine4.58/imap/src/osdep/unix/tcp_unix.c --- pine4.58.ori/imap/src/osdep/unix/tcp_unix.c Thu Oct 31 21:04:41 2002 +++ pine4.58/imap/src/osdep/unix/tcp_unix.c Thu Oct 2 22:03:03 2003 @@ -16,10 +16,41 @@ * Copyright 2002 University of Washington. * The full text of our legal notices is contained in the file called * CPYRIGHT, included with this Distribution. - */ + * + * Notes to IPv6 porting: + * In order to use abstract addresses, + * we must to use the new IPv6 API: getnameinfo(), getaddrinfo(), + * instead of [getipnodebyname(),getipnobyaddr(),inet_pton(),inet_ntop()] + * working only with concrete instances of IP protocol (IPv4 | IPv6 ). + * +*/ + #undef write /* don't use redefined write() */ - + +#ifdef IPv6 +#ifndef SA_LEN +#define SA_LEN(sa) sa_len(sa) + +static size_t sa_len(struct sockaddr_storage *sa) +{ + switch(sa->ss_family) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + default: + return sizeof(struct sockaddr_storage); + } +} +#endif /* SA_LEN */ +#endif + + +/* TODO: IPv6 def + - Maybe cpstr leaves memory with no control. +*/ + static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_open = 0; /* TCP timeouts, in seconds */ static long ttmo_read = 0; @@ -36,11 +67,20 @@ extern long maxposint; /* get this from write.c */ /* Local function prototypes */ - +#ifdef IPv6 +int tcp_socket_open (struct sockaddr_storage *sa,char *tmp,int *ctr,char *hst, + unsigned long port); +#else int tcp_socket_open (struct sockaddr_in *sin,char *tmp,int *ctr,char *hst, unsigned long port); +#endif + long tcp_abort (TCPSTREAM *stream); +#ifdef IPv6 +char *tcp_name (struct sockaddr_storage *sa,long flag); +#else char *tcp_name (struct sockaddr_in *sin,long flag); +#endif long tcp_name_valid (char *s); /* TCP/IP manipulate parameters @@ -138,8 +178,14 @@ int silent = (port & NET_SILENT) ? T : NIL; int *ctrp = (port & NET_NOOPENTIMEOUT) ? NIL : &ctr; char *s; +#ifdef IPv6 + struct sockaddr_storage sa; + struct addrinfo hints,*res,*resave; + int n; +#else struct sockaddr_in sin; struct hostent *he; +#endif char hostname[MAILTMPLEN]; char tmp[MAILTMPLEN]; struct servent *sv = NIL; @@ -147,14 +193,81 @@ void *data; port &= 0xffff; /* erase flags */ /* lookup service */ + +#ifdef IPv6 + memset(&hints,0,sizeof(hints)); + hints.ai_family = PF_UNSPEC; /* Protocol independent */ + /* look like domain literal? */ + if (host[0] == '[' && host[(strlen (host))-1] == ']') { + hints.ai_flags = AI_NUMERICHOST ; /* Don't want DNS resolution */ + strcpy (hostname,host+1); /* yes, copy number part */ + hostname[(strlen (hostname))-1] = '\0'; + if (getaddrinfo (hostname,service,&hints,&res)) + sprintf (tmp,"Bad format domain-literal: %.80s",host); + else + { + memset(&sa,0,sizeof(sa)); + memcpy (&sa,res->ai_addr,res->ai_addrlen); + (*bn) (BLOCK_TCPOPEN,NIL); + /* get an open socket for this system */ + sock = tcp_socket_open (&sa,tmp,ctrp,hostname,port); + (*bn) (BLOCK_NONE,NIL); + freeaddrinfo(res); + } + } + + else { /* lookup host name */ + hints.ai_flags = AI_CANONNAME ; /* Want canonname */ + if (tcpdebug) { + sprintf (tmp,"DNS resolution %.80s",host); + mm_log (tmp,TCPDEBUG); + } + (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ + data = (*bn) (BLOCK_SENSITIVE,NIL); + if ((n=getaddrinfo (lcase (strcpy (hostname,host)),service,&hints,&res))) + sprintf (tmp,"No such host as %.80s",host); + (*bn) (BLOCK_NONSENSITIVE,data); + (*bn) (BLOCK_NONE,NIL); + if (!n) { /* DNS resolution won? */ + resave=res; + if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); + /* copy host name */ + strcpy (hostname,res->ai_canonname); +#ifdef HOST_NOT_FOUND /* muliple addresses only on DNS systems */ + for (sock = -1,i = 0; (sock < 0) && res; i++,res=res->ai_next) { + if (i && !silent) mm_log (tmp,WARN); + memset(&sa,0,sizeof(sa)); + memcpy (&sa,res->ai_addr,res->ai_addrlen); + (*bn) (BLOCK_TCPOPEN,NIL); + /* get an open socket for this system */ + sock = tcp_socket_open (&sa,tmp,ctrp,hostname,port); + (*bn) (BLOCK_NONE,NIL); + } +#else /* the one true address then */ + memset(&sa,0,sizeof(sa)); + memcpy (&sa,res->ai_addr,res->ai_addrlen); + (*bn) (BLOCK_TCPOPEN,NIL); + /* get an open socket for this system */ + sock = tcp_socket_open (&sa,tmp,ctrp,hostname,port); + (*bn) (BLOCK_NONE,NIL); +#endif + freeaddrinfo(resave); + } + } + + +#else if (service && (sv = getservbyname (service,"tcp"))) port = ntohs (sin.sin_port = sv->s_port); /* copy port number in network format */ else sin.sin_port = htons (port); + + /* copy port number in network format */ /* The domain literal form is used (rather than simply the dotted decimal as with other Unix programs) because it has to be a valid "host name" in mailsystem terminology. */ /* look like domain literal? */ + if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (hostname,host+1); /* yes, copy number part */ hostname[(strlen (hostname))-1] = '\0'; @@ -184,6 +297,7 @@ if (he) { /* DNS resolution won? */ if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); /* copy address type */ + sin.sin_family = he->h_addrtype; /* copy host name */ strcpy (hostname,he->h_name); @@ -203,6 +317,7 @@ #endif } } +#endif if (sock >= 0) { /* won */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); @@ -227,22 +342,39 @@ * port number for error message * Returns: socket if success, else -1 with error string in scratch buffer */ - +#ifdef IPv6 +int tcp_socket_open (struct sockaddr_storage *sa,char *tmp,int *ctr,char *hst, + unsigned long port) +#else int tcp_socket_open (struct sockaddr_in *sin,char *tmp,int *ctr,char *hst, unsigned long port) +#endif { int i,ti,sock,flgs; time_t now; struct protoent *pt = getprotobyname ("tcp"); fd_set fds,efds; struct timeval tmo; +#ifdef IPv6 + char straddr[INET6_ADDRSTRLEN]; +#endif blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* fetid Solaris */ void *data = (*bn) (BLOCK_SENSITIVE,NIL); +#ifdef IPv6 + memset(straddr,0,INET6_ADDRSTRLEN); + getnameinfo((const struct sockaddr *)sa,SA_LEN(sa),straddr,INET6_ADDRSTRLEN,NULL,0,NI_NUMERICHOST); + sprintf (tmp,"Trying IP address [%s]",straddr); +#else sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr)); +#endif mm_log (tmp,NIL); /* make a socket */ +#ifdef IPv6 + if ((sock = socket (sa->ss_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) { +#else if ((sock = socket (sin->sin_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) { +#endif sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno)); (*bn) (BLOCK_NONSENSITIVE,data); return -1; @@ -251,8 +383,13 @@ /* set non-blocking if want open timeout */ if (ctr) fcntl (sock,F_SETFL,flgs | FNDELAY); /* open connection */ +#ifdef IPv6 + while ((i = connect (sock,(struct sockaddr *) sa, + SA_LEN(sa))) < 0 && (errno == EINTR)); +#else while ((i = connect (sock,(struct sockaddr *) sin, sizeof (struct sockaddr_in))) < 0 && (errno == EINTR)); +#endif (*bn) (BLOCK_NONSENSITIVE,data); if (i < 0) switch (errno) { /* failed? */ case EAGAIN: /* DG brain damage */ @@ -312,6 +449,9 @@ { TCPSTREAM *stream = NIL; struct hostent *he; +#ifdef IPv6 + struct addrinfo hints,*res; +#endif char host[MAILTMPLEN],tmp[MAILTMPLEN],*path,*argv[MAXARGV+1]; int i,ti,pipei[2],pipeo[2]; time_t now; @@ -335,11 +475,23 @@ if (mb->host[0] == '[' && mb->host[i = (strlen (mb->host))-1] == ']') { strcpy (host,mb->host+1); /* yes, copy without brackets */ host[i-1] = '\0'; +#ifdef IPv6 + memset(&hints,0,sizeof(hints)); + hints.ai_family=PF_UNSPEC; + hints.ai_flags=AI_NUMERICHOST; + if (getaddrinfo(host,NULL,&hints,&res )) { + sprintf (tmp,"Bad format domain-literal: %.80s",host); + mm_log (tmp,ERROR); + return NIL; + } + freeaddrinfo(res); +#else if (inet_addr (host) == -1) { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } +#endif } else { /* note that Unix requires lowercase! */ (*bn) (BLOCK_DNSLOOKUP,NIL); @@ -348,8 +500,19 @@ sprintf (tmp,"DNS canonicalization for rsh/ssh %.80s",mb->host); mm_log (tmp,TCPDEBUG); } +#ifdef IPv6 + memset(&hints,0,sizeof(hints)); + hints.ai_flags=AI_CANONNAME; + hints.ai_family=PF_UNSPEC; + if (!getaddrinfo (lcase (strcpy (host,mb->host)),service,&hints,&res)) + { + strcpy (host,res->ai_canonname); + freeaddrinfo(res); + } +#else if (he = gethostbyname (lcase (strcpy (host,mb->host)))) strcpy (host,he->h_name); +#endif if (tcpdebug) mm_log ("DNS canonicalization for rsh/ssh done",TCPDEBUG); (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); @@ -700,12 +863,21 @@ char *tcp_remotehost (TCPSTREAM *stream) { if (!stream->remotehost) { +#ifdef IPv6 + struct sockaddr_storage sa; + int salen = sizeof (struct sockaddr_storage); + stream->remotehost = /* get socket's peer name */ + (getpeername (stream->tcpsi,(struct sockaddr *) &sa,(void *) &salen) || + ((sa.ss_family != AF_INET) && (sa.ss_family != AF_INET6 ))) ? + cpystr (stream->host) : tcp_name (&sa,NIL); +#else struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); stream->remotehost = /* get socket's peer name */ (getpeername (stream->tcpsi,(struct sockaddr *) &sin,(void *) &sinlen) || (sin.sin_family != AF_INET)) ? cpystr (stream->host) : tcp_name (&sin,NIL); +#endif } return stream->remotehost; } @@ -730,6 +902,15 @@ char *tcp_localhost (TCPSTREAM *stream) { if (!stream->localhost) { +#ifdef IPv6 + struct sockaddr_storage sa; + int salen = sizeof (struct sockaddr_storage); + stream->localhost = /* get socket's name */ + ((stream->port & 0xffff000) || + getsockname (stream->tcpsi,(struct sockaddr *) &sa,(void *) &salen) || + ((sa.ss_family != AF_INET) && (sa.ss_family != AF_INET6 ))) ? + cpystr (mylocalhost ()) : tcp_name (&sa,NIL); +#else struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); stream->localhost = /* get socket's name */ @@ -737,6 +918,7 @@ getsockname (stream->tcpsi,(struct sockaddr *) &sin,(void *) &sinlen) || (sin.sin_family != AF_INET)) ? cpystr (mylocalhost ()) : tcp_name (&sin,NIL); +#endif } return stream->localhost; /* return local host name */ } @@ -746,16 +928,26 @@ */ static char *myClientAddr = NIL; - char *tcp_clientaddr () { if (!myClientAddr) { +#ifdef IPv6 + char straddr[INET6_ADDRSTRLEN]; + struct sockaddr_storage sa; + int salen = sizeof (struct sockaddr_storage); + /* get stdin's peer name */ + myClientAddr = /* get stdin's peer name */ + cpystr (getpeername (0,(struct sockaddr *) &sa,(void *) &salen) ? + "UNKNOWN" : ( getnameinfo((const struct sockaddr *)&sa,salen,straddr,INET6_ADDRSTRLEN,NULL,0,NI_NUMERICHOST) ? "NEITHER IPv4 NOR IPv6":straddr)); + +#else struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myClientAddr = /* get stdin's peer name */ cpystr (getpeername (0,(struct sockaddr *) &sin,(void *) &sinlen) ? "UNKNOWN" : ((sin.sin_family == AF_INET) ? inet_ntoa (sin.sin_addr) : "NON-IPv4")); +#endif } return myClientAddr; } @@ -770,12 +962,21 @@ char *tcp_clienthost () { if (!myClientHost) { +#ifdef IPv6 + struct sockaddr_storage sa; + int salen = sizeof (struct sockaddr_storage); + myClientHost = /* get stdin's peer name */ + getpeername (0,(struct sockaddr *) &sa,(void *) &salen) ? + cpystr ("UNKNOWN") : (((sa.ss_family == AF_INET) || (sa.ss_family == AF_INET6))? + tcp_name (&sa,T) : cpystr ("NEITHER IPv4 NOR IPv6")); +#else struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myClientHost = /* get stdin's peer name */ getpeername (0,(struct sockaddr *) &sin,(void *) &sinlen) ? cpystr ("UNKNOWN") : ((sin.sin_family == AF_INET) ? tcp_name (&sin,T) : cpystr ("NON-IPv4")); +#endif } return myClientHost; } @@ -785,16 +986,24 @@ */ static char *myServerAddr = NIL; - char *tcp_serveraddr () { if (!myServerAddr) { +#ifdef IPv6 + char straddr[INET6_ADDRSTRLEN]; + struct sockaddr_storage sa; + int salen = sizeof (struct sockaddr_storage); + /* get stdin's peer name */ + cpystr (getsockname (0,(struct sockaddr *) &sa,(void *) &salen) ? + "UNKNOWN" : ( getnameinfo((const struct sockaddr *)&sa,salen,straddr,INET6_ADDRSTRLEN,NULL,0,NI_NUMERICHOST) ? "NEITHER IPv4 NOR IPv6":straddr)); +#else struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myServerAddr = /* get stdin's peer name */ cpystr (getsockname (0,(struct sockaddr *) &sin,(void *) &sinlen) ? "UNKNOWN" : ((sin.sin_family == AF_INET) ? inet_ntoa (sin.sin_addr) : "NON-IPv4")); +#endif } return myServerAddr; } @@ -810,6 +1019,18 @@ char *tcp_serverhost () { if (!myServerHost) { +#ifdef IPv6 + struct sockaddr_storage sa; + int salen = sizeof (struct sockaddr_storage); + /* get stdin's name */ + if (getsockname (0,(struct sockaddr *) &sa,(void *) &salen) || + ((sa.ss_family != AF_INET) && (sa.ss_family != AF_INET6))) + myServerHost = cpystr (mylocalhost ()); + else { + myServerHost = tcp_name (&sa,NIL); + myServerPort = ntohs (((struct sockaddr_in *)&sa)->sin_port); + } +#else struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); /* get stdin's name */ @@ -819,6 +1040,7 @@ myServerHost = tcp_name (&sin,NIL); myServerPort = ntohs (sin.sin_port); } +#endif } return myServerHost; } @@ -842,7 +1064,12 @@ char *tcp_canonical (char *name) { char *ret,host[MAILTMPLEN]; +#ifdef IPv6 + struct addrinfo hints,*res; + int n; +#else struct hostent *he; +#endif blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data; /* look like domain literal? */ @@ -854,8 +1081,15 @@ mm_log (host,TCPDEBUG); } /* note that Unix requires lowercase! */ +#ifdef IPv6 + hints.ai_flags=AI_CANONNAME; + ret = cpystr ( (n=getaddrinfo(lcase (strcpy (host,name)),NULL,&hints ,&res))? + name : (char *) res->ai_canonname ); + if (!n) freeaddrinfo(res); +#else ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? (char *) he->h_name : name; +#endif (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG); @@ -868,21 +1102,45 @@ * verbose flag * Returns: cpystr name */ - +#ifdef IPv6 +char *tcp_name (struct sockaddr_storage *sa,long flag) +#else char *tcp_name (struct sockaddr_in *sin,long flag) +#endif { char *s,tmp[MAILTMPLEN]; +#ifdef IPv6 + char straddr[INET6_ADDRSTRLEN]; /* Storing literral address */ + char hostname[INET6_ADDRSTRLEN]; /* Storing dns name */ + int n; + memset(straddr,0,INET6_ADDRSTRLEN); + memset(hostname,0,INET6_ADDRSTRLEN); +#endif if (allowreversedns) { struct hostent *he; + int error; blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL); void *data; if (tcpdebug) { +#ifdef IPv6 + getnameinfo((const struct sockaddr *)sa,SA_LEN(sa),straddr,INET6_ADDRSTRLEN,NULL,0,NI_NUMERICHOST); + sprintf (tmp,"Reverse DNS resolution [%s]",straddr); +#else sprintf (tmp,"Reverse DNS resolution [%s]",inet_ntoa (sin->sin_addr)); +#endif mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL); /* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); - /* translate address to name */ + /* translate address to name */ +#ifdef IPv6 + n= getnameinfo((const struct sockaddr *)sa,SA_LEN(sa),hostname,INET6_ADDRSTRLEN,NULL,0,0); + if ( n || + !tcp_name_valid ((char *) hostname)) + sprintf (s = tmp,"[%s]",straddr); + else if (flag) sprintf (s = tmp," [%s] %s",hostname,straddr); + else s = cpystr((char *) hostname); +#else if (!(he = gethostbyaddr ((char *) &sin->sin_addr, sizeof (struct in_addr),sin->sin_family)) || !tcp_name_valid ((char *) he->h_name)) @@ -890,11 +1148,20 @@ else if (flag) sprintf (s = tmp,"%s [%s]",he->h_name, inet_ntoa (sin->sin_addr)); else s = (char *) he->h_name; +#endif (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG); } +#ifdef IPv6 + else + { + getnameinfo((const struct sockaddr *)sa,SA_LEN(sa),straddr,INET6_ADDRSTRLEN,NULL,0,NI_NUMERICHOST); + sprintf (s = tmp,"[%s]",straddr); + } +#else else sprintf (s = tmp,"[%s]",inet_ntoa (sin->sin_addr)); +#endif return cpystr (s); }