diff options
Diffstat (limited to 'pikul.c')
-rw-r--r-- | pikul.c | 252 |
1 files changed, 175 insertions, 77 deletions
@@ -2,12 +2,19 @@ #include <stdio.h> #endif #include <string.h> -#include <json.h> +#include <stdbool.h> #include "private.h" -CURL *curl; -json_tokener *tokener; -struct shipping shipping; +#define SELECT \ +"<select name=\"%s\" %s>\n\ +%s\ +\t\t\t\t\t\t\t\t\t\t\t</select>" +#define SELECT_NUM_PARAMS 3 +#define OPTION \ +"\t\t\t\t\t\t\t\t\t\t\t\t<option value=\"%s\"%s>%s%s</option>\n" +#define OPTION_NUM_PARAMS 4 + +struct shipping *shipping_list[PIKUL_END]; const char **anteraja_init(char *[]); const char **anteraja_services(const char *, const char *, double); @@ -29,13 +36,14 @@ static void recurse(struct json_object *outer, const char *trail[], struct json_ *last = inner; } -static size_t handle(char *contents, size_t size, size_t nmemb, void *data) +static size_t handle(char *contents, size_t size, size_t nmemb, struct shipping *shipping) { size_t realsize = size * nmemb; #ifdef DEBUG contents[realsize] = '\0'; fprintf(stderr, "%s\n", contents); #endif + json_tokener *tokener = shipping->tokener; json_object *response = json_tokener_parse_ex(tokener, contents, realsize); enum json_tokener_error error = json_tokener_get_error(tokener); if (!response) { @@ -48,24 +56,24 @@ static size_t handle(char *contents, size_t size, size_t nmemb, void *data) } else if (!json_object_is_type(response, json_type_object) || error != json_tokener_success) return realsize; struct json_object *status = NULL; - recurse(response, shipping.status_trail, &status); - if (json_object_get_int(status) != 200) + recurse(response, shipping->status_trail, &status); + if (json_object_get_int(status) != 200) { + shipping->data = NULL; return realsize; - switch (shipping.mode) { + } + switch (shipping->mode) { case SERVICES: ; struct json_object *array = NULL; - recurse(response, shipping.trail, &array); + recurse(response, shipping->trail, &array); size_t length = json_object_array_length(array); - shipping.data = malloc(sizeof(struct pikul_services) - + sizeof(struct pikul_service *[length])); - struct pikul_services *services = (struct pikul_services *)shipping.data; - services->length = length; - const char **attributes = (const char **)data; + struct pikul_service **services = malloc(sizeof(struct pikul_service *) + * (length + 1)); + const char **attributes = (const char **)shipping->data; enum { CODE, NAME, ETD, COST }; for (size_t i = 0; i < length; i++) { - services->list[i] = malloc(sizeof(struct pikul_service)); - struct pikul_service *service = services->list[i]; + services[i] = malloc(sizeof(struct pikul_service)); + struct pikul_service *service = services[i]; json_object *object = json_object_array_get_idx(array, i); struct json_object_iterator iterator = json_object_iter_begin(object); struct json_object_iterator iterator_end = json_object_iter_end(object); @@ -90,13 +98,15 @@ static size_t handle(char *contents, size_t size, size_t nmemb, void *data) json_object_iter_next(&iterator); } } + services[length] = NULL; + shipping->data = services; break; case ORDER: ; struct json_object *string = NULL; - recurse(response, shipping.trail, &string); - shipping.data = malloc(json_object_get_string_len(string) + 1); - strcpy(shipping.data, json_object_get_string(string)); + recurse(response, shipping->trail, &string); + shipping->data = malloc(json_object_get_string_len(string) + 1); + strcpy(shipping->data, json_object_get_string(string)); break; default: break; @@ -106,15 +116,17 @@ static size_t handle(char *contents, size_t size, size_t nmemb, void *data) void pikul_init(enum pikul_company company, char *provisions[]) { - curl_global_init(CURL_GLOBAL_SSL); - curl = curl_easy_init(); + curl_global_init(CURL_GLOBAL_DEFAULT); + struct shipping *shipping = malloc(sizeof(struct shipping)); + CURL *curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, shipping); #ifdef DEBUG curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); #endif - shipping.company = company; - shipping.headers = NULL; + shipping->headers = NULL; const char **fields; + shipping_list[company] = shipping; switch (company) { case PIKUL_ANTERAJA: fields = anteraja_init(provisions); @@ -128,38 +140,43 @@ void pikul_init(enum pikul_company company, char *provisions[]) while (*fields) { char header[strlen(*fields) + strlen(":") + strlen(*provisions) + 1]; sprintf(header, "%s:%s", *fields++, *provisions++); - shipping.headers = curl_slist_append(shipping.headers, header); + shipping->headers = curl_slist_append(shipping->headers, header); } - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, shipping.headers); - tokener = json_tokener_new(); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, shipping->headers); + shipping->handle = curl; + shipping->tokener = json_tokener_new(); } -struct pikul_services *pikul_services(const char *origin, const char *destination, double weight) +struct pikul_service **pikul_services(enum pikul_company company, + const char *origin, const char *destination, double weight) { - shipping.post = NULL; - const char **attributes; - switch (shipping.company) { + struct shipping *shipping = shipping_list[company]; + shipping->post = NULL; + switch (company) { case PIKUL_ANTERAJA: - attributes = anteraja_services(origin, destination, weight); + shipping->data = anteraja_services(origin, destination, weight); break; case PIKUL_SICEPAT: - attributes = sicepat_services(origin, destination, weight); + shipping->data = sicepat_services(origin, destination, weight); break; default: break; } - curl_easy_setopt(curl, CURLOPT_URL, shipping.url); - if (shipping.post) - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, shipping.post); - else + CURL *curl = shipping->handle; + curl_easy_setopt(curl, CURLOPT_URL, shipping->url); + if (shipping->post) { + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, shipping->post); +#ifdef DEBUG + fprintf(stderr, "POST: %s\n", shipping->post); +#endif + } else curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); - shipping.mode = SERVICES; - curl_easy_setopt(curl, CURLOPT_WRITEDATA, attributes); + shipping->mode = SERVICES; curl_easy_perform(curl); - if (shipping.post) - free(shipping.post); - free(shipping.url); - return (struct pikul_services *)shipping.data; + if (shipping->post) + free(shipping->post); + free(shipping->url); + return (struct pikul_service **)shipping->data; } static inline void free_service(struct pikul_service *service) @@ -172,10 +189,11 @@ static inline void free_service(struct pikul_service *service) free(service); } -void pikul_free_services(struct pikul_services *services) +void pikul_free_services(struct pikul_service **services) { - for (size_t i = 0; i < services->length; i++) - free_service(services->list[i]); + size_t i = 0; + while (services[i]) + free_service(services[i++]); free(services); } @@ -185,68 +203,148 @@ static int servicecmp(const void *service1, const void *service2) (*(struct pikul_service * const *)service2)->code); } -double pikul_cost(const char *origin, const char *destination, double weight, const char *code) +char *pikul_html(char *origins[], char *destinations[], double weight, + const char *widget, const char *extra, const char *name, const char *value, + char *code_prefixes[], char *name_prefixes[]) +{ + char *html; + struct pikul_service **services[PIKUL_END]; + bool no_service = true; + for (enum pikul_company company = PIKUL; company < PIKUL_END; company++) { + if (!shipping_list[company]) { + services[company] = NULL; + continue; + } + services[company] = pikul_services(company, + origins[company], destinations[company], weight); + if (services[company] && services[company][0]) + no_service = false; + } + if (!strcmp(widget, "select")) { + char *options = NULL; + if (no_service) { + static const char *empty = "<option value=\"\">Not enough information</option>"; + options = malloc(strlen(empty) + 1); + strcpy(options, empty); + } else + for (enum pikul_company company = PIKUL; company < PIKUL_END; company++) { + if (!services[company]) + continue; + if (!services[company][0]) { + free(services[company]); + continue; + } + size_t i = 0; + struct pikul_service *service; + while ((service = services[company][i++])) { + char *code_prefix = code_prefixes[company]; + char *name_prefix = name_prefixes[company]; + size_t code_length = strlen(code_prefix) + strlen(service->code); + char code[code_length + 1]; + sprintf(code, "%s%s", code_prefix, service->code); + _Bool selected = !strcmp(code, value); + size_t length = strlen(OPTION) + code_length + + (selected ? strlen(" selected") : 0) + + strlen(name_prefix) + strlen(service->name) + - OPTION_NUM_PARAMS * strlen("%s"); + char option[length + 1]; + sprintf(option, OPTION, code, selected ? " selected" : "", + name_prefix, service->name); + if (options) + options = realloc(options, strlen(options) + length + 1); + else { + options = malloc(length + 1); + memset(options, '\0', strlen(options)); + } + strcat(options, option); + } + pikul_free_services(services[company]); + } + html = malloc(strlen(SELECT) + strlen(name) + (extra ? strlen(extra) : 0) + strlen(options) + - SELECT_NUM_PARAMS * strlen("%s") + 1); + sprintf(html, SELECT, name, extra ? extra : "", options); + } + return html; +} + +double pikul_cost(enum pikul_company company, const char *code, + const char *origin, const char *destination, double weight) { - struct pikul_services *services = pikul_services(origin, destination, weight); - if (!services || !services->length) + struct pikul_service **services = pikul_services(company, origin, destination, weight); + if (!services) + return .0; + if (!services[0]) { + free(services); return .0; - qsort(services->list, services->length, sizeof(struct pikul_service *), servicecmp); + } + size_t length = 0; + while (services[length]) + length++; + qsort(services, length, sizeof(struct pikul_service *), servicecmp); struct pikul_service *key_service = malloc(sizeof(struct pikul_service)); memset(key_service, '\0', sizeof(struct pikul_service)); key_service->code = malloc(strlen(code) + 1); strcpy(key_service->code, code); - double cost = (*(struct pikul_service **)bsearch(&key_service, services->list, - services->length, sizeof(struct pikul_service *), servicecmp))->cost; + double cost = (*(struct pikul_service **)bsearch(&key_service, services, + length, sizeof(struct pikul_service *), servicecmp))->cost; free_service(key_service); pikul_free_services(services); return cost; } -char *pikul_order(const char *order_number, const char *service, const char *sender_name, - const char *sender_phone, const char *origin, const char *sender_address, - const char *sender_postal, const char *receiver_name, const char *receiver_phone, - const char *destination, const char *receiver_address, const char *receiver_postal, +char *pikul_order(enum pikul_company company, const char *order_number, const char *service, + const char *sender_name, const char *sender_phone, const char *origin, + const char *sender_address, const char *sender_postal, + const char *receiver_name, const char *receiver_phone, const char *destination, + const char *receiver_address, const char *receiver_postal, int nitems, char **items[], double subtotal) { - shipping.post = NULL; - switch (shipping.company) { + struct shipping *shipping = shipping_list[company]; + shipping->post = NULL; + switch (company) { case PIKUL_ANTERAJA: anteraja_order(order_number, service, sender_name, sender_phone, origin, - sender_address, sender_postal, receiver_name, receiver_phone, + sender_address, sender_postal, receiver_name, receiver_phone, destination, receiver_address, receiver_postal, nitems, items, subtotal); break; default: break; } - curl_easy_setopt(curl, CURLOPT_URL, shipping.url); - if (shipping.post) { - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, shipping.post); + CURL *curl = shipping->handle; + curl_easy_setopt(curl, CURLOPT_URL, shipping->url); + if (shipping->post) { + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, shipping->post); #ifdef DEBUG - fprintf(stderr, "POST: %s\n", shipping.post); + fprintf(stderr, "POST: %s\n", shipping->post); #endif } else curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); - shipping.mode = ORDER; + shipping->mode = ORDER; curl_easy_perform(curl); - if (shipping.post) - free(shipping.post); - free(shipping.url); - return (char *)shipping.data; + if (shipping->post) + free(shipping->post); + free(shipping->url); + return (char *)shipping->data; } void pikul_cleanup() { - switch (shipping.company) { - case PIKUL_ANTERAJA: - anteraja_cleanup(); - break; - default: - break; + for (enum pikul_company company = PIKUL; company < PIKUL_END; company++) { + if (!shipping_list[company]) + continue; + switch (company) { + case PIKUL_ANTERAJA: + anteraja_cleanup(); + break; + default: + break; + } + struct shipping *shipping = shipping_list[company]; + free(shipping->base); + json_tokener_free(shipping->tokener); + curl_slist_free_all(shipping->headers); + curl_easy_cleanup(shipping->handle); } - free(shipping.base); - json_tokener_free(tokener); - curl_slist_free_all(shipping.headers); - curl_easy_cleanup(curl); curl_global_cleanup(); } |