apportate/src/main.c

217 lines
5.3 KiB
C
Raw Normal View History

2022-11-24 08:18:05 +00:00
#include "headers.h"
enum
{
/* display a status bar */
/* currently not implemented */
2022-11-24 08:18:05 +00:00
B,
/* put the file somewhere other than the current directory */
O,
/* silence all output -- the default */
/* note that if -q is passed explicitly, it will irrevocably override -v and -b */
Q,
/* increase the verbosity level. higher levels imply you want the content lower levels would provide */
/* all verbose output
is sent to stderr for ease of capture */
2022-11-24 08:18:05 +00:00
/* 0: no informational, statistical or debug output */
/* 1: informational output (Sending request FOO to host BAR, Received response header BAZ, etc) */
/* 2: statistical. informational+size of header and body in bytes, round-trip time, etc */
/* 3+: debug. statistical+all internal state changes */
/* currently we only implement 1 */
2022-11-24 08:18:05 +00:00
V
};
char param[4] = {0};
/* below is to accompany param[O] */
char *outpath;
2022-11-24 08:18:05 +00:00
int main(int argc, char **argv)
{
int i, translen, gotheader;
int sockd;
char *recvbuf;
char *sendbufp, *offsetp, *errstr;
FILE *filed;
struct tls *tlsc;
uri uristruct;
i = translen = sockd = 0;
sendbufp = offsetp = 0;
if( (recvbuf = malloc(BUFSIZ+1)) == NULL)
{
errstr = "failed to init";
goto err;
}
filed = 0;
tlsc = NULL;
for(i = 0; (i = getopt(argc, argv, "bo:qv")) != -1; i = 0)
{
switch(i)
{
case 'b':
param[B] = 1;
break;
case 'o':
param[O] = 1;
outpath = optarg;
break;
case 'q':
param[Q] = 1;
param[B] = 0;
param[V] = 0;
break;
case 'v':
/* we handle v differently because we want to support different levels of verbosity */
if(!param[Q])
{
param[V]++;
}
break;
default:
errstr = "[-vb] [-q] [-o <file>] uri";
goto usage;
}
}
/* we should probably modify uri_parse to return a zero value on failure... */
if(uri_parse(argv[optind], &uristruct))
{
errstr = "[-q|[-v -b]] [-o <file>] uri";
goto usage;
}
/* if outpath isn't set because we haven't received a -o param, */
/* then we should set the outpath to the final component of the */
/* URI. */
/* If we can't do that, we should just set it to 'default'. */
if(NULL == outpath && !strlen((outpath = (1 + strrchr(uristruct.path, '/')))))
{
outpath = "default";
}
/* generate our request */
if( !(sendbufp = reqgen(&uristruct)))
{
errstr = "Unknown protocol.";
goto err;
}
if(param[V])
{
fprintf(stderr, "request: %s\n", sendbufp);
}
/* having a routine or a global variable to track whether we need TLS would be */
/* nice to add in the future */
/* could probably store whether tls is necessary in a char within uristruct... */
/* Note: at the moment, if the TLS pointer passed is non-NULL, */
/* dial's return code can only be treated as an indicator of success. */
if(!strcmp("https", uristruct.proto))
{
sockd = dial(uristruct.fqdn, uristruct.proto, &tlsc);
}
else
{
sockd = dial(uristruct.fqdn, uristruct.proto, NULL);
}
2022-11-24 08:18:05 +00:00
if(!sockd)
{
errstr = "Couldn't connect to the host using the specified protocol.";
goto err;
}
if(tlsc)
{
translen = tls_write(tlsc, sendbufp, strlen(sendbufp));
}
else
{
translen = send(sockd, sendbufp, strlen(sendbufp), 0);
}
if(translen)
{
if(param[V])
{
printf("send: %d bytes\n", translen);
}
}
else
{
errstr = "Couldn't transmit data.";
goto err;
}
/* now for a slightly more complex version of the same routine: until we've encountered the */
/* delimiter, "\r\n\r\n", don't write to disk. Once we have, calculate the size of the body, */
/* then write that number of bytes to disk starting from the offset. Then, write everything */
/* until end of transmission. */
for(gotheader = 0, offsetp = NULL, translen = 1; translen > 0; memset(recvbuf, 0, BUFSIZ+1))
{
if( NULL == tlsc)
{
printf("recv: %d bytes\n", translen = recv(sockd, recvbuf, BUFSIZ, 0));
}
else
{
printf("recv: %d bytes\n", translen = tls_read(tlsc, recvbuf, BUFSIZ));
}
/* if we haven't gotten the header and our delimiter isn't in the */
/* received string, we're getting a multipart header and need to */
/* skip over it. */
/* right now we assume HTTP/S -- this is undesirable... */
if( strcmp("gopher", uristruct.proto) && !gotheader)
{
if( NULL == (offsetp = strstr(recvbuf, "\r\n\r\n")))
{
printf("continuing...\n");
continue;
}
else
{
gotheader = 1;
offsetp += 4;
printf("got the header\n");
}
}
if( !filed && !(filed = fopen(outpath, "w")))
{
errstr = "couldn't open file";
goto err;
}
fwrite(offsetp, sizeof(char), (translen - (offsetp - recvbuf)), filed);
offsetp = recvbuf;
}
free(recvbuf);
close(sockd);
fclose(filed);
exit(EXIT_SUCCESS);
err:
fprintf(stderr, "%s: %s\n", argv[0], errstr);
exit(EXIT_FAILURE);
usage:
fprintf(stderr, "usage: %s: %s\n", argv[0], errstr);
exit(EXIT_FAILURE);
}