2 Copyright (C) 2006 by Jonas Kramer
3 Published under the terms of the GNU General Public License (GPL).
18 #include <sys/socket.h>
32 #define USERAGENT "Shell.FM/" PACKAGE_VERSION
36 char ** fetch(const char * url
, FILE ** pHandle
, const char * post
, const char * type
) {
37 char ** resp
= NULL
, * host
, * file
, * port
, * status
= NULL
, * line
= NULL
;
40 unsigned short nport
= 80, chunked
= 0;
41 unsigned nline
= 0, nstatus
= 0, size
= 0;
46 const char * headFormat
=
49 "User-Agent: " USERAGENT
"\r\n"
50 "Cookie: Session=%s\r\n"
51 "Connection: close\r\n";
53 const char * proxiedheadFormat
=
54 "%s http://%s/%s HTTP/1.1\r\n"
56 "User-Agent: " USERAGENT
"\r\n"
57 "Cookie: Session=%s\r\n";
59 if(!batch
&& !enabled(QUIET
))
60 fputs("...\r", stderr
);
62 useproxy
= haskey(& rc
, "proxy");
64 type
= "application/x-www-form-urlencoded";
69 strncpy(urlcpy
, url
, sizeof(urlcpy
) - 1);
71 host
= & urlcpy
[strncmp(urlcpy
, "http://", 7) ? 0 : 7];
75 char proxcpy
[512 + 1];
76 memset(proxcpy
, (char) 0, sizeof(proxcpy
));
77 strncpy(proxcpy
, value(& rc
, "proxy"), sizeof(proxcpy
) - 1);
78 connhost
= & proxcpy
[strncmp(proxcpy
, "http://", 7) ? 0 : 7];
81 port
= strchr(connhost
, 0x3A);
82 file
= strchr(host
, 0x2F);
87 if(port
&& port
< file
) {
91 nport
= (unsigned short) strtol(port
, & ptr
, 10);
96 if(!(fd
= ropen(connhost
, nport
)))
100 fprintf(fd
, proxiedheadFormat
, post
? "POST" : "GET", host
,
101 file
? file
: "", host
, value(& data
, "session"));
103 fprintf(fd
, headFormat
, post
? "POST" : "GET", file
? file
: "", host
, value(& data
, "session"));
106 fprintf(fd
, "Content-Type: %s\r\n", type
);
107 fprintf(fd
, "Content-Length: %ld\r\n\r\n%s\r\n", (long) strlen(post
), post
);
113 if(getln(& status
, & size
, fd
) >= 12)
114 validHead
= sscanf(status
, "HTTP/%*f %u", & nstatus
);
116 if(nstatus
!= 200 && nstatus
!= 301 && nstatus
!= 302) {
120 fprintf(stderr
, "Invalid HTTP: %s from: %s\n", status
, url
);
122 fprintf(stderr
, "HTTP Response: %s", status
);
126 freeln(& status
, & size
);
131 freeln(& status
, & size
);
134 if(getln(& line
, & size
, fd
) < 3)
137 if(!strncasecmp(line
, "Transfer-Encoding: chunked", 26))
140 if((nstatus
== 301 || nstatus
== 302) && !strncasecmp(line
, "Location: ", 10)) {
141 char newurl
[512 + 1];
142 memset(newurl
, 0, sizeof(newurl
));
143 sscanf(line
, "Location: %512[^\r\n]", newurl
);
146 return fetch(newurl
, pHandle
, post
, type
);
150 freeln(& line
, & size
);
154 if(!batch
&& !enabled(QUIET
))
155 fputs("\r \r", stderr
);
161 puts("DEBUG: Chunked!");
167 if(getln(& line
, & size
, fd
)) {
168 char * ptr
= strchr(line
, 10);
173 resp
= realloc(resp
, (nline
+ 2) * sizeof(char *));
174 assert(resp
!= NULL
);
177 resp
[++nline
] = NULL
;
184 if(!batch
&& !enabled(QUIET
))
185 fputs("\r \r", stderr
);
189 unsigned encode(const char * orig
, char ** encoded
) {
190 register unsigned i
= 0, x
= 0;
192 * encoded
= calloc((strlen(orig
) * 3) + 1, sizeof(char));
194 assert(* encoded
!= NULL
);
196 while(i
< strlen(orig
)) {
197 if(isalnum(orig
[i
]) || orig
[i
] == ' ')
198 (* encoded
)[x
++] = orig
[i
];
202 strlen(orig
) * 3 - strlen(* encoded
) + 1,
211 for(i
= 0; i
< x
; ++i
)
212 if((* encoded
)[i
] == ' ')
213 (* encoded
)[i
] = '+';
218 unsigned decode(const char * orig
, char ** decoded
) {
219 register unsigned i
= 0, x
= 0;
220 const unsigned len
= strlen(orig
);
222 * decoded
= calloc(len
+ 1, sizeof(char));
224 assert(decoded
!= NULL
);
228 (* decoded
)[x
] = orig
[i
];
231 if(sscanf(orig
+ i
, "%%%02x", & hex
) != 1)
232 (* decoded
)[x
] = orig
[i
];
234 (* decoded
)[x
] = (char) hex
;
243 * decoded
= realloc(* decoded
, (x
+ 1) * sizeof(char));
245 assert(decoded
!= NULL
);
247 for(i
= 0; i
< x
; ++i
)
248 if((* decoded
)[i
] == '+')
249 (* decoded
)[i
] = ' ';
254 void freeln(char ** line
, unsigned * size
) {
265 void unhtml(char * html
) {
267 const char * codes
[] = {
276 for(i
= 0; i
< (sizeof(codes
) / sizeof(char *)); i
+= 2) {
277 unsigned length
= strlen(codes
[i
]);
279 while((ptr
= strcasestr(html
, codes
[i
])) != NULL
) {
280 * ptr
= codes
[i
+ 1][0];
281 memmove(ptr
+ 1, ptr
+ length
, strlen(ptr
+ length
));
282 * (ptr
+ strlen(ptr
) - length
+ 1) = 0;
288 const char * makeurl(const char * fmt
, ...) {
289 static char url
[512];
290 const char * src
= fmt
;
297 memset(url
, 0, sizeof(url
));
299 while(* src
&& pos
< sizeof(url
) - 1) {
301 url
[pos
++] = * (src
++);
302 else if(* (src
+ 1)) {
309 encode(va_arg(argv
, char *), & ptr
);
310 pos
+= snprintf(& url
[pos
], sizeof(url
) - pos
, "%s", ptr
);
316 pos
+= sprintf(& url
[pos
], "%d", va_arg(argv
, int));
320 pos
+= sprintf(& url
[pos
], "%u", va_arg(argv
, unsigned));
330 char ** cache(const char * url
, const char * name
, int refresh
) {
331 time_t expiry
= 60 * 60 * 24;
334 if(haskey(& rc
, "expiry"))
335 expiry
= atoi(value(& rc
, "expiry"));
337 memset(path
, (char) 0, sizeof(path
));
338 strncpy(path
, rcpath("cache"), sizeof(path
));
339 if(access(path
, W_OK
| X_OK
))
342 snprintf(path
, sizeof(path
), "%s/%s", rcpath("cache"), name
);
345 if(access(path
, R_OK
| W_OK
))
348 time_t now
= time(NULL
);
351 stat(path
, & status
);
352 if(status
.st_mtime
< now
- expiry
)
360 char ** data
= fetch(url
, NULL
, NULL
, NULL
);
362 FILE * fd
= fopen(path
, "w");
366 fprintf(fd
, "%s\n", data
[line
++]);
369 fputs("Couldn't write cache.\n", stderr
);