diff options
| -rw-r--r-- | anteraja.c | 31 | ||||
| -rw-r--r-- | pikul.c | 252 | ||||
| -rw-r--r-- | pikul.h | 29 | ||||
| -rw-r--r-- | pikul.i | 10 | ||||
| -rw-r--r-- | private.h | 6 | ||||
| -rw-r--r-- | sicepat.c | 14 | 
6 files changed, 226 insertions, 116 deletions
| @@ -57,33 +57,35 @@ static char *prefix = NULL;  const char **anteraja_init(char *provisions[])  {  	enum { ACCESS_KEY_ID, SECRET_ACCESS_KEY, BASE_PATH, PREFIX }; -	shipping.base = malloc(strlen(provisions[BASE_PATH]) + 1); -	strcpy(shipping.base, provisions[BASE_PATH]); +	struct shipping *shipping = shipping_list[PIKUL_ANTERAJA]; +	shipping->base = malloc(strlen(provisions[BASE_PATH]) + 1); +	strcpy(shipping->base, provisions[BASE_PATH]);  	if (provisions[PREFIX]) {  		prefix = malloc(strlen(provisions[PREFIX]) + 1);  		strcpy(prefix, provisions[PREFIX]);  	} -	shipping.headers = curl_slist_append(shipping.headers, "Content-Type:application/json"); +	shipping->headers = curl_slist_append(shipping->headers, "Content-Type:application/json");  	static const char *status_trail[] = { "status", NULL }; -	shipping.status_trail = status_trail; +	shipping->status_trail = status_trail;  	static const char *fields[] = { "access-key-id", "secret-access-key", NULL };  	return fields;  }  const char **anteraja_services(const char *origin, const char *destination, double weight)  { -	shipping.url = malloc(strlen(shipping.base) + strlen(SERVICES_PATH) + 1); -	sprintf(shipping.url, "%s%s", shipping.base, SERVICES_PATH); -	shipping.post = malloc(strlen(SERVICES_POST) + strlen(origin) + strlen(destination) +	struct shipping *shipping = shipping_list[PIKUL_ANTERAJA]; +	shipping->url = malloc(strlen(shipping->base) + strlen(SERVICES_PATH) + 1); +	sprintf(shipping->url, "%s%s", shipping->base, SERVICES_PATH); +	shipping->post = malloc(strlen(SERVICES_POST) + strlen(origin) + strlen(destination)  			+ SERVICES_WEIGHT - 2 * strlen("%s") - strlen("%d") + 1); -	sprintf(shipping.post, SERVICES_POST, origin, destination, +	sprintf(shipping->post, SERVICES_POST, origin, destination,  			weight < 1.0 ? 1000 : (int)weight * 1000);  	static const char *trail[] = {  		"content",  		"services",  		NULL  	}; -	shipping.trail = trail; +	shipping->trail = trail;  	static const char *attributes[] = {  		"product_code",  		"product_name", @@ -99,8 +101,9 @@ void anteraja_order(const char *order_number, const char *service, const char *s  		const char *destination, const char *receiver_address, const char *receiver_postal,  		int nitems, char **items[], double subtotal)  { -	shipping.url = malloc(strlen(shipping.base) + strlen(ORDER_PATH) + 1); -	sprintf(shipping.url, "%s%s", shipping.base, ORDER_PATH); +	struct shipping *shipping = shipping_list[PIKUL_ANTERAJA]; +	shipping->url = malloc(strlen(shipping->base) + strlen(ORDER_PATH) + 1); +	sprintf(shipping->url, "%s%s", shipping->base, ORDER_PATH);  	enum { SKU, QUANTITY, DESCRIPTION, PRICE, WEIGHT };  	char *json = NULL;  	double total_weight = .0; @@ -132,13 +135,13 @@ void anteraja_order(const char *order_number, const char *service, const char *s  		else  			json[strlen(json)] = '\0';  	} -	shipping.post = malloc(strlen(ORDER_POST) + strlen(prefix) + strlen(order_number) + strlen(service) +	shipping->post = malloc(strlen(ORDER_POST) + strlen(prefix) + strlen(order_number) + strlen(service)  			+ ORDER_WEIGHT + strlen(sender_name) + strlen(sender_phone) + strlen(origin)  			+ strlen(sender_address) + strlen(sender_postal) + strlen(receiver_name)  			+ strlen(receiver_phone) + strlen(destination) + strlen(receiver_address)  			+ strlen(receiver_postal) + strlen(json) + ORDER_INSURANCE + ORDER_SUBTOTAL  			- 15 * strlen("%s") - 2 * strlen("%d") + 1); -	sprintf(shipping.post, ORDER_POST, prefix, order_number, service, +	sprintf(shipping->post, ORDER_POST, prefix, order_number, service,  			total_weight < 1000.0 ? 1000 : (int)total_weight, sender_name, sender_phone,  			origin, sender_address, sender_postal, receiver_name, receiver_phone, destination,  			receiver_address, receiver_postal, json, total_weight < 1000.0 ? "true" : "false", @@ -148,7 +151,7 @@ void anteraja_order(const char *order_number, const char *service, const char *s  		"waybill_no",  		NULL  	}; -	shipping.trail = trail; +	shipping->trail = trail;  }  void anteraja_cleanup() @@ -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();  } @@ -2,8 +2,10 @@  #define PIKUL_H  enum pikul_company { +	PIKUL,  	PIKUL_ANTERAJA, -	PIKUL_SICEPAT +	PIKUL_SICEPAT, +	PIKUL_END  };  struct pikul_service { @@ -13,23 +15,24 @@ struct pikul_service {  	double cost;  }; -struct pikul_services { -	size_t length; -	struct pikul_service *list[]; -}; -  #ifdef __cplusplus  extern "C" {  #endif  void pikul_init(enum pikul_company company, char *provisions[]); -struct pikul_services *pikul_services(const char *origin, const char *destination, double weight); -void pikul_free_services(struct pikul_services *services); -double pikul_cost(const char *origin, const char *destination, double weight, const char *service); -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, +struct pikul_service **pikul_services(enum pikul_company company, +		const char *origin, const char *destination, double weight); +void pikul_free_services(struct pikul_service **services); +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[]); +double pikul_cost(enum pikul_company company, const char *service, +		const char *origin, const char *destination, double weight); +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);  void pikul_cleanup(); @@ -43,8 +43,10 @@  %rename("%(strip:[pikul_])s") "";  void pikul_init(enum pikul_company, char *[]); -double pikul_cost(const char *, const char *, double, const char *); -char *pikul_order(const char *, const char *, const char *, const char *, const char *, const char *, -                const char *, const char *, const char *, const char *, const char *, const char *, int, -                char **[], double); +char *pikul_html(char *[], char *[], double, const char *, const char *, const char *, const char *, +                char *[], char *[]); +double pikul_cost(enum pikul_company, const char *, const char *, const char *, double); +char *pikul_order(enum pikul_company, const char *, const char *, const char *, const char *, const char *, +                const char *, const char *, const char *, const char *, const char *, const char *, +                const char *, int, char **[], double);  void pikul_cleanup(); @@ -1,17 +1,19 @@  #include <curl/curl.h> +#include <json.h>  #include "pikul.h"  extern struct shipping { -	enum pikul_company company; +	CURL *handle;  	char *base;  	struct curl_slist *headers;  	const char **status_trail;  	char *url;  	char *post; +	json_tokener *tokener;  	enum {  		SERVICES,  		ORDER  	} mode;  	const char **trail;  	void *data; -} shipping; +} *shipping_list[]; @@ -6,31 +6,33 @@  const char **sicepat_init(char *provisions[])  { -	shipping.base = malloc(strlen(BASE) + 1); -	strcpy(shipping.base, BASE); +	struct shipping *shipping = shipping_list[PIKUL_SICEPAT]; +	shipping->base = malloc(strlen(BASE) + 1); +	strcpy(shipping->base, BASE);  	static const char *status_trail[] = {  		"sicepat",  		"status",  		"code",  		NULL  	}; -	shipping.status_trail = status_trail; +	shipping->status_trail = status_trail;  	static const char *fields[] = { "api-key", NULL };  	return fields;  }  const char **sicepat_services(const char *origin, const char *destination, double weight)  { -	shipping.url = malloc(strlen(shipping.base) + strlen("tariff?origin=") + strlen(origin) +	struct shipping *shipping = shipping_list[PIKUL_SICEPAT]; +	shipping->url = malloc(strlen(shipping->base) + strlen("tariff?origin=") + strlen(origin)  			+ strlen("&destination=") + strlen(destination) + strlen("&weight=") + 9); -	sprintf(shipping.url, "%stariff?origin=%s&destination=%s&weight=%f", shipping.base, origin, +	sprintf(shipping->url, "%stariff?origin=%s&destination=%s&weight=%f", shipping->base, origin,  			destination, weight);  	static const char *trail[] = {  		"sicepat",  		"results",  		NULL  	}; -	shipping.trail = trail; +	shipping->trail = trail;         	static const char *attributes[] = {  		"service",  		"description", |