Merge branch 'master' of git://cadel.mutabah.net/acess2
[tpg/acess2.git] / Usermode / Applications / wget / main.c
1 /*
2  * Acess2 Command-line HTTP Client (wget)
3  * - By John Hodge
4  *
5  * main.c
6  */
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <net.h>
10 #include <uri.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 enum eProcols
15 {
16         PROTO_NONE,
17         PROTO_HTTP,
18         PROTO_HTTPS
19 };
20
21 const char      **gasURLs;
22  int    giNumURLs;
23
24 int _ParseHeaderLine(char *Line, int State, size_t *Size);
25
26 int main(int argc, char *argv[])
27 {
28          int    proto, rv;
29         gasURLs = malloc( (argc - 1) * sizeof(*gasURLs) );
30         
31         // Parse arguments
32         for(int i = 1; i < argc; i ++ )
33         {
34                 char    *arg = argv[i];
35                 if( arg[0] != '-' ) {
36                         // URL
37                         gasURLs[giNumURLs++] = arg;
38                 }
39                 else if( arg[1] != '-') {
40                         // Short arg
41                 }
42                 else {
43                         // Long arg
44                 }
45         }
46
47         // Do the download
48         for( int i = 0; i < giNumURLs; i ++ )
49         {
50                 char    *outfile;
51                 tURI    *uri = URI_Parse(gasURLs[i]);
52                 struct addrinfo *addrinfo;
53
54                 if( !uri ) {
55                         fprintf(stderr, "'%s' is not a valid URL", gasURLs[i]);
56                         continue ;
57                 }               
58
59                 printf("Proto: %s, Host: %s, Path: %s\n", uri->Proto, uri->Host, uri->Path);
60
61                 if( uri->Path[0] == '\0' )
62                         outfile = "index.html";
63                 else
64                         outfile = strrchr(uri->Path, '/') + 1;
65                 if( !outfile )
66                         outfile = uri->Path;
67
68                 if( strcmp(uri->Proto, "http") == 0 ) {
69                         proto = PROTO_HTTP;
70                 }
71                 else if( strcmp(uri->Proto, "https") == 0 ) {
72                         proto = PROTO_HTTPS;
73                 }
74                 else {
75                         // Unknown
76                         fprintf(stderr, "Unknown protocol '%s'\n", uri->Proto);
77                         free(uri);
78                         continue ;
79                 }
80
81                 rv = getaddrinfo(uri->Host, NULL, NULL, &addrinfo);
82                 if( rv != 0 ) {
83                         fprintf(stderr, "Unable to resolve %s: %s\n", uri->Host, gai_strerror(rv));
84                         continue ;
85                 }
86
87                 for( struct addrinfo *addr = addrinfo; addr != NULL; addr = addr->ai_next )
88                 {
89                          int    bSkipLine = 0;
90                         // TODO: Convert to POSIX/BSD
91                          int    sock = Net_OpenSocket(addr->ai_family, addr->ai_addr, "tcpc");
92                         if( sock == -1 )        continue ;
93
94                         writef(sock, "GET /%s HTTP/1.1\r\n", uri->Path);
95                         writef(sock, "Host: %s\r\n", uri->Host);
96 //                      writef(sock, "Accept-Encodings: */*\r\n");
97                         writef(sock, "User-Agent: awget/0.1 (Acess2)\r\n");
98                         writef(sock, "\r\n");
99                         
100                         // Parse headers
101                         char    inbuf[BUFSIZ+1];
102                         size_t  offset = 0;
103                          int    state = 0;
104                         size_t  bytes_seen = 0;
105                         size_t  bytes_wanted = -1;      // invalid
106                         
107                         while( state == 0 || state == 1 )
108                         {
109                                 if( offset == sizeof(inbuf) ) {
110                                         bSkipLine = 1;
111                                         offset = 0;
112                                 }
113                                 // TODO: Handle -1 return
114                                 offset += read(sock, inbuf + offset, sizeof(inbuf) - offset);
115                                 inbuf[offset] = 0;
116                                 
117                                 char    *eol = strchr(inbuf, '\n');
118                                 // No end of line char? read some more
119                                 if( eol == NULL )       continue ;
120                                 // Update write offset  
121                                 offset = eol + 1 - inbuf;
122                                 
123                                 // Clear EOL bytes
124                                 *eol = '\0';
125                                 // Nuke the \r
126                                 if( eol - 1 >= inbuf )
127                                         eol[-1] = '\0';
128                                         
129                                 
130                                 if( !bSkipLine )
131                                         state = _ParseHeaderLine(inbuf, state, &bytes_wanted);
132                                 
133                                 memmove( inbuf, inbuf + offset, sizeof(inbuf) - offset );
134                                 offset = 0;
135                         }
136
137                         if( state == 2 )
138                         {
139                                  int    outfd = open(outfile, O_WR|O_CREAT, 0666);
140                                 if( outfd != -1 )
141                                 {
142                                         while( bytes_seen < bytes_wanted )
143                                         {
144                                                 // Abuses offset as read byte count
145                                                 offset = read(sock, inbuf, sizeof(inbuf));
146                                                 write(outfd, inbuf, offset);
147                                                 bytes_seen += offset;
148                                         }
149                                         close(outfd);
150                                 }
151                         }
152                         
153                         close(sock);
154                         break ;
155                 }
156
157                 free(uri);
158         }
159 }
160
161 int _ParseHeaderLine(char *Line, int State, size_t *Size)
162 {
163         // First line (Status and version)
164         if( State == 0 )
165         {
166                 // HACK - assumes HTTP/1.1 (well, 9 chars before status)
167                 switch( atoi(Line + 9) )
168                 {
169                 case 200:
170                         // All good!
171                         return 1;
172                 default:
173                         fprintf(stderr, "Unknown HTTP status - %s\n", Line + 9);
174                         return -1;
175                 }
176         }
177         // Last line?
178         else if( Line[0] == '\0' )
179         {
180                 return 2;
181         }
182         // Body lines
183         else
184         {
185                 char    *colon = strchr(Line, ':');
186                 if(colon == NULL)       return 1;
187
188                 *colon = '\0';
189                 if( strcmp(Line, "Content-Length") == 0 ) {
190                         *Size = atoi(colon + 1);
191                 }
192                 else {
193                         printf("Ignorning header '%s' = '%s'\n", Line, colon+1);
194                 }
195
196                 return 1;
197         }
198 }
199

UCC git Repository :: git.ucc.asn.au