1 /****************************************************************/
2 /* Web unit                                                     */
3 /* (c) Christophe CALMEJANE (Ze KiLleR) - 1999-06               */
4 /****************************************************************/
5 
6 /*
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public
9     License as published by the Free Software Foundation; either
10     version 2.1 of the License, or (at your option) any later version.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Lesser General Public License for more details.
16 
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21 
22 
23 /* TO DO :
24  * Purger les cookies expirés
25 */
26 
27 #include "skyutils.h"
28 
29 #ifndef SU_TRACE_INTERNAL
30 #undef malloc
31 #undef calloc
32 #undef realloc
33 #undef strdup
34 #undef free
35 #endif /* !SU_TRACE_INTERNAL */
36 
37 #define SW_DEFAULT_USER_AGENT "Mozilla/6.0 (compatible; MSIE 5.01; Windows NT)"
38 #define SW_DEFAULT_HEADER "Connection: Keep-Alive" "\x0D" "\x0A" "Accept-Language: fr-FR, en" "\x0D" "\x0A" "Accept-Charset: iso-8859-1,*,utf-8" "\x0D" "\x0A" "Accept: text/html, text/plain, text/*, image/gif, image/jpg, image/png, */*" "\x0D" "\x0A"
39 #define DEFAULT_PORT 80
40 #define DEFAULT_SSL_PORT 443
41 #define SOCKET_TIME_OUT 60
42 
43 #ifdef __unix__
44 extern int SU_DebugLevel;
45 #endif /* __unix__ */
46 
47 char *SW_GetInput_String;
48 char *SW_GetImage_String;
49 char *SW_Proxy_String = NULL;
50 char *SW_Proxy_User = NULL;
51 char *SW_Proxy_Password = NULL;
52 char *SW_UserHeader = NULL;
53 char *SW_UserAgent = NULL;
54 int   SW_Proxy_Port = 0;
55 int   SW_SocketTimeout = SOCKET_TIME_OUT;
56 SU_PList SW_Cookies = NULL; /* SU_PCookie */
57 
58 int SU_Dump_PageNum = 0;
59 
DumpPage(const char fname[],const char * buf,const int size)60 void DumpPage(const char fname[],const char *buf,const int size)
61 {
62   FILE *fp;
63   char FN[50];
64 
65   if(fname == NULL)
66   {
67     SU_snprintf(FN,sizeof(FN),"Dump%d.html",SU_Dump_PageNum++);
68     printf("SkyUtils_DumpPage : Dumping to %s\n",FN);
69     fp = fopen(FN,"wt");
70   }
71   else
72     fp = fopen(fname,"wb");
73   if(fp == NULL)
74     return;
75 #ifdef __unix__
76   /* this debug view is useful if u need debug dynamic input name and need to know
77    * what page is taken from server */
78   if(SU_DebugLevel >= 10)
79     fwrite(buf,size,1,stdout);
80 #endif /* __unix__ */
81   fwrite(buf,size,1,fp);
82   fclose(fp);
83 }
84 
85 /* ** SSL CODE ** */
86 #ifdef SU_USE_SSL
87 #include <openssl/crypto.h>
88 #include <openssl/x509.h>
89 #include <openssl/pem.h>
90 #include <openssl/ssl.h>
91 #include <openssl/err.h>
92 #include <openssl/rand.h>
93 #define SSL_RETRY_LIMIT 20
94 static SSL_CTX *SU_SSL_ctx = NULL;
95 
SU_SSL_Init()96 void SU_SSL_Init()
97 {
98   unsigned char Seed[1024];
99   SU_u32 i,j,pid;
100   SSL_load_error_strings();
101   SSL_library_init();
102 
103 #ifdef _WIN32
104   pid = (SU_u32) GetTickCount() ^ (SU_u32) time(NULL);
105 #else
106   pid = (((SU_u32) getpid()) << 16) ^ (SU_u32) time(NULL);
107 #endif
108 
109   for(i=0;i<sizeof(Seed);i++)
110   {
111     for(j=0,Seed[i]=0;j<8;j++)
112     {
113       Seed[i] |= (pid & 1) << j;
114       pid = ((((pid >> 7) ^ (pid >> 6) ^ (pid >> 2) ^ (pid >> 0)) & 1) << 31) | (pid >> 1);
115     }
116   }
117 
118   RAND_seed(Seed,sizeof(Seed));
119 }
120 
SU_SSL_InitializeCTX(char * pcError)121 SSL_CTX *SU_SSL_InitializeCTX(char *pcError)
122 {
123   char errormsg[1024];
124   SSL_CTX *sslctx;
125 
126 #ifndef OPENSSL_NO_SSL3
127   sslctx = SSL_CTX_new(SSLv3_client_method());
128 #else
129   sslctx = SSL_CTX_new(SSLv23_client_method());
130 #endif
131   if(sslctx == NULL)
132   {
133     ERR_error_string(ERR_get_error(), errormsg);
134     SU_snprintf(pcError, 1024, "SSL_CTX_new(): %s", errormsg);
135     return NULL;
136   }
137 
138   SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, NULL);
139 
140   return sslctx;
141 }
142 
SU_SSL_Create(SU_SOCKET Sock,char * pcError)143 SSL *SU_SSL_Create(SU_SOCKET Sock,char *pcError)
144 {
145   char errormsg[1024];
146   int iError;
147   SSL *ssl;
148 
149   if(!SU_SSL_ctx)
150   {
151     SU_SSL_Init();
152     SU_SSL_ctx = SU_SSL_InitializeCTX(pcError);
153     if(SU_SSL_ctx == NULL)
154       return NULL;
155     SSL_CTX_set_options(SU_SSL_ctx, SSL_OP_ALL);
156     SSL_CTX_set_default_verify_paths(SU_SSL_ctx);
157   }
158 
159   ssl = SSL_new(SU_SSL_ctx);
160   if(ssl == NULL)
161   {
162     ERR_error_string(ERR_get_error(),errormsg);
163     SU_snprintf(pcError, 1024, "SSL_new(): %s", errormsg);
164     return NULL;
165   }
166 
167   iError = SSL_set_fd(ssl,Sock);
168   if(iError == 0)
169   {
170     ERR_error_string(ERR_get_error(), errormsg);
171     SU_snprintf(pcError, 1024, "SSL_connect(): %s", errormsg);
172     SSL_free(ssl);
173     return NULL;
174   }
175   return ssl;
176 }
177 
SU_SSL_Connect(SU_SOCKET Sock,char * pcError)178 SSL *SU_SSL_Connect(SU_SOCKET Sock,char *pcError)
179 {
180   int iError;
181   char errormsg[1024];
182 
183   SSL *ssl = SU_SSL_Create(Sock,pcError);
184   if(ssl == NULL)
185     return NULL;
186 
187   iError = SSL_connect(ssl);
188   if(iError <= 0)
189   {
190     ERR_error_string(ERR_get_error(), errormsg);
191     SU_snprintf(pcError, 1024, "SSL_connect(): %s", errormsg);
192     SSL_free(ssl);
193     return NULL;
194   }
195 
196   return ssl;
197 }
198 
SU_SSL_Write(SSL * ssl,char * pcData,int iLength,char * pcError)199 int SU_SSL_Write(SSL *ssl, char *pcData, int iLength, char *pcError)
200 {
201   char errormsg[1024];
202   int iNSent;
203   int iOffset;
204   int iToSend;
205   int iWRetries;
206 
207   iToSend = iLength;
208   iOffset = iWRetries = 0;
209   do
210   {
211     iNSent = SSL_write(ssl, &pcData[iOffset], iToSend);
212 
213     switch (SSL_get_error(ssl, iNSent))
214     {
215     case SSL_ERROR_NONE:
216       iToSend -= iNSent;
217       iOffset += iNSent;
218       break;
219 
220     case SSL_ERROR_SSL:
221       if(pcError)
222         SU_snprintf(pcError, 1024, "SSL_write(): SSL_ERROR_SSL");
223       return -1;
224       break;
225 
226     case SSL_ERROR_WANT_READ:
227       if(pcError)
228         SU_snprintf(pcError, 1024, "SSL_write(): SSL_ERROR_WANT_READ");
229       return -1;
230       break;
231 
232     case SSL_ERROR_WANT_WRITE:
233       if (++iWRetries >= SSL_RETRY_LIMIT)
234       {
235         if(pcError)
236           SU_snprintf(pcError, 1024, "SSL_write(): SSL_ERROR_WANT_WRITE: Retry limit reached!");
237         return -1;
238       }
239       break;
240 
241     case SSL_ERROR_WANT_X509_LOOKUP:
242       if(pcError)
243         SU_snprintf(pcError, 1024, "SSL_write(): SSL_ERROR_WANT_X509_LOOKUP");
244       return -1;
245       break;
246 
247     case SSL_ERROR_SYSCALL:
248       if (ERR_peek_error())
249       {
250         ERR_error_string(ERR_get_error(), errormsg);
251       }
252       if (iNSent == -1)
253       {
254         if(pcError)
255           SU_snprintf(pcError, 1024, "SSL_write(): SSL_ERROR_SYSCALL: Underlying I/O error: %s",strerror(errno));
256       }
257       else
258       {
259         if(pcError)
260           SU_snprintf(pcError, 1024, "SSL_write(): SSL_ERROR_SYSCALL: Unexpected EOF.");
261       }
262       return -1;
263       break;
264 
265     case SSL_ERROR_ZERO_RETURN:
266       if(pcError)
267         SU_snprintf(pcError, 1024, "SSL_write(): SSL_ERROR_ZERO_RETURN: The SSL connection has been closed.");
268       return -1;
269       break;
270 
271     default:
272       if(pcError)
273         SU_snprintf(pcError, 1024, "SSL_write(): Undefined error.");
274       return -1;
275       break;
276     }
277   } while (iToSend > 0);
278 
279   return iOffset;
280 }
281 
SU_SSL_Read(SSL * ssl,char * pcData,int iLength,char * pcError)282 int SU_SSL_Read(SSL *ssl, char *pcData, int iLength, char *pcError)
283 {
284   char errormsg[1024];
285   int iDone;
286   int iNRead;
287   int iRRetries;
288 
289   iDone = iRRetries = 0;
290   iNRead = SSL_read(ssl, pcData, iLength);
291   while (iDone == 0)
292   {
293     iDone = 1;
294     switch (SSL_get_error(ssl, iNRead))
295     {
296     case SSL_ERROR_NONE:
297       return iNRead;
298       break;
299 
300     case SSL_ERROR_SSL:
301       ERR_error_string(ERR_get_error(), errormsg);
302       if(pcError)
303         SU_snprintf(pcError, 1024, "SSL_read(): SSL_ERROR_SSL: %s",errormsg);
304       return -1;
305       break;
306 
307     case SSL_ERROR_WANT_READ:
308       if (++iRRetries < SSL_RETRY_LIMIT)
309       {
310         if(pcError)
311           SU_snprintf(pcError, 1024, "SSL_read(): SSL_ERROR_WANT_READ");
312         iNRead = SSL_read(ssl, pcData, iLength);
313         iDone = 0;
314       }
315       else
316       {
317         if(pcError)
318           SU_snprintf(pcError, 1024, "SSL_read(): SSL_ERROR_WANT_READ: Retry limit reached!");
319         return -1;
320       }
321       break;
322 
323     case SSL_ERROR_WANT_WRITE:
324       if(pcError)
325         SU_snprintf(pcError, 1024, "SSL_read(): SSL_ERROR_WANT_WRITE");
326       return -1;
327       break;
328 
329     case SSL_ERROR_WANT_X509_LOOKUP:
330       if(pcError)
331         SU_snprintf(pcError, 1024, "SSL_read(): SSL_ERROR_WANT_X509_LOOKUP");
332       return -1;
333       break;
334 
335     case SSL_ERROR_SYSCALL:
336       if (ERR_peek_error())
337       {
338         ERR_error_string(ERR_get_error(), errormsg);
339       }
340       if (iNRead == -1)
341       {
342         if(pcError)
343           SU_snprintf(pcError, 1024, "SSL_read(): SSL_ERROR_SYSCALL: Underlying I/O error: %s", strerror(errno));
344         return -1;
345       }
346       else
347       {
348         if(pcError)
349           SU_snprintf(pcError, 1024, "SSL_read(): SSL_ERROR_SYSCALL: Unexpected EOF. (%d)",iNRead);
350         return -1;
351       }
352       break;
353 
354     case SSL_ERROR_ZERO_RETURN:
355       if(pcError)
356         SU_snprintf(pcError, 1024, "SSL_read(): SSL_ERROR_ZERO_RETURN: The SSL connection has been closed.");
357       return 0;
358       break;
359 
360     default:
361       if(pcError)
362         SU_snprintf(pcError, 1024, "SSL_read(): Undefined error.");
363       return -1;
364       break;
365     }
366   }
367   return -1;
368 }
369 
SU_SSL_SessionCleanup(SSL * ssl)370 void SU_SSL_SessionCleanup(SSL *ssl)
371 {
372   if(ssl != NULL)
373   {
374     SSL_shutdown(ssl);
375     SSL_free(ssl);
376   }
377 }
378 /* ** END OF SSL CODE ** */
379 #else /* !SU_USE_SSL */
380 typedef void SSL;
381 #endif /* SU_USE_SSL */
382 
SU_SetSocketTimeout(const int Timeout)383 void SU_SetSocketTimeout(const int Timeout)
384 {
385   if(Timeout == 0)
386     SW_SocketTimeout = SOCKET_TIME_OUT;
387   else
388     SW_SocketTimeout = Timeout;
389 }
390 
SU_SetProxy(const char Proxy[],const int Port,const char User[],const char Password[])391 void SU_SetProxy(const char Proxy[],const int Port,const char User[], const char Password[])
392 {
393   if(SW_Proxy_String != NULL)
394     free(SW_Proxy_String);
395   if((Proxy != NULL)&&(strlen(Proxy)>0))
396     SW_Proxy_String = SU_strdup(Proxy);
397   else
398     SW_Proxy_String = NULL;
399   SW_Proxy_Port = Port;
400   if(SW_Proxy_User != NULL)
401     free(SW_Proxy_User);
402   if((User != NULL)&&(strlen(User)>0))
403     SW_Proxy_User = SU_strdup(User);
404   else
405     SW_Proxy_User = NULL;
406   if(SW_Proxy_Password != NULL)
407     free(SW_Proxy_Password);
408   if((Password != NULL)&&(strlen(Password)>0))
409     SW_Proxy_Password = SU_strdup(Password);
410   else
411     SW_Proxy_Password = NULL;
412 }
413 
ExtractPath(char * URL,bool proxy)414 char *ExtractPath(char *URL,bool proxy)
415 {
416   char *path;
417   char l[]=".?/",c;
418   int i;
419 
420   if(proxy)
421   {
422     URL = strstr(URL,"://") + 3;
423     URL = strchr(URL,'/');
424     if(URL == NULL)
425     {
426       return SU_strdup("/");
427     }
428   }
429   path = SU_strdup(URL);
430   if(strcmp(path,"/") == 0)
431     return path;
432   if(path[strlen(path)-1] == '/')
433   {
434     path[strlen(path)-1] = 0;
435     return path;
436   }
437   if(SU_strrchrl(path,l,&c) == NULL)
438     return path;
439   if(c == '/')
440     return path;
441 
442   i = strlen(path)-1;
443   while(path[i] != '/')
444   {
445     if(i == 0)
446     {
447       path[0] = '/';
448       break;
449     }
450     i--;
451   }
452   if(i == 0)
453     path[1] = 0;
454   else
455     path[i] = 0;
456   return path;
457 }
458 
AfficheCookie(SU_PCookie Cok)459 void AfficheCookie(SU_PCookie Cok)
460 {
461   printf("Cookie : %s=%s--\n",Cok->Name,Cok->Value);
462   if(Cok->Domain != NULL)
463     printf("  Domain = %s--\n",Cok->Domain);
464   if(Cok->Path != NULL)
465     printf("  Path = %s--\n",Cok->Path);
466   if(Cok->Expire != NULL)
467     printf("  Expires = %s--\n",Cok->Expire);
468   if(Cok->Secured)
469     printf("  Secured\n");
470 }
471 
SU_FreeCookie(SU_PCookie Cok)472 void SU_FreeCookie(SU_PCookie Cok)
473 {
474   free(Cok->Name);
475   free(Cok->Value);
476   if(Cok->Domain != NULL)
477     free(Cok->Domain);
478   if(Cok->Path != NULL)
479     free(Cok->Path);
480   if(Cok->Expire != NULL)
481     free(Cok->Expire);
482   free(Cok);
483 }
484 
GetPortFromHost(char * Host,bool ssl_mode)485 int GetPortFromHost(char *Host,bool ssl_mode)
486 {
487   char *p;
488 
489   p = strchr(Host,':');
490   if(p == NULL)
491   {
492     return ssl_mode?DEFAULT_SSL_PORT:DEFAULT_PORT;
493   }
494   p[0] = 0;
495   p++;
496   return atoi(p);
497 }
498 
GetHostFromURL(const char * URL,char Host[],int Length,bool proxy,char URL_OUT[],int * PortConnect,const char OtherHost[],bool * ssl_mode)499 int GetHostFromURL(const char *URL,char Host[],int Length,bool proxy,char URL_OUT[],int *PortConnect,const char OtherHost[],bool *ssl_mode)
500 {
501   char *ptr,*ptr2;
502   int len;
503   char buf[URL_BUF_SIZE];
504   char ReplaceHost[URL_BUF_SIZE];
505 
506   SU_strcpy(ReplaceHost,OtherHost,sizeof(ReplaceHost));
507   SU_strcpy(URL_OUT,URL,URL_BUF_SIZE);
508   *ssl_mode = false;
509   if(SU_nocasestrstr((char *)URL,"https") == URL)
510   {
511 #ifndef SU_USE_SSL
512     printf("SkyUtils_GetHostFromURL Error : HTTPS requested, but skyutils was not compiled with SSL support. Exiting !\n");
513     return -10;
514     *ssl_mode = false;
515 #else /* SU_USE_SSL */
516     *ssl_mode = true;
517 #endif /* ! SU_USE_SSL */
518     ptr = (char *)URL+8;
519     ptr2 = strchr(ptr,'/');
520   }
521   else if(SU_nocasestrstr((char *)URL,"http") == URL)
522   {
523     ptr = (char *)URL+7;
524     ptr2 = strchr(ptr,'/');
525   }
526   else if(SU_nocasestrstr((char *)URL,"ftp") == URL)
527   {
528     ptr = (char *)URL+6;
529     ptr2 = strchr(ptr,'@');
530     if(ptr2 != NULL)
531     {
532       ptr = ptr2+1;
533       ptr2 = strchr(ptr,'/');
534     }
535   }
536   else
537   {
538     if(ReplaceHost[0] == 0)
539       SU_strcpy(Host,URL,Length);
540     else
541       SU_strcpy(Host,ReplaceHost,Length);
542     if(!proxy)
543     {
544       URL_OUT[0] = '/';
545       URL_OUT[1] = 0;
546       *PortConnect = GetPortFromHost(Host,*ssl_mode);
547     }
548     return 0;
549   }
550   if(ptr2 == NULL)
551   {
552     if(ReplaceHost[0] == 0)
553       SU_strcpy(Host,ptr,Length);
554     else
555       SU_strcpy(Host,ReplaceHost,Length);
556     if(!proxy)
557     {
558       URL_OUT[0] = '/';
559       URL_OUT[1] = 0;
560       *PortConnect = GetPortFromHost(Host,*ssl_mode);
561     }
562     return 0;
563   }
564   len = ptr2 - ptr + 1; /* +1 for the \0 */
565   if(len > Length)
566     len = Length;
567   if(ReplaceHost[0] == 0)
568   {
569     SU_strcpy(Host,ptr,len);
570   }
571   else
572   {
573     SU_strcpy(Host,ReplaceHost,Length);
574   }
575   if(!proxy)
576   { /* If not using a proxy, we must remove host from URL_OUT */
577     SU_strcpy(buf,ptr2,sizeof(buf));
578     SU_strcpy(URL_OUT,buf,URL_BUF_SIZE);
579     *PortConnect = GetPortFromHost(Host,*ssl_mode);
580   }
581   else
582   { /* Using proxy ? */
583     if(ReplaceHost[0] != 0)
584     { /* Ahh, we must replace host in URL_OUT */
585       if(URL[0] == 'h')
586       {
587         if(*ssl_mode)
588           strcpy(URL_OUT,"https://");
589         else
590           strcpy(URL_OUT,"http://");
591       }
592       else
593         strcpy(URL_OUT,"ftp://");
594       SU_strcpy(buf,ptr2,sizeof(buf));
595       SU_strcat(URL_OUT,ReplaceHost,URL_BUF_SIZE);
596       SU_strcat(URL_OUT,buf,URL_BUF_SIZE);
597       *PortConnect = GetPortFromHost((char *)ReplaceHost,*ssl_mode);
598     }
599   }
600   return 0;
601 }
602 
FreeAnswer(SU_PAnswer Ans)603 void FreeAnswer(SU_PAnswer Ans)
604 {
605   if(Ans == NULL)
606     return;
607   if(Ans->Location != NULL)
608     free(Ans->Location);
609   if(Ans->Data != NULL)
610     free(Ans->Data);
611 }
612 
ParseBuffer(SU_PAnswer Ans,char * Buf,int * len,SU_PHTTPActions Act,bool proxy)613 SU_PAnswer ParseBuffer(SU_PAnswer Ans,char *Buf,int *len,SU_PHTTPActions Act,bool proxy)
614 {
615   char *ptr,*ptr2;
616   char *tmp,*tok;
617   char *saf; /* Used at the end of the while ! DO NOT USE */
618   SU_PCookie Cok;
619   float f;
620   SU_PList Ptr;
621 
622   if(Ans == NULL)
623   {
624     Ans = (SU_PAnswer) malloc(sizeof(SU_TAnswer));
625     memset(Ans,0,sizeof(SU_TAnswer));
626     Ans->Data_Length = -1;
627     Ans->Data_ToReceive = -1;
628   }
629   if(Ans->Data_Length != -1)
630   {
631     Ans->Data = (char *) realloc(Ans->Data,Ans->Data_Length+*len+1); /* +1 for \0 */
632     memcpy(Ans->Data+Ans->Data_Length,Buf,*len);
633     Ans->Data_Length += *len;
634     Ans->Data[Ans->Data_Length] = 0;
635     *len = 0;
636     return Ans;
637   }
638   while(*len != 0)
639   {
640     ptr = strstr(Buf,"\r\n");
641     if(ptr == NULL) /* Not enough bytes received */
642       return Ans;
643     if(ptr == Buf) /* Data following */
644     {
645 #ifdef __unix__
646       if(SU_DebugLevel >= 3)
647       {
648         printf("SkyUtils_ParseBuffer : Found Data in HTTP answer\n");
649         if(Ans->Data_ToReceive >= 0)
650           printf("SkyUtils_ParseBuffer : Waiting %d bytes\n",Ans->Data_ToReceive);
651       }
652 #endif /* __unix__ */
653       Ans->Data_Length = 0;
654       if(*len == 2) /* Not enough data */
655         return Ans;
656       Ans->Data = (char *) malloc(*len-2+1); /* +1 for \0 */
657       memcpy(Ans->Data,Buf+2,*len-2);
658       Ans->Data_Length = *len - 2;
659       Ans->Data[Ans->Data_Length] = 0;
660       *len = 0;
661       return Ans;
662     }
663     ptr[0] = 0;
664     saf = ptr;
665     /* Parse header command */
666 #ifdef __unix__
667     if(SU_DebugLevel >= 3)
668       printf("SkyUtils_ParseBuffer : Found header : %s\n",Buf);
669 #endif /* __unix__ */
670     if(SU_nocasestrstr(Buf,"HTTP/") == Buf) /* Found reply code */
671     {
672       sscanf(Buf,"HTTP/%f %d",&f,&Ans->Code);
673     }
674     else if(SU_nocasestrstr(Buf,"Content-Length") == Buf)
675     {
676       Ans->Data_ToReceive = atoi(strchr(Buf,':')+1);
677     }
678     else if(SU_nocasestrstr(Buf,"Set-Cookie") == Buf) /* Found Set-Cookie */
679     {
680       Cok = (SU_PCookie) malloc(sizeof(SU_TCookie));
681       memset(Cok,0,sizeof(SU_TCookie));
682       tmp = SU_TrimLeft(strchr(Buf,':') + 1);
683       tmp = SU_strdup(tmp);
684       tok = SU_TrimLeft(strtok(tmp,";"));
685       /* Get NAME=VALUE */
686       ptr2 = strchr(tok,'=');
687       ptr2[0] = 0;
688       Cok->Name = SU_strdup(tok);
689       Cok->Value = SU_strdup(ptr2+1);
690       /* Get options */
691       tok = SU_TrimLeft(strtok(NULL,";"));
692       while(tok != NULL)
693       {
694         if(strncasecmp(tok,"expires",7) == 0)
695         {
696           ptr2 = strchr(tok,'=');
697           if(ptr2 != NULL)
698           {
699             Cok->Expire = SU_strdup(ptr2+1);
700           }
701           else
702             printf("SkyUtils_ParseBuffer Warning : Error with Expire value in cookie : %s\n",tok);
703         }
704         else if(strncasecmp(tok,"path",4) == 0)
705         {
706           ptr2 = strchr(tok,'=');
707           if(ptr2 != NULL)
708           {
709             Cok->Path = SU_strdup(ptr2+1);
710           }
711           else
712             printf("SkyUtils_ParseBuffer Warning : Error with Path value in cookie : %s\n",tok);
713         }
714         else if(strncasecmp(tok,"domain",6) == 0)
715         {
716           ptr2 = strchr(tok,'=');
717           if(ptr2 != NULL)
718           {
719             if(ptr2[1] == '.')
720               Cok->Domain = SU_strdup(ptr2+2);
721             else
722               Cok->Domain = SU_strdup(ptr2+1);
723           }
724           else
725             printf("SkyUtils_ParseBuffer Warning : Error with Domain value in cookie : %s\n",tok);
726         }
727         else if(strncasecmp(tok,"secure",6) == 0)
728         {
729           Cok->Secured = true;
730         }
731 #ifdef __unix__
732         else if(SU_DebugLevel >= 1)
733           printf("SkyUtils_ParseBuffer Warning : Unknown option in Set-Cookie : %s\n",tok);
734 #endif /* __unix__ */
735         tok = SU_TrimLeft(strtok(NULL,";"));
736       }
737       free(tmp);
738       if(Cok->Domain == NULL)
739       {
740         Cok->Domain = SU_strdup(Act->Host);
741       }
742       if(Cok->Path == NULL)
743       {
744         tmp = ExtractPath(Act->URL,proxy);
745         Cok->Path = SU_strdup(tmp);
746         free(tmp);
747       }
748 #ifdef __unix__
749       if(SU_DebugLevel >= 4)
750         AfficheCookie(Cok);
751 #endif /* __unix__ */
752       /* Check if a cookie with same Name/Domain/Path exists */
753       Ptr = SW_Cookies;
754       while(Ptr != NULL)
755       {
756         if((strcmp(((SU_PCookie)Ptr->Data)->Name,Cok->Name) == 0) && (strcmp(((SU_PCookie)Ptr->Data)->Domain,Cok->Domain) == 0))
757         {
758           if((Cok->Path != NULL) && (((SU_PCookie)Ptr->Data)->Path != NULL))
759           {
760             if(strcmp(((SU_PCookie)Ptr->Data)->Path,Cok->Path) == 0)
761             {
762               SU_FreeCookie((SU_PCookie)Ptr->Data);
763               Ptr->Data = Cok;
764               break;
765             }
766           }
767         }
768         Ptr = Ptr->Next;
769       }
770       if(Ptr == NULL)
771         SW_Cookies = SU_AddElementTail(SW_Cookies,Cok);
772     }
773     else if(SU_nocasestrstr(Buf,"Location") == Buf) /* Found Location */
774     {
775       ptr2 = SU_TrimLeft(strchr(Buf,':') + 1);
776       Ans->Location = SU_strdup(ptr2);
777     }
778     /* End of parse header command */
779     *len -= (saf - Buf) + 2;
780     memmove(Buf,saf+2,*len);
781   }
782   return Ans;
783 }
784 
CreateConnection(char Host[],int Port,SSL ** ssl)785 int CreateConnection(char Host[],int Port,SSL **ssl)
786 {
787   SU_SOCKET Sock;
788   struct sockaddr_in sin;
789   struct hostent *HE;
790 
791   Sock = socket(AF_INET,SOCK_STREAM,getprotobyname("tcp")->p_proto);
792   if(Sock == -1)
793     return -1;
794   sin.sin_family = AF_INET;
795   sin.sin_port = htons(Port);
796   sin.sin_addr.s_addr = inet_addr(Host);
797   if(sin.sin_addr.s_addr == INADDR_NONE)
798   {
799     HE = gethostbyname(Host);
800     if( HE == NULL )
801     {
802       printf("SkyUtils_CreateConnection : Unknown Host : %s\n",Host);
803       return -2;
804     }
805     sin.sin_addr = *(struct in_addr *)(HE->h_addr_list[0]);
806   }
807   if(connect(Sock,(struct sockaddr *)(&sin),sizeof(sin)) == -1)
808   {
809     SU_CLOSE_SOCKET(Sock);
810     return -3;
811   }
812 #ifdef SU_USE_SSL
813   if(ssl != NULL)
814   {
815     char errormsg[1024];
816     *ssl = SU_SSL_Connect(Sock,errormsg);
817     if(*ssl == NULL)
818     {
819       printf("SkyUtils_CreateConnection : %s\n", errormsg);
820       SU_CLOSE_SOCKET(Sock);
821       return -4;
822     }
823   }
824 #endif
825   return Sock;
826 }
827 
828 /* Base64 encode a string */
http_base64_encode(const char * text)829 char * http_base64_encode(const char *text)
830 {
831 
832   const char b64_alphabet[65] = {
833       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
834       "abcdefghijklmnopqrstuvwxyz"
835       "0123456789+/=" };
836 
837   /* The tricky thing about this is doing the padding at the end,
838    * doing the bit manipulation requires a bit of concentration only */
839   char *buffer = NULL;
840   char *point = NULL;
841   int inlen = 0;
842   int outlen = 0;
843 
844   /* check our args */
845   if (text == NULL)
846     return NULL;
847 
848   /* Use 'buffer' to store the output. Work out how big it should be...
849    * This must be a multiple of 4 bytes */
850 
851   inlen = strlen( text );
852   /* check our arg...avoid a pesky FPE */
853   if (inlen == 0)
854     {
855       buffer = (char *) malloc(sizeof(char));
856       buffer[0] = '\0';
857       return buffer;
858     }
859   outlen = (inlen*4)/3;
860   if( (inlen % 3) > 0 ) /* got to pad */
861     outlen += 4 - (inlen % 3);
862 
863   buffer = (char *) malloc( outlen + 1 ); /* +1 for the \0 */
864   memset(buffer, 0, outlen + 1); /* initialize to zero */
865 
866   /* now do the main stage of conversion, 3 bytes at a time,
867    * leave the trailing bytes (if there are any) for later */
868 
869   for( point=buffer; inlen>=3; inlen-=3, text+=3 ) {
870     *(point++) = b64_alphabet[ *text>>2 ];
871     *(point++) = b64_alphabet[ (*text<<4 & 0x30) | *(text+1)>>4 ];
872     *(point++) = b64_alphabet[ (*(text+1)<<2 & 0x3c) | *(text+2)>>6 ];
873     *(point++) = b64_alphabet[ *(text+2) & 0x3f ];
874   }
875 
876   /* Now deal with the trailing bytes */
877   if( inlen ) {
878     /* We always have one trailing byte */
879     *(point++) = b64_alphabet[ *text>>2 ];
880     *(point++) = b64_alphabet[ (*text<<4 & 0x30) |
881 			     (inlen==2?*(text+1)>>4:0) ];
882     *(point++) = (inlen==1?'=':b64_alphabet[ *(text+1)<<2 & 0x3c ] );
883     *(point++) = '=';
884   }
885 
886   *point = '\0';
887 
888   return buffer;
889 }
890 
SendBuffer(int Sock,char * buf,int len,SSL * ssl,bool verbose)891 static int SendBuffer(int Sock,char *buf,int len,SSL *ssl,bool verbose)
892 {
893   int res;
894 
895 #ifdef SU_USE_SSL
896   if(ssl)
897   {
898     if(verbose)
899     {
900       char errormsg[1024];
901       res = SU_SSL_Write(ssl,buf,len,errormsg);
902       if(res == -1)
903       {
904         printf("SkyUtils_SendCommand Error : Error sending command using SSL : %s\n",errormsg);
905       }
906     }
907     else
908       res = SU_SSL_Write(ssl,buf,len,NULL);
909   }
910   else
911 #endif /* SU_USE_SSL */
912 #ifdef __unix__
913   if(SU_DebugLevel >= 2)
914     printf("SkyUtils_SendCommand : Sending %s(%d) : %s\n",ssl?"SSL ":"",len,buf);
915 #endif /* __unix__ */
916   res = send(Sock,buf,len,0);
917   return res;
918 }
919 
SendFile(int Sock,FILE * fp,int FLen,SSL * ssl)920 static int SendFile(int Sock,FILE *fp,int FLen,SSL *ssl)
921 {
922   int res = 0;
923   char buf[16000];
924   int len,pos;
925 
926   while(res >= 0)
927   {
928     len = (FLen > sizeof(buf))?sizeof(buf):FLen;
929     if(fread(buf,len,1,fp) != 1)
930     {
931       res = -1;
932       break;
933     }
934 #ifdef SU_USE_SSL
935     if(ssl)
936       res = SU_SSL_Write(ssl,buf,len,NULL);
937     else
938 #endif /* SU_USE_SSL */
939     res = send(Sock,buf,len,SU_MSG_NOSIGNAL);
940     FLen -= len;
941     if(res <= 0)
942     {
943       res = -1;
944       break;
945     }
946     else if(res != len)
947     { /* Not all bytes sent */
948       pos = res;
949       len -= res;
950       while(len > 0)
951       {
952 #ifdef SU_USE_SSL
953         if(ssl)
954           res = SU_SSL_Write(ssl,buf+pos,len,NULL);
955         else
956 #endif /* SU_USE_SSL */
957         res = send(Sock,buf+pos,len,SU_MSG_NOSIGNAL);
958         if(res <= 0)
959           break;
960         pos += res;
961         len -= res;
962       }
963       if(res <= 0)
964         break;
965     }
966     if(FLen == 0)
967     {
968       len = 0;
969       buf[len++] = 0x0D;
970       buf[len++] = 0x0A;
971       buf[len] = 0;
972 #ifdef SU_USE_SSL
973       if(ssl)
974         res = SU_SSL_Write(ssl,buf,len,NULL);
975       else
976 #endif /* SU_USE_SSL */
977       send(Sock,buf,len,SU_MSG_NOSIGNAL);
978 #ifdef __unix__
979       if(SU_DebugLevel >= 2)
980         printf("SkyUtils_SendCommand : Successfully sent file\n");
981 #endif /* __unix__ */
982       res = 0;
983       break;
984     }
985   }
986   return res;
987 }
988 
SendCommand(SU_SOCKET Sock,SU_PHTTPActions Act,bool proxy,SSL * ssl)989 bool SendCommand(SU_SOCKET Sock,SU_PHTTPActions Act,bool proxy,SSL *ssl)
990 {
991   char buf[16000];
992   int len;
993   SU_u64 FLen;
994   int res;
995   char *Com,*tmp,*tmp2,*tmp3;
996   SU_PList Ptr;
997   int cook,blen,blen2;
998   FILE *fp;
999   bool do_it;
1000 
1001   if(Act->Command == ACT_GET)
1002     Com = "GET";
1003   else if(Act->Command == ACT_POST)
1004     Com = "POST";
1005   else if(Act->Command == ACT_PUT)
1006     Com = "PUT";
1007   else if(Act->Command == ACT_DELETE)
1008     Com = "DELETE";
1009   else
1010     Com = "ERROR";
1011   if(Act->URL_Params == NULL)
1012     SU_snprintf(buf,sizeof(buf),"%s %s HTTP/1.0%c%cHost: %s%c%c",Com,Act->URL,0x0D,0x0A,Act->Host,0x0D,0x0A);
1013   else
1014     SU_snprintf(buf,sizeof(buf),"%s %s?%s HTTP/1.0%c%cHost: %s%c%c",Com,Act->URL,Act->URL_Params,0x0D,0x0A,Act->Host,0x0D,0x0A);
1015   len = strlen(buf);
1016   /* Now add header from file, or default one */
1017   if(SW_UserHeader == NULL)
1018   {
1019     if(SW_UserAgent == NULL)
1020       SU_SetUserAgent(SW_DEFAULT_USER_AGENT);
1021     SU_snprintf(buf+len,sizeof(buf)-len,"User-Agent: %s\x0D\x0A%s",SW_UserAgent,SW_DEFAULT_HEADER);
1022   }
1023   else
1024     SU_snprintf(buf+len,sizeof(buf)-len,"%s",SW_UserHeader);
1025   len = strlen(buf);
1026 
1027   Ptr = SW_Cookies;
1028   cook = 0;
1029   while(Ptr != NULL)
1030   {
1031     blen = strlen(((SU_PCookie)Ptr->Data)->Domain)+2;
1032     if(strchr(Act->Host,':') == NULL)
1033     {
1034       tmp = (char *) malloc(blen);
1035       SU_snprintf(tmp,blen,"*%s",((SU_PCookie)Ptr->Data)->Domain);
1036     }
1037     else
1038     {
1039       tmp = (char *) malloc(blen+2);
1040       SU_snprintf(tmp,blen+2,"*%s:*",((SU_PCookie)Ptr->Data)->Domain);
1041     }
1042     if(SU_strwcmp(Act->Host,tmp))
1043     {
1044       do_it = false;
1045       if(((SU_PCookie)Ptr->Data)->Path == NULL)
1046         do_it = true;
1047       else
1048       {
1049         blen2 = strlen(((SU_PCookie)Ptr->Data)->Path)+2;
1050         tmp2 = (char *) malloc(blen2);
1051         SU_snprintf(tmp2,blen2,"%s*",((SU_PCookie)Ptr->Data)->Path);
1052         tmp3 = ExtractPath(Act->URL,proxy);
1053         if(SU_strwcmp(tmp3,tmp2))
1054           do_it = true;
1055         free(tmp2);
1056         free(tmp3);
1057       }
1058       if(do_it)
1059       {
1060         if(cook == 0)
1061         {
1062           SU_snprintf(buf+len,sizeof(buf)-len,"Cookie: %s=%s",((SU_PCookie)Ptr->Data)->Name,((SU_PCookie)Ptr->Data)->Value);
1063           len = strlen(buf);
1064           cook = 1;
1065         }
1066         else
1067         {
1068           SU_snprintf(buf+len,sizeof(buf)-len,"; %s=%s",((SU_PCookie)Ptr->Data)->Name,((SU_PCookie)Ptr->Data)->Value);
1069           len = strlen(buf);
1070         }
1071       }
1072     }
1073     free(tmp);
1074     Ptr = Ptr->Next;
1075   }
1076   if(cook != 0)
1077   {
1078     buf[len++] = 0x0D;
1079     buf[len++] = 0x0A;
1080   }
1081   if(Act->Referer != NULL)
1082   {
1083     SU_snprintf(buf+len,sizeof(buf)-len,"Referer: %s%c%c",Act->Referer,0x0D,0x0A);
1084     len = strlen(buf);
1085   }
1086   /* Manage proxy authorization */
1087   if(proxy != 0)
1088   {
1089     if(SW_Proxy_User != NULL)
1090     {
1091        char authtoken[256];
1092        char *auth64=NULL;
1093 
1094        if(SW_Proxy_Password != NULL)
1095           SU_snprintf(authtoken,255,"%s:%s",SW_Proxy_User,SW_Proxy_Password);
1096        else
1097           SU_snprintf(authtoken,255,"%s:",SW_Proxy_User);
1098        auth64 = http_base64_encode(authtoken);
1099        if(auth64 != NULL)
1100        {
1101           SU_snprintf(buf+len,sizeof(buf)-len,"Proxy-Authorization: Basic %s%c%c",auth64,0x0D,0x0A);
1102     	  len = strlen(buf);
1103           free(auth64);
1104        }
1105     }
1106   }
1107   if(Act->Command == ACT_POST)
1108   {
1109     if(Act->MultiParts == NULL) /* Post_Data */
1110     {
1111       SU_snprintf(buf+len,sizeof(buf)-len,"Content-type: application/x-www-form-urlencoded%c%cContent-length: %d%c%c%c%c",0x0D,0x0A,Act->Post_Length,0x0D,0x0A,0x0D,0x0A);
1112       len = strlen(buf);
1113       memcpy(buf+len,Act->Post_Data,Act->Post_Length);
1114       len += Act->Post_Length;
1115       buf[len++] = 0x0D;
1116       buf[len++] = 0x0A;
1117       buf[len] = 0;
1118       SendBuffer(Sock,buf,len,ssl,true);
1119     }
1120     else /* MultiParts */
1121     {
1122       int multi_length = 0;
1123       SU_PList Ptr = Act->MultiParts;
1124       SU_PHTTPPart Part;
1125       char boundary[27+13+1];
1126       int boundary_length;
1127       SU_u32 tim = (SU_u32) time(NULL);
1128       SU_u32 pid = SU_PROCESS_SELF;
1129       SU_u32 tid = SU_THREAD_SELF;
1130       if(tim >= 0x1000000)
1131         tim &= 0xFFFFFF;
1132       if(pid >= 0x10000)
1133         pid &= 0xFFFF;
1134       if(tid >= 0x1000)
1135         tid &= 0xFFF;
1136 
1137       SU_snprintf(boundary,sizeof(boundary),"---------------------------%06x%04x%03x",tim,pid,tid);
1138       boundary_length = strlen(boundary);
1139       while(Ptr != NULL)
1140       {
1141         Part = (SU_PHTTPPart) Ptr->Data;
1142         if(Part->FileName)
1143         {
1144           fp = fopen(Part->FileName,"rb");
1145           if(fp == NULL)
1146             return false;
1147           fseek(fp,0,SEEK_END);
1148           Part->Length = ftell(fp);
1149           fclose(fp);
1150         }
1151         multi_length += Part->Length + boundary_length + 2 + 2 + 2; /* +2 (--) before boundary, +2 (\n) after boundary, +2 (\n) at end of part */
1152         if(Part->Header)
1153         {
1154           multi_length += strlen(Part->Header) + 2; /* +2 after header */
1155         }
1156         multi_length += 2; /* +2 (--) for final boundary */
1157         Ptr = Ptr->Next;
1158       }
1159       SU_snprintf(buf+len,sizeof(buf)-len,"Content-type: multipart/form-data; boundary=%s%c%cContent-length: %d%c%c%c%c",boundary,0x0D,0x0A,multi_length,0x0D,0x0A,0x0D,0x0A);
1160       len = strlen(buf);
1161       buf[len] = 0;
1162       SendBuffer(Sock,buf,len,ssl,true);
1163 
1164       Ptr = Act->MultiParts;
1165       while(Ptr != NULL)
1166       {
1167         Part = (SU_PHTTPPart) Ptr->Data;
1168         if(Part->Header)
1169         {
1170           SU_snprintf(buf,sizeof(buf),"--%s%c%c%s%c%c%c%c",boundary,0x0D,0x0A,Part->Header,0x0D,0x0A,0x0D,0x0A);
1171           len = strlen(buf);
1172           buf[len] = 0;
1173         }
1174         else
1175         {
1176           SU_snprintf(buf,sizeof(buf),"--%s%c%c%c%c",boundary,0x0D,0x0A,0x0D,0x0A);
1177           len = strlen(buf);
1178           buf[len] = 0;
1179         }
1180         SendBuffer(Sock,buf,len,ssl,true);
1181         if(Part->FileName) /* File */
1182         {
1183           fp = fopen(Part->FileName,"rb");
1184           if(fp == NULL)
1185             return false;
1186           res = SendFile(Sock,fp,Part->Length,ssl);
1187           fclose(fp);
1188           if(res == -1)
1189             return false;
1190         }
1191         else /* Data */
1192         {
1193           SendBuffer(Sock,Part->Data,Part->Length,ssl,false);
1194         }
1195         /* End of boundary */
1196         SU_snprintf(buf,sizeof(buf),"%c%c",0x0D,0x0A);
1197         len = strlen(buf);
1198         buf[len] = 0;
1199         SendBuffer(Sock,buf,len,ssl,true);
1200         Ptr = Ptr->Next;
1201       }
1202       /* Final boundary */
1203       SU_snprintf(buf,sizeof(buf),"--%s--%c%c",boundary,0x0D,0x0A);
1204       len = strlen(buf);
1205       buf[len] = 0;
1206       SendBuffer(Sock,buf,len,ssl,true);
1207     }
1208   }
1209   else if((Act->Command == ACT_GET) || (Act->Command == ACT_DELETE))
1210   {
1211     if(Act->ContentType != NULL)
1212     {
1213       SU_snprintf(buf+len,sizeof(buf)-len,"Content-Type: %s%c%c",Act->ContentType,0x0D,0x0A);
1214       len = strlen(buf);
1215     }
1216     buf[len++] = 0x0D;
1217     buf[len++] = 0x0A;
1218     buf[len] = 0;
1219     SendBuffer(Sock,buf,len,ssl,true);
1220   }
1221   if(Act->Command == ACT_PUT)
1222   {
1223     fp = fopen(Act->FileName,"rb");
1224     if(fp == NULL)
1225       return false;
1226     fseek(fp,0,SEEK_END);
1227     FLen = (SU_u64)ftell(fp);
1228     rewind(fp);
1229 #ifdef __unix__
1230     if(SU_DebugLevel >= 2)
1231       printf("SkyUtils_SendCommand : Sending file %s of length %ld\n",Act->FileName,FLen);
1232 #endif /* __unix__ */
1233     SU_snprintf(buf+len,sizeof(buf)-len,"Content-Type: application/octet-stream%c%cContent-length: %ld%c%c%c%c",FLen,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A);
1234     len = strlen(buf);
1235     res = SendBuffer(Sock,buf,len,ssl,true);
1236     res = SendFile(Sock,fp,(int)FLen,ssl);
1237     fclose(fp);
1238     if(res == -1)
1239     {
1240       if(Act->CB.OnErrorSendingFile != NULL)
1241         Act->CB.OnErrorSendingFile(errno,Act->User);
1242 #ifdef __unix__
1243       if(SU_DebugLevel >= 2)
1244         printf("SkyUtils_SendCommand Warning : Error sending file, %ld bytes remaining that were not sent\n",FLen);
1245 #endif /* __unix__ */
1246     }
1247 #ifdef SU_USE_SSL
1248     if(ssl)
1249     {
1250       SU_SSL_SessionCleanup(ssl);
1251     }
1252 #endif /* SU_USE_SSL */
1253     SU_CLOSE_SOCKET(Sock);
1254     return res == 0;
1255   }
1256   return true;
1257 }
1258 
WaitForAnswer(SU_SOCKET Sock,SU_PHTTPActions Act,bool proxy,SSL * ssl)1259 SU_PAnswer WaitForAnswer(SU_SOCKET Sock,SU_PHTTPActions Act,bool proxy,SSL *ssl)
1260 {
1261   int len;
1262   int BufPos = 0;
1263   char Buf[32768];
1264   SU_PAnswer Ans = NULL;
1265   fd_set rfds;
1266   struct timeval tv;
1267   int retval;
1268 
1269   FD_ZERO(&rfds);
1270   FD_SET(Sock,&rfds);
1271   tv.tv_sec = SW_SocketTimeout;
1272   tv.tv_usec = 0;
1273   retval = select(Sock+1,&rfds,NULL,NULL,&tv);
1274   if(retval != 1)
1275     return NULL;
1276 #ifdef SU_USE_SSL
1277   if(ssl)
1278     len = SU_SSL_Read(ssl,Buf,sizeof(Buf),NULL);
1279   else
1280 #endif /* SU_USE_SSL */
1281   len = recv(Sock,Buf,sizeof(Buf),0);
1282   while(len > 0)
1283   {
1284     len += BufPos;
1285     Ans = ParseBuffer(Ans,Buf,&len,Act,proxy);
1286     BufPos = len;
1287     if(Ans->Data_ToReceive >= 0)
1288     {
1289       if(Ans->Data_Length >= Ans->Data_ToReceive)
1290         break;
1291     }
1292     FD_ZERO(&rfds);
1293     FD_SET(Sock,&rfds);
1294     tv.tv_sec = SW_SocketTimeout;
1295     tv.tv_usec = 0;
1296     retval = select(Sock+1,&rfds,NULL,NULL,&tv);
1297     if(retval == 0) /* Time out */
1298     {
1299       if(Ans->Data_Length == -1)
1300       {
1301         FreeAnswer(Ans);
1302         Ans = NULL;
1303       }
1304 #ifdef __unix__
1305       else if(SU_DebugLevel >= 1)
1306         printf("SkyUtils_WaitForAnswer Warning : Connection timed out, but some data was retrieved\n");
1307 //        printf("SkyUtils_WaitForAnswer Warning : Connection timed out, but some datas were retrieved\n");
1308 #endif /* __unix__ */
1309       break;
1310     }
1311     else if(retval < 0)
1312     {
1313       if(Ans->Data_Length == -1)
1314       {
1315         FreeAnswer(Ans);
1316         Ans = NULL;
1317       }
1318 #ifdef __unix__
1319       else if(SU_DebugLevel >= 1)
1320         printf("SkyUtils_WaitForAnswer Warning : Unexpected network error : %d\n",errno);
1321 #endif /* __unix__ */
1322       break;
1323     }
1324 #ifdef SU_USE_SSL
1325     if(ssl)
1326       len = SU_SSL_Read(ssl,Buf+BufPos,sizeof(Buf)-BufPos,NULL);
1327     else
1328 #endif /* SU_USE_SSL */
1329     len = recv(Sock,Buf+BufPos,sizeof(Buf)-BufPos,0);
1330   }
1331 #ifdef SU_USE_SSL
1332   if(ssl)
1333   {
1334     SU_SSL_SessionCleanup(ssl);
1335   }
1336 #endif /* SU_USE_SSL */
1337   SU_CLOSE_SOCKET(Sock);
1338   if(Ans != NULL)
1339   {
1340 #ifdef __unix__
1341     if(SU_DebugLevel >= 5)
1342       DumpPage(NULL,Ans->Data,Ans->Data_Length);
1343 #endif /* __unix__ */
1344     if((Ans->Data != NULL) && (Act->FileName != NULL) && ((Act->Command == ACT_GET) || (Act->Command == ACT_POST)))
1345       DumpPage(Act->FileName,Ans->Data,Ans->Data_Length);
1346   }
1347   return Ans;
1348 }
1349 
SU_SendProxySSLConnect(SU_SOCKET Sock,char * Host,int Port,int * Code)1350 bool SU_SendProxySSLConnect(SU_SOCKET Sock,char *Host,int Port,int *Code)
1351 {
1352   char buf[1024];
1353   int res,len;
1354   fd_set rfds;
1355   struct timeval tv;
1356   int retval,BufPos = 0;
1357   bool found = false,again = true;
1358   char *ptr;
1359   float f;
1360 
1361   if(SW_UserAgent == NULL)
1362     SU_SetUserAgent(SW_DEFAULT_USER_AGENT);
1363   SU_snprintf(buf,sizeof(buf),"CONNECT %s:%d HTTP/1.0%c%cUser-Agent: %s%c%cHost: %s%c%cProxy-Connection: close%c%cConnection: close%c%c%c%c",Host,Port,0x0D,0x0A,SW_UserAgent,0x0D,0x0A,Host,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A);
1364   len = strlen(buf);
1365   res = send(Sock,buf,len,0);
1366   if(res != len)
1367     return false;
1368 
1369   FD_ZERO(&rfds);
1370   FD_SET(Sock,&rfds);
1371   tv.tv_sec = SW_SocketTimeout;
1372   tv.tv_usec = 0;
1373   retval = select(Sock+1,&rfds,NULL,NULL,&tv);
1374   if(retval != 1)
1375     return false;
1376   res = recv(Sock,buf,sizeof(buf)-1,0);
1377   while((res > 0) && again)
1378   {
1379     BufPos += res;
1380     buf[BufPos] = 0;
1381     ptr = strstr(buf,"\r\n");
1382     while(ptr != NULL)
1383     {
1384       if(ptr == buf) /* End of answer */
1385       {
1386         again = false;
1387         break;
1388       }
1389       if(SU_nocasestrstr(buf,"HTTP/") == buf) /* Found reply code */
1390       {
1391         sscanf(buf,"HTTP/%f %d",&f,Code);
1392         if(*Code == 200) /* Ok */
1393         {
1394           BufPos = 0;
1395           found = true;
1396           break;
1397         }
1398       }
1399       BufPos -= ptr+2-buf-1; /* -1 for \0 */
1400       memmove(buf,ptr+2,BufPos);
1401       ptr = strstr(buf,"\r\n");
1402     }
1403     if(again)
1404       break;
1405     FD_ZERO(&rfds);
1406     FD_SET(Sock,&rfds);
1407     tv.tv_sec = SW_SocketTimeout;
1408     tv.tv_usec = 0;
1409     retval = select(Sock+1,&rfds,NULL,NULL,&tv);
1410     if(retval != 1)
1411       return found;
1412     res = recv(Sock,buf+BufPos,sizeof(buf)-BufPos-1,0);
1413   }
1414   return found;
1415 }
1416 
SU_EncodeURL(const char URL_in[],char URL_out[],int URL_out_len)1417 char *SU_EncodeURL(const char URL_in[],char URL_out[],int URL_out_len)
1418 {
1419   char NB[10];
1420   int i,pos;
1421 
1422   pos = 0;
1423   for(i=0;i<(int)strlen(URL_in);i++)
1424   {
1425     if((URL_in[i] >='!') && (URL_in[i] <='~'))
1426     {
1427       if((pos+1) >= URL_out_len)
1428       {
1429         break;
1430       }
1431       URL_out[pos++] = URL_in[i];
1432     }
1433     else
1434     {
1435       if((pos+3) >= URL_out_len)
1436       {
1437         break;
1438       }
1439       URL_out[pos++] = '%';
1440       SU_snprintf(NB,sizeof(NB),"%.2x",URL_in[i]);
1441       URL_out[pos++] = NB[strlen(NB)-2];
1442       URL_out[pos++] = NB[strlen(NB)-1];
1443     }
1444   }
1445   URL_out[pos] = 0;
1446   return URL_out;
1447 }
1448 
SU_ExecuteActions(SU_PList Actions)1449 int SU_ExecuteActions(SU_PList Actions)
1450 {
1451   SU_PList Ptr = Actions;
1452   SU_PList ActRec = NULL;
1453   SU_PAnswer Ans;
1454   SU_THTTPActions Act;
1455   char URL_OUT[URL_BUF_SIZE];
1456   int  Sock;
1457   char *ptr;
1458   int  PortConnect;
1459   SSL *ssl = NULL;
1460   bool ssl_mode = false;
1461   int Code;
1462   char *proxy_string;
1463 
1464   while(Ptr != NULL)
1465   {
1466     if(((SU_PHTTPActions)Ptr->Data)->Sleep != 0)
1467     {
1468 #ifdef __unix__
1469       if(SU_DebugLevel >= 1)
1470         printf("SkyUtils_SU_ExecuteActions : Sleeping %d sec before sending command\n",((SU_PHTTPActions)Ptr->Data)->Sleep);
1471       sleep(((SU_PHTTPActions)Ptr->Data)->Sleep); /* Sleeping */
1472 #else /* !__unix__ */
1473       Sleep(((SU_PHTTPActions)Ptr->Data)->Sleep*1000); /* Sleeping */
1474 #endif /* __unix__ */
1475     }
1476     switch(((SU_PHTTPActions)Ptr->Data)->Command)
1477     {
1478       case ACT_GET :
1479       case ACT_POST :
1480       case ACT_PUT :
1481       case ACT_DELETE :
1482         Code = GetHostFromURL(((SU_PHTTPActions)Ptr->Data)->URL,((SU_PHTTPActions)Ptr->Data)->Host,sizeof(((SU_PHTTPActions)Ptr->Data)->Host),(SW_Proxy_String != NULL),URL_OUT,&PortConnect,((SU_PHTTPActions)Ptr->Data)->Host,&ssl_mode);
1483         if(Code != 0)
1484           return Code;
1485         ((SU_PHTTPActions)Ptr->Data)->SSL = ssl_mode;
1486         if(((SU_PHTTPActions)Ptr->Data)->CB.OnSendingCommand != NULL)
1487           ((SU_PHTTPActions)Ptr->Data)->CB.OnSendingCommand((SU_PHTTPActions)Ptr->Data);
1488         /* Get URL_OUT once again, if 'Act' has been modified in OnSendingCommand */
1489         Code = GetHostFromURL(((SU_PHTTPActions)Ptr->Data)->URL,((SU_PHTTPActions)Ptr->Data)->Host,sizeof(((SU_PHTTPActions)Ptr->Data)->Host),(SW_Proxy_String != NULL),URL_OUT,&PortConnect,"",&ssl_mode);
1490         SU_strcpy(((SU_PHTTPActions)Ptr->Data)->URL,URL_OUT,sizeof(URL_OUT));
1491         if(SW_Proxy_String != NULL)
1492         {
1493 #ifdef __unix__
1494           if(SU_DebugLevel >= 1)
1495           {
1496             if(SW_Proxy_User == NULL)
1497               printf("SkyUtils_SU_ExecuteActions : Using proxy: %s, port %d\n",SW_Proxy_String,SW_Proxy_Port);
1498             else
1499               printf("SkyUtils_SU_ExecuteActions : Using proxy: %s, with user %s [%s], port %d\n",SW_Proxy_String,SW_Proxy_User,SW_Proxy_Password,SW_Proxy_Port);
1500           }
1501 #endif /* __unix__ */
1502           Sock = CreateConnection(SW_Proxy_String,SW_Proxy_Port,NULL); /* Not using SSL struct with a proxy */
1503         }
1504         else
1505           Sock = CreateConnection(((SU_PHTTPActions)Ptr->Data)->Host,PortConnect,ssl_mode?&ssl:NULL);
1506         if(Sock < 0)
1507         {
1508           printf("SkyUtils_SU_ExecuteActions Error : Cannot connect to the host\n");
1509           return(-1);
1510         }
1511         proxy_string = SW_Proxy_String;
1512 #ifdef SU_USE_SSL
1513         if((SW_Proxy_String != NULL) && ssl_mode) /* If proxy AND ssl, must send a CONNECT message to the proxy */
1514         {
1515           char errormsg[1024];
1516 #ifdef __unix__
1517           if(SU_DebugLevel >= 1)
1518           {
1519             printf("SkyUtils_SU_ExecuteActions : Sending SSL CONNECT to the proxy, for %s:%d\n",((SU_PHTTPActions)Ptr->Data)->Host,GetPortFromHost(((SU_PHTTPActions)Ptr->Data)->Host,true));
1520           }
1521 #endif /* __unix__ */
1522           if(!SU_SendProxySSLConnect(Sock,((SU_PHTTPActions)Ptr->Data)->Host,GetPortFromHost(((SU_PHTTPActions)Ptr->Data)->Host,true),&Code))
1523           {
1524             printf("SkyUtils_SU_ExecuteActions Error : Cannot send CONNECT message to the proxy : Code=%d\n",Code);
1525             return(-1);
1526           }
1527 #ifdef __unix__
1528           if(SU_DebugLevel >= 1)
1529           {
1530             printf("SkyUtils_SU_ExecuteActions : SSL CONNECT successfully sent !\n");
1531           }
1532 #endif /* __unix__ */
1533           ssl = SU_SSL_Connect(Sock,errormsg);
1534           if(ssl == NULL)
1535           {
1536             printf("SkyUtils_SU_ExecuteActions Error : Cannot create SSL connection : %s\n",errormsg);
1537             return(-1);
1538           }
1539           proxy_string = NULL;
1540           /* Transforming URL as if we were not using a proxy */
1541           Code = GetHostFromURL(((SU_PHTTPActions)Ptr->Data)->URL,((SU_PHTTPActions)Ptr->Data)->Host,sizeof(((SU_PHTTPActions)Ptr->Data)->Host),false,URL_OUT,&PortConnect,"",&ssl_mode);
1542           if(Code != 0)
1543             return Code;
1544           SU_strcpy(((SU_PHTTPActions)Ptr->Data)->URL,URL_OUT,sizeof(URL_OUT));
1545         }
1546 #endif /* SU_USE_SSL */
1547         if(SendCommand(Sock,(SU_PHTTPActions)Ptr->Data,(proxy_string != NULL),ssl_mode?ssl:NULL)) /* If SSL && proxy, simulate NO PROXY */
1548         {
1549           Ans = WaitForAnswer(Sock,((SU_PHTTPActions)Ptr->Data),(proxy_string != NULL),ssl_mode?ssl:NULL);
1550           if(Ans == NULL)
1551           {
1552             printf("SkyUtils_SU_ExecuteActions Error : Connection timed out\n");
1553             return(-2);
1554           }
1555           if(((SU_PHTTPActions)Ptr->Data)->CB.OnAnswer != NULL)
1556             ((SU_PHTTPActions)Ptr->Data)->CB.OnAnswer(Ans,((SU_PHTTPActions)Ptr->Data)->User);
1557 #ifdef __unix__
1558           if(SU_DebugLevel >= 2)
1559             printf("SkyUtils_SU_ExecuteActions : Found Code : %d\n",Ans->Code);
1560 #endif /* __unix__ */
1561           switch(Ans->Code)
1562           {
1563             case 200 : /* Ok reply */
1564               if(((SU_PHTTPActions)Ptr->Data)->CB.OnOk != NULL)
1565                 ((SU_PHTTPActions)Ptr->Data)->CB.OnOk(Ans,((SU_PHTTPActions)Ptr->Data)->User);
1566               break;
1567             case 201 : /* Created */
1568               if(((SU_PHTTPActions)Ptr->Data)->CB.OnCreated != NULL)
1569                 ((SU_PHTTPActions)Ptr->Data)->CB.OnCreated(Ans,((SU_PHTTPActions)Ptr->Data)->User);
1570               break;
1571             case 202 : /* Modified */
1572               if(((SU_PHTTPActions)Ptr->Data)->CB.OnModified != NULL)
1573                 ((SU_PHTTPActions)Ptr->Data)->CB.OnModified(Ans,((SU_PHTTPActions)Ptr->Data)->User);
1574               break;
1575             case 301 : /* Moved */
1576             case 302 : /* Moved */
1577             case 303 : /* Moved */
1578               if(((SU_PHTTPActions)Ptr->Data)->CB.OnMoved != NULL)
1579                 ((SU_PHTTPActions)Ptr->Data)->CB.OnMoved(Ans,((SU_PHTTPActions)Ptr->Data)->User);
1580               memset(&Act,0,sizeof(Act));
1581               if(((SU_PHTTPActions)Ptr->Data)->FileName)
1582                 Act.FileName = SU_strdup(((SU_PHTTPActions)Ptr->Data)->FileName);
1583               Act.User = ((SU_PHTTPActions)Ptr->Data)->User;
1584               memcpy(&Act.CB,&((SU_PHTTPActions)Ptr->Data)->CB,sizeof(Act.CB));
1585               Act.Command = ACT_GET;
1586               if(SU_nocasestrstr(Ans->Location,"http://") != Ans->Location) /* Relative path */
1587               {
1588                 if(SU_nocasestrstr(Ans->Location,"https://") != Ans->Location) /* Really a relative path */
1589                 {
1590                   ptr = SU_AddLocationToUrl(((SU_PHTTPActions)Ptr->Data)->URL,((SU_PHTTPActions)Ptr->Data)->Host,Ans->Location,((SU_PHTTPActions)Ptr->Data)->SSL);
1591                   free(Ans->Location);
1592                   Ans->Location = ptr;
1593                 }
1594               }
1595               /* Let say we use a proxy, so we have less code to execute :o) */
1596               Code = GetHostFromURL(Ans->Location,((SU_PHTTPActions)Ptr->Data)->Host,sizeof(Act.Host),true,Act.URL,&PortConnect,"",&ssl_mode);
1597               if(Code != 0)
1598                 return Code;
1599               SU_EncodeURL(Ans->Location,Act.URL,sizeof(Act.URL));
1600               Act.URL_Params = NULL;
1601               if(((SU_PHTTPActions)Ptr->Data)->Referer != NULL)
1602                 Act.Referer = ((SU_PHTTPActions)Ptr->Data)->Referer;
1603               else
1604                 Act.Referer = ((SU_PHTTPActions)Ptr->Data)->URL;
1605               ActRec = SU_AddElementHead(NULL,&Act);
1606               SU_ExecuteActions(ActRec);
1607               if(Act.FileName)
1608                 free(Act.FileName);
1609               ActRec = SU_DelElementHead(ActRec);
1610               break;
1611             case 403 : /* Forbidden */
1612               if(((SU_PHTTPActions)Ptr->Data)->CB.OnForbidden != NULL)
1613                 ((SU_PHTTPActions)Ptr->Data)->CB.OnForbidden(Ans,((SU_PHTTPActions)Ptr->Data)->User);
1614               break;
1615             case 404 : /* Page Not Found */
1616               if(((SU_PHTTPActions)Ptr->Data)->CB.OnNotFound != NULL)
1617                 ((SU_PHTTPActions)Ptr->Data)->CB.OnNotFound(Ans,((SU_PHTTPActions)Ptr->Data)->User);
1618               break;
1619             case 413 : /* Request entity too large */
1620               if(((SU_PHTTPActions)Ptr->Data)->CB.OnTooBig != NULL)
1621                 ((SU_PHTTPActions)Ptr->Data)->CB.OnTooBig(Ans,((SU_PHTTPActions)Ptr->Data)->User);
1622               break;
1623             case 503 : /* Unknown Host */
1624               if(((SU_PHTTPActions)Ptr->Data)->CB.OnUnknownHost != NULL)
1625                 ((SU_PHTTPActions)Ptr->Data)->CB.OnUnknownHost(Ans,((SU_PHTTPActions)Ptr->Data)->User);
1626               break;
1627             default : /* Other */
1628               if(((SU_PHTTPActions)Ptr->Data)->CB.OnOtherReply != NULL)
1629                 ((SU_PHTTPActions)Ptr->Data)->CB.OnOtherReply(Ans,Ans->Code,((SU_PHTTPActions)Ptr->Data)->User);
1630               break;
1631           }
1632           FreeAnswer(Ans);
1633         }
1634         break;
1635       default :
1636         printf("SkyUtils_SU_ExecuteActions Warning : Unknown Action !!\n");
1637     }
1638     Ptr = Ptr->Next;
1639   }
1640   return 0;
1641 }
1642 
SU_FreePart(SU_PHTTPPart Part)1643 void SU_FreePart(SU_PHTTPPart Part)
1644 {
1645   if(Part->Header)
1646     free(Part->Header);
1647   if(Part->FileName)
1648     free(Part->FileName);
1649   if(Part->Data)
1650     free(Part->Data);
1651   free(Part);
1652 }
1653 
SU_FreeAction(SU_PHTTPActions Act)1654 void SU_FreeAction(SU_PHTTPActions Act)
1655 {
1656   if(Act->URL_Params != NULL)
1657     free(Act->URL_Params);
1658   if(Act->Post_Data != NULL)
1659     free(Act->Post_Data);
1660   if(Act->FileName != NULL)
1661     free(Act->FileName);
1662   if(Act->Referer != NULL)
1663     free(Act->Referer);
1664   if(Act->ContentType)
1665     free(Act->ContentType);
1666   if(Act->MultiParts)
1667   {
1668     SU_PList Ptr = Act->MultiParts;
1669     while(Ptr != NULL)
1670     {
1671       SU_FreePart(Ptr->Data);
1672       Ptr = Ptr->Next;
1673     }
1674     SU_FreeList(Act->MultiParts);
1675   }
1676   free(Act);
1677 }
1678 
SU_GetInput(char * html)1679 SU_PInput SU_GetInput(char *html)
1680 {
1681   SW_GetInput_String = html;
1682   return SU_GetNextInput();
1683 }
1684 
SU_GetNextInput(void)1685 SU_PInput SU_GetNextInput(void)
1686 {
1687   char *p,*ps,*pt,*q,*r,*s,*tmp,buf[500];
1688   char c,toto[3],res;
1689   int len;
1690   SU_PInput In;
1691   bool textarea = false;
1692 
1693   p = SU_nocasestrstr(SW_GetInput_String,"<input");
1694   ps = SU_nocasestrstr(SW_GetInput_String,"<select");
1695   pt = SU_nocasestrstr(SW_GetInput_String,"<textarea");
1696   if((pt != NULL) && ((pt<p) || (p == NULL)) && ((pt<ps) || (ps == NULL))) /* Textarea found first */
1697   {
1698     p = pt+3; /* +3 to adjust from sizeof("textarea") to sizeof("input") */
1699     textarea = true;
1700   }
1701   if(((p>ps) || (p == NULL)) && (ps != NULL))
1702     p = ps+1; /* +1 to adjust from sizeof("select") to sizeof("input") */
1703   if(p == NULL)
1704     return NULL;
1705   s = p;
1706   In = (SU_PInput) malloc(sizeof(SU_TInput));
1707   memset(In,0,sizeof(SU_TInput));
1708   p+=7;
1709   r = strchr(p,'>');
1710   /* Now parse input tags */
1711   toto[0] = '=';
1712   toto[1] = ' ';
1713   toto[2] = 0;
1714   while(p[0] != '>')
1715   {
1716     while(*p == ' ')
1717       p++;
1718     q = SU_strchrl(p,toto,&res);
1719     if(q == NULL)
1720       break;
1721     if(q > r) /* Attention ici, si on veux plus tard recup les non Name=Value */
1722       break;
1723     len = q-p;
1724     if(len >= sizeof(buf))
1725       len = sizeof(buf) - 1;
1726     memcpy(buf,p,len);
1727     buf[len] = 0;
1728     /* buf contient la partie Name de Name=Value */
1729     p = SU_TrimLeft(q + 1);
1730     if(res == ' ')
1731     {
1732       if(p[0] != '=')
1733         continue;
1734       else
1735         p = SU_TrimLeft(p+1);
1736     }
1737     while((len > 0) && (buf[len-1] == ' '))
1738     {
1739       len--;
1740       buf[len] = 0; /* Remove trailing spaces */
1741     }
1742     if((strchr(buf,' ') == NULL) && (res != '>')) /* Si on a bien a faire a un Name=Value */
1743     {
1744       if(p[0] == '"') /* Si la partie Value est une chaine */
1745       {
1746         c = '"';
1747         p++;
1748       }
1749       else if(p[0] == '\'') /* Si la partie Value est une chaine */
1750       {
1751         c = '\'';
1752         p++;
1753       }
1754       else
1755         c = ' ';
1756       q = strchr(p,c);
1757       if(q == NULL)
1758         break;
1759       if(q > r)
1760       {
1761         if((c == '"') || (c == '\'')) /* '>' must be inside the string */
1762           r = strchr(r+1,'>');
1763         else
1764           q = r;
1765       }
1766       len = q-p;
1767       if(len <= 0)
1768         continue;
1769       tmp = (char *) malloc(len+1);
1770       memcpy(tmp,p,len);
1771       tmp[len] = 0;
1772       p = q;
1773       if((c == '"') || (c == '\'')) /* Si la partie Value est une chaine */
1774         p++;
1775       if(SU_nocasestrstr(buf,"type") == buf)
1776         In->Type = tmp;
1777       else if(SU_nocasestrstr(buf,"name") == buf)
1778         In->Name = tmp;
1779       else if(SU_nocasestrstr(buf,"value") == buf)
1780         In->Value = tmp;
1781       else
1782         free(tmp);
1783     }
1784   }
1785   if(textarea)
1786   {
1787     if(In->Type == NULL)
1788       In->Type = SU_strdup("textarea");
1789     p = SU_nocasestrstr(r+1,"</textarea>");
1790     if(p == NULL)
1791     {
1792       if(In->Name != NULL)
1793       {
1794         free(In->Name);
1795         In->Name = NULL;
1796       }
1797     }
1798     else
1799     {
1800       if(In->Value != NULL)
1801         free(In->Value);
1802       In->Value = (char *) malloc(p-r);
1803       SU_strcpy(In->Value,r+1,p-r);
1804       r = p+2;
1805     }
1806   }
1807   if(r != NULL)
1808     SW_GetInput_String = r;
1809   else
1810     SW_GetInput_String = s+6;
1811   if(In->Name == NULL)
1812   {
1813     SU_FreeInput(In);
1814     return SU_GetNextInput();
1815   }
1816   return In;
1817 }
1818 
SU_FreeInput(SU_PInput In)1819 void SU_FreeInput(SU_PInput In)
1820 {
1821   if(In->Type != NULL)
1822     free(In->Type);
1823   if(In->Name != NULL)
1824     free(In->Name);
1825   if(In->Value != NULL)
1826     free(In->Value);
1827   free(In);
1828 }
1829 
SU_GetImage(char * html)1830 SU_PImage SU_GetImage(char *html)
1831 {
1832   SW_GetImage_String = html;
1833   return SU_GetNextImage();
1834 }
1835 
SU_GetNextImage(void)1836 SU_PImage SU_GetNextImage(void)
1837 {
1838   char *p,*q,*tmp;
1839   int len;
1840   char c;
1841   SU_PImage Im;
1842 
1843   p = SU_nocasestrstr(SW_GetImage_String,"img src");
1844   if(p == NULL)
1845     return NULL;
1846   Im = (SU_PImage) malloc(sizeof(SU_TImage));
1847   memset(Im,0,sizeof(SU_TImage));
1848   p+=7;
1849   while(*p == ' ')
1850     p++;
1851   p++; /* zap le '=' */
1852   while(*p == ' ')
1853     p++; /* zap les espaces apres le '=' */
1854   if(*p == '"')
1855   {
1856     c = '"';
1857     p++; /* zap le '"' si c'est une chaine */
1858   }
1859   else if(*p == '\'')
1860   {
1861     c = '\'';
1862     p++; /* zap le '\'' si c'est une chaine */
1863   }
1864   else
1865     c = ' ';
1866   q = strchr(p,c);
1867   len = q-p;
1868   tmp = (char *) malloc(len+1);
1869   memcpy(tmp,p,len);
1870   tmp[len] = 0;
1871   p = q;
1872   if((c == '"') || (c == '\'')) /* Si la partie Value est une chaine */
1873     p++;
1874   Im->Src = tmp;
1875   while(p[0] != '>')
1876   {
1877     /* Faudrait boucler ici pour recup le Name eventuellement */
1878     p++;
1879   }
1880 
1881   SW_GetImage_String = p;
1882   return Im;
1883 }
1884 
SU_FreeImage(SU_PImage Im)1885 void SU_FreeImage(SU_PImage Im)
1886 {
1887   if(Im->Src != NULL)
1888     free(Im->Src);
1889   if(Im->Name != NULL)
1890     free(Im->Name);
1891   free(Im);
1892 }
1893 
SU_RetrieveLink(const char URL[],const char Ans[],const char link[],const int index)1894 SU_PHTTPActions SU_RetrieveLink(const char URL[],const char Ans[],const char link[],const int index)
1895 {
1896   char *p,*q,c,*tmp,*tmp2,*rp,*rs;
1897   SU_PHTTPActions Act;
1898   int i;
1899   bool found;
1900 
1901   p = (char *)Ans-1;
1902   for(i=1;i<=index;i++)
1903     p = strstr(p+1,link);
1904   if(p == NULL)
1905     return NULL;
1906   while(strncasecmp(p,"href",4) != 0)
1907     p--;
1908   p+=4;
1909   p = SU_TrimLeft(p); /* Remove spaces */
1910   p++; /* Zap '=' */
1911   p = SU_TrimLeft(p); /* Remove spaces */
1912   if(p[0] == '"')
1913   {
1914     c = '"';
1915     p++; /* Zap '"' */
1916   }
1917   else if(p[0] == '\'')
1918   {
1919     c = '\'';
1920     p++; /* Zap '\'' */
1921   }
1922   else
1923     c = ' ';
1924   q = strchr(p,c);
1925   tmp = (char *) malloc(q-p+1);
1926   SU_strcpy(tmp,p,q-p+1);
1927 
1928   Act = (SU_PHTTPActions) malloc(sizeof(SU_THTTPActions));
1929   memset(Act,0,sizeof(SU_THTTPActions));
1930   Act->Command = ACT_GET;
1931   /* URL in tmp, but may be relative */
1932   if(strncasecmp(tmp,"http",4) == 0) /* Absolute */
1933     strncpy(Act->URL,tmp,sizeof(Act->URL));
1934   else
1935   {
1936     if(tmp[0] == '/') /* Root of the host */
1937     {
1938 #ifdef __unix__
1939       tmp2 = strchr(URL+7,'/');
1940 #else /* !__unix__ */
1941       tmp2 = strchr((char *)URL+7,'/');
1942 #endif /* __unix__ */
1943       if(tmp2 == NULL) /* Already at the root of the site */
1944       {
1945         SU_strcpy(Act->URL,URL,sizeof(Act->URL));
1946         SU_strcat(Act->URL,tmp,sizeof(Act->URL));
1947       }
1948       else
1949       {
1950         if((tmp2-URL+1) >= sizeof(Act->URL))
1951           printf("SkyUtils_SU_RetrieveLink Warning : URL replacement in SU_RetrieveLink is bigger than sizeof(URL). Results will be unpredictable\n");
1952         else
1953           SU_strcpy(Act->URL,URL,tmp2-URL+1); /* Copy the root part of URL */
1954         SU_strcat(Act->URL,tmp,sizeof(Act->URL));
1955       }
1956     }
1957     else
1958     {
1959       tmp2 = tmp;
1960       strncpy(Act->URL,URL,sizeof(Act->URL));
1961       /* If / at the end of URL, remove it */
1962       if(Act->URL[strlen(Act->URL)-1] == '/')
1963         Act->URL[strlen(Act->URL)-1] = 0;
1964       /* If end of URL if a file, remove it */
1965       rp = strrchr(Act->URL,'.');
1966       rs = strrchr(Act->URL,'/');
1967       if(rp > rs)
1968         rs[0] = 0;
1969       /* For each ../ remove it from URL */
1970       while(strncasecmp(tmp2,"../",3) == 0)
1971       {
1972         tmp2+=3;
1973         i = strlen(Act->URL) - 1;
1974         found = false;
1975         while(i >= 0)
1976         {
1977           if(Act->URL[i] == '/')
1978           {
1979             found = true;
1980             Act->URL[i] = 0;
1981             break;
1982           }
1983           i--;
1984         }
1985         if(!found)
1986         {
1987           free(tmp);
1988           free(Act);
1989           return NULL;
1990         }
1991       }
1992       /* If no / at the end of URL, add it */
1993       if(Act->URL[strlen(Act->URL)-1] != '/')
1994         SU_strcat(Act->URL,"/",sizeof(Act->URL));
1995       /* Cat URL and dest */
1996       SU_strcat(Act->URL,tmp2,sizeof(Act->URL));
1997     }
1998   }
1999   free(tmp);
2000   return Act;
2001 }
2002 
2003 /* Code added by Pierre Bacquet (pbacquet@delta.fr) */
SU_RetrieveFrame(const char URL[],const char Ans[],const char framename[])2004 SU_PHTTPActions SU_RetrieveFrame(const char URL[],const char Ans[],const char framename[])
2005 {
2006   char *p,*q,c,*tmp,*tmp2,*rp,*rs;
2007   SU_PHTTPActions Act;
2008   int i;
2009   bool found;
2010   char pattern[1024];
2011 
2012   SU_snprintf(pattern,sizeof(pattern),"FRAME NAME=%s", framename);
2013 
2014   p = SU_nocasestrstr((char *)Ans,pattern);
2015   if(p == NULL)
2016     return NULL;
2017   while(strncasecmp(p,"src",3) != 0)
2018     p++;
2019   p+=3;
2020   p = SU_TrimLeft(p); /* Remove spaces */
2021   p++; /* Zap '=' */
2022   p = SU_TrimLeft(p); /* Remove spaces */
2023   if(p[0] == '"')
2024   {
2025     c = '"';
2026     p++; /* Zap '"' */
2027   }
2028   else if(p[0] == '\'')
2029   {
2030     c = '\'';
2031     p++; /* Zap '\'' */
2032   }
2033   else
2034     c = ' ';
2035   q = strchr(p,c);
2036   tmp = (char *) malloc(q-p+1);
2037   SU_strcpy(tmp,p,q-p+1);
2038 
2039   Act = (SU_PHTTPActions) malloc(sizeof(SU_THTTPActions));
2040   memset(Act,0,sizeof(SU_THTTPActions));
2041   Act->Command = ACT_GET;
2042   /* URL in tmp, but may be relative */
2043   if(strncasecmp(tmp,"http",4) == 0) /* Absolute */
2044     strncpy(Act->URL,tmp,sizeof(Act->URL));
2045   else
2046   {
2047     if(tmp[0] == '/') /* Root of the host */
2048     {
2049 #ifdef __unix__
2050       tmp2 = strchr(URL+7,'/');
2051 #else /* !__unix__ */
2052       tmp2 = strchr((char *)URL+7,'/');
2053 #endif /* __unix__ */
2054       if(tmp2 == NULL) /* Already at the root of the site */
2055       {
2056         SU_strcpy(Act->URL,URL,sizeof(Act->URL));
2057         SU_strcat(Act->URL,tmp,sizeof(Act->URL));
2058       }
2059       else
2060       {
2061         if((tmp2-URL+1) >= sizeof(Act->URL))
2062           printf("SkyUtils_SU_RetrieveFrame Warning : URL replacement in SU_RetrieveFrame is bigger than sizeof(URL). Results will be unpredictable\n");
2063         else
2064           SU_strcpy(Act->URL,URL,tmp2-URL+1); /* Copy the root part of URL */
2065         SU_strcat(Act->URL,tmp,sizeof(Act->URL));
2066       }
2067     }
2068     else
2069     {
2070       tmp2 = tmp;
2071       strncpy(Act->URL,URL,sizeof(Act->URL));
2072       /* If / at the end of URL, remove it */
2073       if(Act->URL[strlen(Act->URL)-1] == '/')
2074         Act->URL[strlen(Act->URL)-1] = 0;
2075       /* If end of URL if a file, remove it */
2076       rp = strrchr(Act->URL,'.');
2077       rs = strrchr(Act->URL,'/');
2078       if(rp > rs)
2079         rs[0] = 0;
2080       /* For each ../ remove it from URL */
2081       while(strncasecmp(tmp2,"../",3) == 0)
2082       {
2083         tmp2+=3;
2084         i = strlen(Act->URL) - 1;
2085         found = false;
2086         while(i >= 0)
2087         {
2088           if(Act->URL[i] == '/')
2089           {
2090             found = true;
2091             Act->URL[i] = 0;
2092             break;
2093           }
2094           i--;
2095         }
2096         if(!found)
2097         {
2098           free(tmp);
2099           free(Act);
2100           return NULL;
2101         }
2102       }
2103       /* If no / at the end of URL, add it */
2104       if(Act->URL[strlen(Act->URL)-1] != '/')
2105         SU_strcat(Act->URL,"/",sizeof(Act->URL));
2106       /* Cat URL and dest */
2107       SU_strcat(Act->URL,tmp2,sizeof(Act->URL));
2108     }
2109   }
2110   free(tmp);
2111   return Act;
2112 }
2113 
2114 /* Retrieve document.forms[num] */
SU_RetrieveForm(const char Ans[],const int num)2115 SU_PForm SU_RetrieveForm(const char Ans[],const int num)
2116 {
2117   char *p,*ps,*pt,*q,*r,*saf,*parse,*tmp,c,buf[500];
2118   int i,len;
2119   SU_PInput In;
2120   SU_PForm Form;
2121   SU_PList Ptr;
2122   char toto[3],res;
2123   bool textarea = false;
2124 
2125   p = SU_nocasestrstr((char *)Ans,"<form");
2126   if(p == NULL)
2127     return NULL;
2128   for(i=0;i<num;i++)
2129   {
2130     p = SU_nocasestrstr(p,"/form");
2131     if(p == NULL)
2132       return NULL;
2133     p = SU_nocasestrstr(p,"<form");
2134     if(p == NULL)
2135       return NULL;
2136   }
2137   q = SU_nocasestrstr(p,"/form");
2138   if(q == NULL)
2139     return NULL;
2140   saf = (char *) malloc(q-p+1);
2141   toto[1] = '>';
2142   toto[2] = 0;
2143   SU_strcpy(saf,p,q-p+1);
2144   /* Got the full form in saf */
2145   parse = saf;
2146   Form = (SU_PForm) malloc(sizeof(SU_TForm));
2147   memset(Form,0,sizeof(SU_TForm));
2148   Ptr = NULL;
2149   p = SU_TrimLeft(parse+5);
2150   /* Now parse form tag */
2151   while(p[0] != '>')
2152   {
2153     if(strncasecmp(p,"method",6) == 0)
2154     {
2155       p = SU_TrimLeft(p+6);
2156       p++; /* Zap '=' */
2157       p = SU_TrimLeft(p);
2158       if(p[0] == '"')
2159       {
2160         c = '"';
2161         p++; /* Zap '"' */
2162       }
2163       else if(p[0] == '\'')
2164       {
2165         c = '\'';
2166         p++; /* Zap '\'' */
2167       }
2168       else
2169         c = ' ';
2170       toto[0] = c;
2171       q = SU_strchrl(p,toto,&res);
2172       if(q == NULL)
2173         break;
2174       tmp = (char *) malloc(q-p+1);
2175       SU_strcpy(tmp,p,q-p+1);
2176       Form->Method = tmp;
2177       p = q;
2178       if((c == '"') || (c == '\''))
2179         p++; /* Zap '"' */
2180     }
2181     else if(strncasecmp(p,"name",4) == 0)
2182     {
2183       p = SU_TrimLeft(p+4);
2184       p++; /* Zap '=' */
2185       p = SU_TrimLeft(p);
2186       if(p[0] == '"')
2187       {
2188         c = '"';
2189         p++; /* Zap '"' */
2190       }
2191       else if(p[0] == '\'')
2192       {
2193         c = '\'';
2194         p++; /* Zap '\'' */
2195       }
2196       else
2197         c = ' ';
2198       toto[0] = c;
2199       q = SU_strchrl(p,toto,&res);
2200       if(q == NULL)
2201         break;
2202       tmp = (char *) malloc(q-p+1);
2203       SU_strcpy(tmp,p,q-p+1);
2204       Form->Name = tmp;
2205       p = q;
2206       if((c == '"') || (c == '\''))
2207         p++; /* Zap '"' */
2208     }
2209     else if(strncasecmp(p,"action",6) == 0)
2210     {
2211       p = SU_TrimLeft(p+6);
2212       p++; /* Zap '=' */
2213       p = SU_TrimLeft(p);
2214       if(p[0] == '"')
2215       {
2216         c = '"';
2217         p++; /* Zap '"' */
2218       }
2219       else if(p[0] == '\'')
2220       {
2221         c = '\'';
2222         p++; /* Zap '\'' */
2223       }
2224       else
2225         c = ' ';
2226       toto[0] = c;
2227       q = SU_strchrl(p,toto,&res);
2228       if(q == NULL)
2229         break;
2230       tmp = (char *) malloc(q-p+1);
2231       SU_strcpy(tmp,p,q-p+1);
2232       Form->Action = tmp;
2233       p = q;
2234       if((c == '"') || (c == '\''))
2235         p++; /* Zap '"' */
2236     }
2237     else
2238     {
2239       q = strchr(p,' ');
2240       r = strchr(p,'>');
2241       if((q == NULL) || (r == NULL))
2242         break;
2243       if(r < q)
2244         break;
2245       else
2246         p = q;
2247     }
2248     p = SU_TrimLeft(p);
2249   }
2250 #ifdef __unix__
2251   if(SU_DebugLevel >= 3)
2252     printf("SkyUtils_SU_RetrieveForm : Info for forms[%d] : Method=%s - Name=%s - Action=%s\n",num,(Form->Method == NULL)?"(null)":Form->Method,(Form->Name == NULL)?"(null)":Form->Name,(Form->Action == NULL)?"(null)":Form->Action);
2253 #endif /* __unix__ */
2254 
2255   p = SU_nocasestrstr(parse,"<input");
2256   ps = SU_nocasestrstr(parse,"<select");
2257   pt = SU_nocasestrstr(parse,"<textarea");
2258   if((pt != NULL) && ((pt<p) || (p == NULL)) && ((pt<ps) || (ps == NULL))) /* Textarea found first */
2259   {
2260     p = pt+3; /* +3 to adjust from sizeof("textarea") to sizeof("input") */
2261     textarea = true;
2262   }
2263   if(((p>ps) || (p == NULL)) && (ps != NULL))
2264     p = ps+1; /* +1 to adjust from sizeof("select") to sizeof("input") */
2265   while(p != NULL)
2266   {
2267     In = (SU_PInput) malloc(sizeof(SU_TInput));
2268     memset(In,0,sizeof(SU_TInput));
2269     p = SU_TrimLeft(p+6);
2270     /* Now parse input tags */
2271     r = strchr(p,'>');
2272     toto[0] = '=';
2273     toto[1] = ' ';
2274     while(p[0] != '>')
2275     {
2276       q = SU_strchrl(p,toto,&res);
2277       if(q == NULL)
2278         break;
2279       if(q > r) /* Attention ici, si on veux plus tard recup les non Name=Value */
2280         break;
2281       len = q-p;
2282       if(len >= sizeof(buf))
2283         len = sizeof(buf) - 1;
2284       memcpy(buf,p,len);
2285       buf[len] = 0;
2286       /* buf contient la partie Name de Name=Value */
2287       p = SU_TrimLeft(q + 1);
2288       if(res == ' ')
2289       {
2290         if(p[0] != '=')
2291           continue;
2292         else
2293           p = SU_TrimLeft(p+1);
2294       }
2295       while((len > 0) && (buf[len-1] == ' '))
2296       {
2297         len--;
2298         buf[len] = 0; /* Remove trailing spaces */
2299       }
2300       if((strchr(buf,' ') == NULL) && (res != '>')) /* Si on a bien a faire a un Name=Value */
2301       {
2302         if(p[0] == '"') /* Si la partie Value est une chaine */
2303         {
2304           c = '"';
2305           p++;
2306         }
2307         else if(p[0] == '\'') /* Si la partie Value est une chaine */
2308         {
2309           c = '\'';
2310           p++;
2311         }
2312         else
2313           c = ' ';
2314         q = strchr(p,c);
2315         if(q == NULL)
2316           q = r;
2317         if(q > r)
2318         {
2319           if((c == '"') || (c == '\'')) /* '>' must be inside the string */
2320             r = strchr(r+1,'>');
2321           else
2322             q = r;
2323         }
2324         len = q-p;
2325         if(len <= 0)
2326           continue;
2327         tmp = (char *) malloc(len+1);
2328         memcpy(tmp,p,len);
2329         tmp[len] = 0;
2330         p = q;
2331         if((c == '"') || (c == '\'')) /* Si la partie Value est une chaine */
2332           p++;
2333         if(SU_nocasestrstr(buf,"type") == buf)
2334           In->Type = tmp;
2335         else if(SU_nocasestrstr(buf,"name") == buf)
2336           In->Name = tmp;
2337         else if(SU_nocasestrstr(buf,"value") == buf)
2338           In->Value = tmp;
2339         else
2340           free(tmp);
2341       }
2342       p = SU_TrimLeft(p);
2343     }
2344     if(textarea)
2345     {
2346       if(In->Type == NULL)
2347         In->Type = SU_strdup("textarea");
2348       q = SU_nocasestrstr(p+1,"</textarea>");
2349       if(q == NULL)
2350       {
2351         if(In->Name != NULL)
2352         {
2353           free(In->Name);
2354           In->Name = NULL;
2355         }
2356       }
2357       else
2358       {
2359         if(In->Value != NULL)
2360           free(In->Value);
2361         In->Value = (char *) malloc(q-p);
2362         SU_strcpy(In->Value,r+1,q-p);
2363         p = q+2;
2364       }
2365     }
2366     if(In->Type == NULL)
2367       In->Type = SU_strdup("text");
2368     if(In->Name != NULL)
2369     {
2370 #ifdef __unix__
2371       if(SU_DebugLevel >= 3)
2372         printf("SkyUtils_SU_RetrieveForm : Adding INPUT to form[%d] : Type=%s - Name=%s - Value=%s\n",num,(In->Type == NULL)?"(null)":In->Type,(In->Name == NULL)?"(null)":In->Name,(In->Value == NULL)?"(null)":In->Value);
2373 #endif /* __unix__ */
2374       Ptr = SU_AddElementHead(Ptr,In);
2375     }
2376     else
2377       SU_FreeInput(In);
2378 
2379     textarea = false;
2380     parse = p+1; /* Set parse to the end of INPUT (after the '>') */
2381     p = SU_nocasestrstr(parse,"<input");
2382     ps = SU_nocasestrstr(parse,"<select");
2383     pt = SU_nocasestrstr(parse,"<textarea");
2384     if((pt != NULL) && ((pt<p) || (p == NULL)) && ((pt<ps) || (ps == NULL))) /* Textarea found first */
2385     {
2386       p = pt+3; /* +3 to adjust from sizeof("textarea") to sizeof("input") */
2387       textarea = true;
2388     }
2389     if(((p>ps) || (p == NULL)) && (ps != NULL))
2390       p = ps+1; /* +1 to adjust from sizeof("select") to sizeof("input") */
2391   }
2392   free(saf);
2393   Form->Inputs = Ptr;
2394   return Form;
2395 }
2396 
SU_FreeForm(SU_PForm Form)2397 void SU_FreeForm(SU_PForm Form)
2398 {
2399   SU_PList Ptr;
2400 
2401   Ptr = Form->Inputs;
2402   while(Ptr != NULL)
2403   {
2404     SU_FreeInput((SU_PInput)Ptr->Data);
2405     Ptr = Ptr->Next;
2406   }
2407   SU_FreeList(Form->Inputs);
2408   if(Form->Method != NULL)
2409     free(Form->Method);
2410   if(Form->Name != NULL)
2411     free(Form->Name);
2412   if(Form->Action != NULL)
2413     free(Form->Action);
2414 }
2415 
SU_AddLocationToUrl(const char * URL,const char * Host,const char * Location,bool ssl_mode)2416 char *SU_AddLocationToUrl(const char *URL,const char *Host,const char *Location,bool ssl_mode)
2417 {
2418   char *ptr = NULL;
2419   int len,i,pos = 0;
2420 
2421   if(strncasecmp(Location,"http://",7) != 0) /* Relative path */
2422   {
2423     len = strlen(Host)+strlen(URL)+strlen(Location)+strlen("https://")+1;
2424     ptr = (char *) malloc(len);
2425     if(Location[0] == '/')
2426     { /* Relative path, but absolute on the site */
2427       SU_snprintf(ptr,len,"http%s://%s",ssl_mode?"s":"",Host);
2428       /* Remove trailing / if exists */
2429       if(ptr[strlen(ptr)-1] == '/' )
2430         ptr[strlen(ptr)-1] = 0;
2431     }
2432     else
2433     { /* Relative path from current directory */
2434       if(strncasecmp(URL,"http://",7) == 0) /* If using proxy, or if URL is already absolute */
2435         SU_strcpy(ptr,URL,len);
2436       else if(strncasecmp(URL,"https://",8) == 0) /* If using proxy, or if URL is already absolute - SSL */
2437         SU_strcpy(ptr,URL,len);
2438       else
2439         SU_snprintf(ptr,len,"http%s://%s%s",ssl_mode?"s":"",Host,URL);
2440 
2441       if(strcmp(ptr+strlen("http://")+(ssl_mode?1:0),Host) == 0) /* If requested the root of the site */
2442         SU_strcat(ptr,"/",len);
2443       else
2444       {
2445         i = strlen(ptr) - 1;
2446         while(i>=0)
2447         {
2448           if(ptr[i] == '/')
2449           {
2450             ptr[i+1] = 0;
2451             break;
2452           }
2453           i--;
2454         }
2455       }
2456       /* Here, ptr have a trailing '/' */
2457       /* Check for '../' in Location */
2458       while(strncmp(Location+pos,"../",3) == 0)
2459       {
2460         i = strlen(ptr) - 1 - 1; /* Start from before the trailing '/' */
2461         while(i>=0)
2462         {
2463           if(ptr[i] == '/')
2464           {
2465             ptr[i+1] = 0; /* Go back a directory level */
2466             break;
2467           }
2468           i--;
2469         }
2470         pos += 3;
2471       }
2472     }
2473     SU_strcat(ptr,Location+pos,len);
2474   }
2475   else
2476     ptr = SU_strdup(Location);
2477   return ptr;
2478 }
2479 
2480 /* Skips white spaces before the string, then extracts it */
SU_GetStringFromHtml(const char Ans[],const char TextBefore[])2481 char *SU_GetStringFromHtml(const char Ans[],const char TextBefore[])
2482 {
2483   char *p,*q,*tmp;
2484   char c;
2485   int len;
2486 
2487   p = strstr(Ans,TextBefore);
2488   if(p == NULL)
2489     return NULL;
2490   p += strlen(TextBefore);
2491   while(p[0] == ' ') /* Remove spaces */
2492     p++;
2493 
2494   if(p[0] == '"') /* If we have a string */
2495   {
2496     c = '"';
2497     p++;
2498   }
2499   else if(p[0] == '\'') /* If we have a string */
2500   {
2501     c = '\'';
2502     p++;
2503   }
2504   else
2505     c = ' ';
2506   q = strchr(p,c);
2507   if(q == NULL)
2508     return NULL;
2509   len = q-p;
2510   tmp = (char *) malloc(len+1);
2511   memcpy(tmp,p,len);
2512   tmp[len] = 0;
2513   return tmp;
2514 }
2515 
SU_SetUserAgent(const char UA[])2516 void SU_SetUserAgent(const char UA[])
2517 {
2518   if(SW_UserAgent != NULL)
2519     free(SW_UserAgent);
2520   if(UA == NULL)
2521     SW_UserAgent = NULL;
2522   else
2523     SW_UserAgent = SU_strdup(UA);
2524 }
2525