X-Git-Url: http://git.cascardo.eti.br/?p=cascardo%2Flibreceita.git;a=blobdiff_plain;f=rnetclient.c;h=2b98cc409adf915dfde4212d3128e46d2c9a6511;hp=a2aaf10068b5f30268ba8c039da1a4cf2afb29d2;hb=958b40f350e535895301519f24c3453190db95df;hpb=2aff1868c6bab9262973134267a4be09a1351780 diff --git a/rnetclient.c b/rnetclient.c index a2aaf10..2b98cc4 100644 --- a/rnetclient.c +++ b/rnetclient.c @@ -49,7 +49,7 @@ static void session_new(gnutls_session_t *session) gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, cred); } -static int deflateRecord(char *buffer, size_t len, char **out, size_t *olen) +static int deflateRecord(char *buffer, size_t len, char **out, size_t *olen, int header) { z_stream zstrm; int r; @@ -74,13 +74,13 @@ static int deflateRecord(char *buffer, size_t len, char **out, size_t *olen) free(*out); return -1; } - *olen = zstrm.avail_out + 6; + *olen = zstrm.total_out + 6; (*out)[0] = 0x1; - (*out)[1] = (zstrm.avail_out >> 8); - (*out)[2] = (zstrm.avail_out & 0xff); + (*out)[1] = (zstrm.total_out >> 8); + (*out)[2] = (zstrm.total_out & 0xff); (*out)[3] = (len >> 8); (*out)[4] = (len & 0xff); - (*out)[5] = 0x1; + (*out)[5] = header ? 0x01 : 0x0; deflateEnd(&zstrm); return 0; } @@ -174,11 +174,11 @@ static void usage(void) exit(1); } -static int rnet_send(gnutls_session_t session, char *buffer, size_t len) +static int rnet_send(gnutls_session_t session, char *buffer, size_t len, int header) { char *out; size_t olen; - deflateRecord(buffer, len, &out, &olen); + deflateRecord(buffer, len, &out, &olen, header); gnutls_record_send(session, out, olen); free(out); return 0; @@ -194,20 +194,92 @@ static int rnet_recv(gnutls_session_t session, struct rnet_message **message) rnet_message_expand(message, 6); buffer = (*message)->buffer; r = gnutls_record_recv(session, buffer, 6); - len = (buffer[1] << 8 | buffer[2]); - rnet_message_expand(message, len); - buffer = (*message)->buffer + 6; - r = gnutls_record_recv(session, buffer, len); - inflateRecord(buffer - 6, len + 6, &out, &olen); - rnet_message_del(*message); - *message = NULL; - rnet_message_expand(message, olen); - memcpy((*message)->buffer, out, olen); - (*message)->len = olen; - free(out); + if (buffer[0] == 0x01) { + len = (buffer[1] << 8 | buffer[2]); + rnet_message_expand(message, len); + buffer = (*message)->buffer + 6; + r = gnutls_record_recv(session, buffer, len); + inflateRecord(buffer - 6, len + 6, &out, &olen); + rnet_message_del(*message); + *message = NULL; + rnet_message_expand(message, olen); + memcpy((*message)->buffer, out, olen); + (*message)->len = olen; + free(out); + } else { + len = (buffer[1] << 8 | buffer[2]); + rnet_message_expand(message, len - 1); + buffer = (*message)->buffer + 6; + r = gnutls_record_recv(session, buffer, len - 1); + (*message)->len = len + 4; + rnet_message_strip(*message, 4); + } return 0; } +static void save_rec_file(char *cpf, char *buffer, int len) +{ + int fd; + char *filename; + char *home, *tmpdir; + mode_t mask; + size_t fnlen; + int r; + home = getenv("HOME"); + if (!home) { + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + home = tmpdir; + } + fnlen = strlen(home) + strlen(cpf) + 13; + filename = malloc(fnlen); + snprintf(filename, fnlen, "%s/%s.REC.XXXXXX", home, cpf); + mask = umask(0177); + fd = mkstemp(filename); + if (fd < 0) { + fprintf(stderr, "Could not create receipt file: %s\n", + strerror(errno)); + goto out; + } + r = write(fd, buffer, len); + if (r != len) { + fprintf(stderr, "Could not write to receipt file%s%s\n", + r < 0 ? ": " : ".", + r < 0 ? strerror(errno) : ""); + goto out; + } + fprintf(stderr, "Wrote the receipt to %s.\n", filename); +out: + close(fd); + free(filename); + umask(mask); +} + +static void handle_response_text_and_file(char *cpf, struct rnet_message *message) +{ + char *value; + int vlen; + if (!rnet_message_parse(message, "texto", &value, &vlen)) + fprintf(stderr, "%.*s\n", vlen, value); + if (!rnet_message_parse(message, "arquivo", &value, &vlen)) + save_rec_file(cpf, value, vlen); +} + +static void handle_response_already_found(char *cpf, struct rnet_message *message) +{ + handle_response_text_and_file(cpf, message); +} + +static void handle_response_error(struct rnet_message *message) +{ + char *value; + int vlen; + if (!rnet_message_parse(message, "texto", &value, &vlen)) + fprintf(stderr, "%.*s\n", vlen, value); + fprintf(stderr, "Error transmiting DEC file.\n"); +} + int main(int argc, char **argv) { int c; @@ -215,6 +287,8 @@ int main(int argc, char **argv) struct rnet_decfile *decfile; struct rnet_message *message = NULL; gnutls_session_t session; + int finish = 0; + char *cpf; if (argc < 2) { usage(); @@ -226,6 +300,8 @@ int main(int argc, char **argv) exit(1); } + cpf = rnet_decfile_get_header_field(decfile, "cpf"); + gnutls_global_init(); session_new(&session); @@ -245,14 +321,60 @@ int main(int argc, char **argv) gnutls_strerror(r)); rnet_encode(decfile, &message); - rnet_send(session, message->buffer, message->len); + rnet_send(session, message->buffer, message->len, 1); rnet_message_del(message); message = NULL; - rnet_recv(session, &message); - write(1, message->buffer, message->len); + r = rnet_recv(session, &message); + if (r || !message || message->len == 0) { + fprintf(stderr, "error when receiving response\n"); + goto out; + } + switch (message->buffer[0]) { + case 1: /* go ahead */ + handle_response_text_and_file(cpf, message); + break; + case 3: /* error */ + handle_response_error(message); + finish = 1; + break; + case 4: + handle_response_already_found(cpf, message); + finish = 1; + break; + case 2: + case 5: + handle_response_text_and_file(cpf, message); + finish = 1; + break; + } rnet_message_del(message); + if (finish) + goto out; + + message = rnet_decfile_get_file(decfile); + rnet_send(session, message->buffer, message->len, 0); + + message = NULL; + r = rnet_recv(session, &message); + if (r || !message || message->len == 0) { + fprintf(stderr, "error when receiving response\n"); + goto out; + } + switch (message->buffer[0]) { + case 3: /* error */ + handle_response_error(message); + break; + case 2: + case 4: + case 5: + case 1: + handle_response_text_and_file(cpf, message); + break; + } + +out: gnutls_bye(session, GNUTLS_SHUT_RDWR); close(c); rnet_decfile_close(decfile);