diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile.PL | 7 | ||||
-rw-r--r-- | anteraja.c | 140 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | handler.h | 83 | ||||
-rw-r--r-- | pikul.c | 60 | ||||
-rw-r--r-- | pikul.h | 5 | ||||
-rw-r--r-- | pikul.i | 50 | ||||
-rw-r--r-- | shipping.h | 10 |
9 files changed, 300 insertions, 59 deletions
@@ -11,3 +11,6 @@ install-sh ltmain.sh Makefile.in missing +*.old +*.p* +*_wrap.c diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..2344c9c --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,7 @@ +use ExtUtils::MakeMaker; +WriteMakefile( + NAME => 'Pikul', + INC => '`pkg-config --cflags json-c`', + LIBS => ['-lpikul -lcurl -ljson-c'], + OBJECT => '$(O_FILES)' +); @@ -8,27 +8,72 @@ \"destination\":\"%s\",\ \"weight\":%d\ }" +#define SERVICES_WEIGHT 5 + +#define ORDER_PATH "order" +#define ORDER_POST \ +"{\ +\"booking_id\":\"%s-%s\",\ +\"service_code\":\"%s\",\ +\"parcel_total_weight\":%d,\ +\"shipper\":{\ +\"name\":\"%s\",\ +\"phone\":\"%s\",\ +\"district\":\"%s\",\ +\"address\":\"%s\",\ +\"postcode\":\"%s\"\ +},\ +\"receiver\":{\ +\"name\":\"%s\",\ +\"phone\":\"%s\",\ +\"district\":\"%s\",\ +\"address\":\"%s\",\ +\"postcode\":\"%s\"\ +},\ +\"items\":[\ +%s\ +],\ +\"use_insurance\":%s,\ +\"declared_value\":%d\ +}" +#define ORDER_WEIGHT 5 +#define ORDER_INSURANCE strlen("false") +#define ORDER_SUBTOTAL 9 + +#define ORDER_ITEM \ +"{\ +\"item_name\":\"%s\",\ +\"item_quantity\":%d,\ +\"declared_value\":%d,\ +\"weight\":%d\ +}" +#define ORDER_ITEM_QUANTITY 2 +#define ORDER_ITEM_PRICE 9 +#define ORDER_ITEM_WEIGHT 5 extern CURL *curl; static const char *status_trail[] = { "status", NULL }; +static char *prefix = NULL; -void anteraja_init(char *provisions[], struct shipping *shipping) +void anteraja_init(char *provisions[]) { - enum { BASE_PATH, ACCESS_KEY }; - shipping->base = malloc(strlen(provisions[BASE_PATH]) + 1); - strcpy(shipping->base, provisions[BASE_PATH]); - headers((const char *[]){ "access-key-id", "secret-access-key", NULL }, - &provisions[ACCESS_KEY], shipping); - shipping->headers = curl_slist_append(shipping->headers, "Content-Type:application/json"); + enum { BASE_PATH, ACCESS_KEY_ID, SECRET_ACCESS_KEY, PREFIX }; + shipping.base = malloc(strlen(provisions[BASE_PATH]) + 1); + strcpy(shipping.base, provisions[BASE_PATH]); + headers((const char *[]){ "access-key-id", "secret-access-key", NULL }, &provisions[ACCESS_KEY_ID]); + shipping.headers = curl_slist_append(shipping.headers, "Content-Type:application/json"); + if (provisions[PREFIX]) { + prefix = malloc(strlen(provisions[PREFIX]) + 1); + strcpy(prefix, provisions[PREFIX]); + } } -void anteraja_services(const char *origin, const char *destination, double weight, - struct shipping *shipping, char **url, char **post) +void anteraja_services(const char *origin, const char *destination, double weight, char **url, char **post) { - *url = malloc(strlen(shipping->base) + strlen(SERVICES_PATH) + 1); - sprintf(*url, "%s%s", shipping->base, SERVICES_PATH); - *post = malloc(strlen(SERVICES_POST) + strlen(origin) + strlen(destination) + strlen("50000") + *url = malloc(strlen(shipping.base) + strlen(SERVICES_PATH) + 1); + sprintf(*url, "%s%s", shipping.base, SERVICES_PATH); + *post = malloc(strlen(SERVICES_POST) + strlen(origin) + strlen(destination) + SERVICES_WEIGHT - 2 * strlen("%s") - strlen("%d") + 1); sprintf(*post, SERVICES_POST, origin, destination, weight < 1.0 ? 1000 : (int)weight * 1000); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, *post); @@ -38,7 +83,7 @@ size_t anteraja_services_handle(const char *contents, size_t size, size_t nmemb, struct pikul_services **services) { size_t realsize = size * nmemb; - handle_services(contents, realsize, status_trail, (const char *[]){ + handle(SERVICES, contents, realsize, status_trail, (const char *[]){ "content", "services", NULL @@ -50,3 +95,72 @@ size_t anteraja_services_handle(const char *contents, size_t size, size_t nmemb, }, services); return realsize; } + +void anteraja_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, + int nitems, char **items[], double subtotal, char **url, char **post) +{ + *url = malloc(strlen(shipping.base) + strlen(ORDER_PATH) + 1); + sprintf(*url, "%s%s", shipping.base, ORDER_PATH); + enum { SKU, QUANTITY, DESCRIPTION, PRICE, WEIGHT }; + char *json = NULL; + double total_weight = .0; + for (int i = 0; i < nitems; i++) { + size_t length = strlen(ORDER_ITEM) + strlen(items[i][DESCRIPTION]) + ORDER_ITEM_QUANTITY + + ORDER_ITEM_PRICE + ORDER_ITEM_WEIGHT - strlen("%s") - 3 * strlen("%d") + + strlen(","); + char item[length + 1]; + int quantity = atoi(items[i][QUANTITY]); + if (quantity > 1) + nitems -= quantity - 1; + double price = atof(items[i][PRICE]); + if (price < 1000.0) + price = 1000.0; + double weight = atof(items[i][WEIGHT]) * 1000.0; + if (weight < 100.0) + weight = 100.0; + total_weight += weight * quantity; + sprintf(item, ORDER_ITEM, items[i][DESCRIPTION], quantity, (int)price, (int)weight); + if (json) + json = realloc(json, strlen(json) + length + 1); + else { + json = malloc(length + 1); + memset(json, '\0', strlen(json)); + } + strcat(json, item); + if (i + 1 < nitems) + strcat(json, ","); + else + json[strlen(json)] = '\0'; + } + *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(*post, ORDER_POST, prefix, order_number, service, (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", subtotal < 1000.0 ? 1000 : (int)subtotal); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, *post); +} + +size_t anteraja_order_handle(const char *contents, size_t size, size_t nmemb, char **tracking_number) +{ + size_t realsize = size * nmemb; + handle(ORDER, contents, realsize, status_trail, (const char *[]){ + "content", + "waybill_no", + NULL + }, NULL, tracking_number); + return realsize; +} + +void anteraja_cleanup() +{ + if (prefix) + free(prefix); +} diff --git a/configure.ac b/configure.ac index c6d63c1..5dbace7 100644 --- a/configure.ac +++ b/configure.ac @@ -7,6 +7,7 @@ PKG_CHECK_MODULES([DEPS], [libcurl json-c]) AC_TYPE_SIZE_T AC_C_INLINE AC_FUNC_MALLOC +AC_FUNC_REALLOC AC_CHECK_FUNCS([memset]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) @@ -8,8 +8,10 @@ extern json_tokener *tokener; void recurse(struct json_object *, const char *[], struct json_object **); -inline void handle_services(const char *contents, size_t num_bytes, const char *status_trail[], - const char *trail[], const char *attributes[], struct pikul_services **services) +enum type { SERVICES, ORDER }; + +inline void handle(enum type type, const char *contents, size_t num_bytes, const char *status_trail[], + const char *trail[], const char *attributes[], void *data) { #ifdef DEBUG ((char *)contents)[num_bytes] = '\0'; @@ -30,37 +32,54 @@ inline void handle_services(const char *contents, size_t num_bytes, const char * recurse(response, status_trail, &status); if (json_object_get_int(status) != 200) return; - struct json_object *array = NULL; - recurse(response, trail, &array); - size_t length = json_object_array_length(array); - *services = malloc(sizeof(struct pikul_services) + sizeof(struct pikul_service *[length])); - (*services)->length = length; - 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]; - 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); - while (!json_object_iter_equal(&iterator, &iterator_end)) { - const char *name = json_object_iter_peek_name(&iterator); - json_object *value = json_object_iter_peek_value(&iterator); - if (!strcmp(name, attributes[COST])) - service->cost = json_object_get_double(value); - else { - int len = json_object_get_string_len(value); - if (len) { - char *string = malloc(len + 1); - strcpy(string, json_object_get_string(value)); - if (!strcmp(name, attributes[CODE])) - service->code = string; - else if (!strcmp(name, attributes[NAME])) - service->name = string; - else if (!strcmp(name, attributes[ETD])) - service->etd = string; + switch (type) { + case SERVICES: + ; + struct json_object *array = NULL; + recurse(response, trail, &array); + size_t length = json_object_array_length(array); + struct pikul_services **services = (struct pikul_services **)data; + *services = malloc(sizeof(struct pikul_services) + + sizeof(struct pikul_service *[length])); + (*services)->length = length; + 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]; + 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); + while (!json_object_iter_equal(&iterator, &iterator_end)) { + const char *name = json_object_iter_peek_name(&iterator); + json_object *value = json_object_iter_peek_value(&iterator); + if (!strcmp(name, attributes[COST])) + service->cost = json_object_get_double(value); + else { + int len = json_object_get_string_len(value); + if (len) { + char *string = malloc(len + 1); + strcpy(string, json_object_get_string(value)); + if (!strcmp(name, attributes[CODE])) + service->code = string; + else if (!strcmp(name, attributes[NAME])) + service->name = string; + else if (!strcmp(name, attributes[ETD])) + service->etd = string; + } + } + json_object_iter_next(&iterator); } } - json_object_iter_next(&iterator); - } + break; + case ORDER: + ; + struct json_object *string = NULL; + recurse(response, trail, &string); + char **tracking_number = (char **)data; + *tracking_number = malloc(json_object_get_string_len(string) + 1); + strcpy(*tracking_number, json_object_get_string(string)); + break; + default: + break; } } @@ -3,15 +3,19 @@ CURL *curl; json_tokener *tokener; -static struct shipping shipping; +struct shipping shipping; -extern inline void headers(const char *[], char *[], struct shipping *); -extern inline void handle_services(const char *, size_t, const char *[], const char *[], const char *[], - struct pikul_services **); +void headers(const char *[], char *[]); +void handle(enum type, const char *, size_t, const char *[], const char *[], const char *[], void *); -extern void anteraja_init(char *[], struct shipping *); -extern void anteraja_services(const char *, const char *, double, struct shipping *, char **, char **); -extern size_t anteraja_services_handle(const char *, size_t, size_t, struct pikul_services **); +void anteraja_init(char *[]); +void anteraja_services(const char *, const char *, double, char **, char **); +size_t anteraja_services_handle(const char *, size_t, size_t, struct pikul_services **); +void anteraja_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 **, char **); +size_t anteraja_order_handle(const char *, size_t size, size_t nmemb, char **); +void anteraja_cleanup(); extern void sicepat_init(char *[], struct shipping *); extern void sicepat_services(const char *, const char *, double, struct shipping *, char **); @@ -27,7 +31,7 @@ void pikul_init(enum pikul_company company, char *provisions[]) shipping.company = company; switch (company) { case PIKUL_ANTERAJA: - anteraja_init(provisions, &shipping); + anteraja_init(provisions); break; case PIKUL_SICEPAT: sicepat_init(provisions, &shipping); @@ -58,7 +62,7 @@ struct pikul_services *pikul_services(const char *origin, const char *destinatio size_t (*handler)(const char *, size_t, size_t, struct pikul_services **); switch (shipping.company) { case PIKUL_ANTERAJA: - anteraja_services(origin, destination, weight, &shipping, &url, &post); + anteraja_services(origin, destination, weight, &url, &post); handler = anteraja_services_handle; break; case PIKUL_SICEPAT: @@ -117,8 +121,46 @@ double pikul_cost(const char *origin, const char *destination, double weight, co 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, + int nitems, char **items[], double subtotal) +{ + char *tracking_number = NULL; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &tracking_number); + char *url; + char *post = NULL; + size_t (*handler)(const char *, size_t, size_t, char **); + switch (shipping.company) { + case PIKUL_ANTERAJA: + anteraja_order(order_number, service, sender_name, sender_phone, origin, + sender_address, sender_postal, receiver_name, receiver_phone, + destination, receiver_address, receiver_postal, nitems, items, + subtotal, &url, &post); + handler = anteraja_order_handle; + break; + default: + break; + } + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handler); + curl_easy_perform(curl); + if (post) + free(post); + free(url); + return tracking_number; +} + void pikul_cleanup() { + switch (shipping.company) { + case PIKUL_ANTERAJA: + anteraja_cleanup(); + break; + default: + break; + } free(shipping.base); json_tokener_free(tokener); curl_slist_free_all(shipping.headers); @@ -26,6 +26,11 @@ 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, + int nitems, char **items[], double subtotal); void pikul_cleanup(); #ifdef __cplusplus @@ -0,0 +1,50 @@ +%module Pikul +%{ +#include "pikul.h" +%} + +%typemap(in) char *[] { + AV *tempav = (AV *)SvRV($input); + I32 len = av_len(tempav); + $1 = (char **)malloc((len + 2) * sizeof(char *)); + int i; + for (i = 0; i <= len; i++) { + SV **tv = av_fetch(tempav, i, 0); + $1[i] = (char *)SvPV(*tv, PL_na); + } + $1[i] = NULL; +}; +%typemap(freearg) char *[] { + free($1); +} + +%typemap(in) char **[] { + AV *items = (AV *)SvRV($input); + I32 nitems_min1 = av_len(items); + $1 = (char ***)malloc((nitems_min1 + 2) * sizeof(char **)); + int i; + for (i = 0; i <= nitems_min1; i++) { + SV **refptr = av_fetch(items, i, 0); + AV *flat = (AV *)SvRV(*refptr); + I32 nattrs_min1 = av_len(flat); + $1[i] = (char **)malloc((nattrs_min1 + 2) * sizeof(char *)); + int j; + for (j = 0; j <= nattrs_min1; j++) { + SV **tv = av_fetch(flat, j, 0); + $1[i][j] = (char *)SvPV(*tv, PL_na); + } + $1[i][j] = NULL; + } + $1[i] = NULL; +}; +%typemap(freearg) char **[] { + free($1); +} + +%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); +void pikul_cleanup(); @@ -2,18 +2,18 @@ #include <curl/curl.h> #include "pikul.h" -struct shipping { +extern struct shipping { enum pikul_company company; char *base; struct curl_slist *headers; -}; +} shipping; -inline void headers(const char *fields[], char *provisions[], struct shipping *shipping) +inline void headers(const char *fields[], char *provisions[]) { - shipping->headers = NULL; + shipping.headers = NULL; while (*fields) { char header[strlen(*fields) + strlen(*provisions) + 2]; sprintf(header, "%s:%s", *fields++, *provisions++); - shipping->headers = curl_slist_append(shipping->headers, header); + shipping.headers = curl_slist_append(shipping.headers, header); } } |