summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorꦌꦫꦶꦏ꧀ꦦꦿꦧꦮꦑꦩꦭ꧀ <erik@darapsa.co.id>2022-02-02 09:29:10 +0800
committerꦌꦫꦶꦏ꧀ꦦꦿꦧꦮꦑꦩꦭ꧀ <erik@darapsa.co.id>2022-02-02 09:29:10 +0800
commit12cde42c929b63a1ef1b2ad7f3482336419980b2 (patch)
tree3c7e7185909432068985da6bb739bf34d67fcd58
parentebfa1718a36a8a0f3cf4571bc48b1990129af703 (diff)
Asynchronous connection
Important updates: 1. Emscripten port. 2. HTTP request code copied from libicclient & slightly fixed. 3. Cookies, for maintaining authorisation between different async handles.
-rw-r--r--Makefile.am14
-rw-r--r--client.c87
-rw-r--r--post.c3
-rw-r--r--post.h43
-rw-r--r--request.c227
-rw-r--r--request.h113
-rw-r--r--rtclient.h11
-rw-r--r--rtclient/search.h12
-rw-r--r--rtclient/ticket.h14
-rw-r--r--rtclient/typedefs.h18
-rw-r--r--rtclient/user.h8
-rw-r--r--search.c58
-rw-r--r--ticket.c235
-rw-r--r--user.c82
14 files changed, 522 insertions, 403 deletions
diff --git a/Makefile.am b/Makefile.am
index 43a977c..71876b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,13 +1,10 @@
lib_LTLIBRARIES = librtclient.la
librtclient_la_SOURCES = \
- request.h \
- request.c \
- post.h \
- post.c \
- user.c \
- ticket.c \
- search.c \
- client.c
+ client.c \
+ request.c \
+ user.c \
+ ticket.c \
+ search.c
librtclient_la_CPPFLAGS = -I${prefix}/include
librtclient_la_LDFLAGS = -L${prefix}/lib
if EMSCRIPTEN
@@ -18,6 +15,7 @@ librtclient_la_LDFLAGS += $(CURL_LIBS)
endif
include_HEADERS = rtclient.h
pkginclude_HEADERS = \
+ rtclient/typedefs.h \
rtclient/user.h \
rtclient/ticket.h \
rtclient/search.h
diff --git a/client.c b/client.c
index f452b06..85bc1e7 100644
--- a/client.c
+++ b/client.c
@@ -1,57 +1,68 @@
-#include <stdbool.h>
#include <stdlib.h>
+#include <string.h>
#include "request.h"
#include "rtclient.h"
-CURL *curl = NULL;
+#ifdef __EMSCRIPTEN__
+emscripten_fetch_attr_t attr;
+#else
char *server_url = NULL;
+char *cookies_path = NULL;
+char *cainfo = NULL;
+#endif
-bool rtclient_init(const char *url, const char *certificate)
+void rtclient_init(const char *url, const char *cookies,
+ const char *certificate)
{
+#ifdef __EMSCRIPTEN__
+ emscripten_fetch_attr_init(&attr);
+ attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
+#else
+ size_t length = strlen(url);
+ size_t append = url[length - 1] != '/';
+ server_url = malloc(length + append + 1);
+ strcpy(server_url, url);
+ if (append)
+ strcat(server_url, "/");
+ cookies_path = malloc(strlen(cookies) + 1);
+ strcpy(cookies_path, cookies);
curl_global_init(CURL_GLOBAL_SSL);
- curl = curl_easy_init();
- if (curl) {
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
- curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
- curl_easy_setopt(curl, CURLOPT_REFERER, url);
- if (certificate)
- curl_easy_setopt(curl, CURLOPT_CAINFO, certificate);
-#ifdef DEBUG
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
-#endif
- size_t length = strlen(url);
- bool append = !(bool)(url[length - 1] == '/');
- server_url = malloc(length + (size_t)append + 1);
- strcpy(server_url, url);
- if (append)
- strcat(server_url, "/");
+ if (certificate) {
+ cainfo = malloc(strlen(certificate) + 1);
+ strcpy(cainfo, certificate);
}
+#endif
+}
- return (bool)curl;
+void rtclient_login(const char *name, const char *password,
+ void (*handler)(rtclient_response *))
+{
+ request(handler, NULL, &(struct body){ 2, {
+ { "user", name },
+ { "pass", password }
+ }}, "");
}
-void rtclient_login(const char *name, const char *password)
+void rtclient_free_response(rtclient_response *response)
{
- struct curl_httppost *post, *last = NULL;
- curl_formadd(&post, &last
- , CURLFORM_COPYNAME, "user"
- , CURLFORM_PTRCONTENTS, name
- , CURLFORM_END);
- curl_formadd(&post, &last
- , CURLFORM_COPYNAME, "pass"
- , CURLFORM_PTRCONTENTS, password
- , CURLFORM_END);
- last = NULL;
- request(NULL, NULL, post, "");
- curl_formfree(post);
- post = NULL;
+#ifdef __EMSCRIPTEN__
+ if (response->userData)
+ free(response->userData);
+ emscripten_fetch_close(response);
+#else
+ free(response->data);
+ curl_easy_cleanup(response->curl);
+ free(response);
+#endif
}
void rtclient_cleanup()
{
- if (curl) {
- free(server_url);
- curl_easy_cleanup(curl);
- }
+#ifndef __EMSCRIPTEN__
+ if (cainfo)
+ free(cainfo);
+ free(cookies_path);
+ free(server_url);
curl_global_cleanup();
+#endif
}
diff --git a/post.c b/post.c
deleted file mode 100644
index 8dca62f..0000000
--- a/post.c
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "post.h"
-
-extern inline void post(const char *, const char *[], size_t);
diff --git a/post.h b/post.h
deleted file mode 100644
index 8420d73..0000000
--- a/post.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef RTCLIENT_POST_H
-#define RTCLIENT_POST_H
-
-#include "request.h"
-
-inline void post(const char *path, const char *pairs[], size_t n)
-{
- size_t length = 0;
- for (size_t i = 0; i < n; i += 2) {
- const char *pair = pairs[i];
- if (pair && strcmp(pair, ""))
- length += strlen(pair) + strlen(pairs[i + 1]) + 3;
- }
-
- char content[length + 1];
- memset(content, 0, strlen(content));
- for (size_t i = 0; i < n; i += 2) {
- const char *pair = pairs[i];
- if (pair && strcmp(pair, ""))
- sprintf(content, "%s%s: %s\n", content, pairs[i + 1]
- , pair);
- }
-#ifdef DEBUG
-#ifdef ANDROID
- __android_log_print(ANDROID_LOG_DEBUG, "librtclient", "%s\nContent:\n%s"
- , __func__, content);
-#else
- fprintf(stderr, "%s\nContent:\n%s", __func__, content);
-#endif // ANDROID
-#endif // DEBUG
-
- struct curl_httppost *post, *last = NULL;
- curl_formadd(&post, &last
- , CURLFORM_COPYNAME, "content"
- , CURLFORM_PTRCONTENTS, content
- , CURLFORM_END);
- last = NULL;
- request(NULL, NULL, post, "%s", path);
- curl_formfree(post);
- post = NULL;
-}
-
-#endif // RTCLIENT_POST_H
diff --git a/request.c b/request.c
index 652ec71..299bf2c 100644
--- a/request.c
+++ b/request.c
@@ -1,4 +1,227 @@
+#if defined __ANDROID__ && defined DEBUG
+#include <android/log.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
#include "request.h"
-extern inline void request(size_t (*writefunction)(void *, size_t, size_t, void *)
- , void *writedata, struct curl_httppost *post, char *fmt, ...);
+#ifdef __EMSCRIPTEN__
+
+extern emscripten_fetch_attr_t attr;
+
+#else
+
+#ifdef HAVE_THREADS_H
+#include <threads.h>
+#else
+#include <pthread.h>
+typedef pthread_t thrd_t;
+#endif
+#include <curl/curl.h>
+
+extern char *server_url;
+extern char *cookies_path;
+extern char *cainfo;
+
+struct container {
+ struct curl_httppost *post;
+ void (*handler)(rtclient_response *);
+ rtclient_response *response;
+};
+
+static size_t append(char *data, size_t size, size_t nmemb, rtclient_response *response)
+{
+ size_t realsize = size * nmemb;
+ response->data = realloc(response->data, response->numBytes + realsize + 1);
+ memcpy(&(response->data[response->numBytes]), data, realsize);
+ response->numBytes += realsize;
+ response->data[response->numBytes] = '\0';
+ return realsize;
+}
+
+static
+#ifdef HAVE_THREADS_H
+int
+#else
+void *
+#endif
+async(void *arg)
+{
+#ifdef HAVE_THREADS_H
+ int ret = thrd_success;
+#endif
+ struct container *container = (struct container *)arg;
+ CURLcode res = curl_easy_perform(container->response->curl);
+ if (container->post)
+ curl_formfree(container->post);
+ if (res == CURLE_OK && container->handler)
+ container->handler(container->response);
+ else {
+#ifdef HAVE_THREADS_H
+ ret = thrd_error;
+#endif
+#ifdef DEBUG
+ const char *error = curl_easy_strerror(res);
+#ifdef __ANDROID__
+ __android_log_print(ANDROID_LOG_ERROR, "librtclient.so", "%s", error);
+#else
+ fprintf(stderr, "%s\n", error);
+#endif
+#endif
+ }
+ free(container);
+#ifdef HAVE_THREADS_H
+ return ret;
+#else
+ return NULL;
+#endif
+}
+#endif
+
+void request(void (*handler)(rtclient_response *), void (*callback)(void *), struct body *body, char *fmt, ...)
+{
+ va_list ap;
+ char *p, *sval;
+ unsigned int uval;
+ size_t length =
+#ifndef __EMSCRIPTEN__
+ strlen(server_url) +
+#endif
+ strlen(fmt);
+
+ va_start(ap, fmt);
+ for (p = fmt; *p; p++) {
+ if (*p != '%')
+ continue;
+ switch(*++p) {
+ case 's':
+ sval = va_arg(ap, char *);
+ length += strlen(sval) - 2;
+ break;
+ case 'u':
+ uval = va_arg(ap, unsigned int);
+ do {
+ length++;
+ } while ((uval /= 10));
+ length -= 2;
+ break;
+ case 'c':
+ length++;
+ break;
+ default:
+ break;
+ }
+ }
+ va_end(ap);
+
+ char url[length + 1];
+#ifdef __EMSCRIPTEN__
+ memset(url, '\0', length + 1);
+#else
+ length = 0;
+ strcpy(url, server_url);
+#endif
+
+ va_start(ap, fmt);
+ for (p = fmt; *p; p++) {
+ if (*p != '%')
+ continue;
+ switch(*++p) {
+ case 's':
+ sval = va_arg(ap, char *);
+ strcat(url, sval);
+ length = strlen(url);
+ break;
+ case 'u':
+ uval = va_arg(ap, unsigned int);
+ sprintf(url, "%s%u", url, uval);
+ length = strlen(url);
+ break;
+ case 'c':
+ url[length++] = (char)va_arg(ap, int);
+ url[length] = '\0';
+ break;
+ default:
+ break;
+ }
+ }
+ va_end(ap);
+
+#ifdef __EMSCRIPTEN__
+ if (handler)
+ attr.onsuccess = handler;
+ if (body) {
+ size_t length = 0;
+ char *post = malloc(1);
+ memset(post, '\0', 1);
+ for (size_t i = 0; i < body->num_pairs; i++) {
+ struct pair pair = body->pairs[i];
+ if (!pair.value)
+ continue;
+ length += strlen(pair.key) + strlen(pair.value) + (i ? 1 : 0) + 1;
+ post = realloc(post, length + 1);
+ if (i)
+ strcat(post, "&");
+ sprintf(post, "%s%s=%s", post, pair.key, pair.value);
+ }
+ strcpy(attr.requestMethod, "POST");
+ const char *headers[] = { "Content-Type", "application/x-www-form-urlencoded", NULL };
+ attr.requestHeaders = headers;
+ attr.requestData = post;
+ attr.requestDataSize = length + 1;
+ attr.userData = post;
+ } else {
+ strcpy(attr.requestMethod, "GET");
+ attr.userData = callback;
+ }
+ emscripten_fetch(&attr, url);
+#else
+ CURL *curl = curl_easy_init();
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookies_path);
+ FILE *cookies_file = fopen(cookies_path, "r");
+ if (cookies_file)
+ fclose(cookies_file);
+ else
+ curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookies_path);
+ curl_easy_setopt(curl, CURLOPT_REFERER, url);
+ if (cainfo)
+ curl_easy_setopt(curl, CURLOPT_CAINFO, cainfo);
+#ifdef DEBUG
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+#endif
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, append);
+ rtclient_response *response = malloc(sizeof(rtclient_response));
+ response->data = malloc(1);
+ response->numBytes = 0;
+ response->userData = callback;
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
+ struct curl_httppost *post = NULL;
+ struct curl_httppost *last = NULL;
+ if (body) {
+ for (size_t i = 0; i < body->num_pairs; i++) {
+ struct pair pair = body->pairs[i];
+ if (!pair.value)
+ continue;
+ curl_formadd(&post, &last, CURLFORM_COPYNAME, pair.key, CURLFORM_PTRCONTENTS, pair.value, CURLFORM_END);
+ }
+ last = NULL;
+ curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
+ } else
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
+ struct container *container = malloc(sizeof(struct container));
+ response->curl = curl;
+ container->post = post;
+ container->handler = handler;
+ container->response = response;
+ thrd_t thread;
+#ifdef HAVE_THREADS_H
+ thrd_create(&thread, async, container);
+#else
+ pthread_create(&thread, NULL, async, container);
+#endif
+#endif
+}
diff --git a/request.h b/request.h
index 932f75e..4c559fb 100644
--- a/request.h
+++ b/request.h
@@ -1,105 +1,16 @@
-#ifndef RTCLIENT_REQUEST_H
-#define RTCLIENT_REQUEST_H
+#ifndef REQUEST_H
+#define REQUEST_H
-#if defined(ANDROID) && defined(DEBUG)
-#include <android/log.h>
-#endif
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <curl/curl.h>
-
-extern CURL *curl;
-extern char *server_url;
-
-inline void request(size_t (*writefunction)(void *, size_t, size_t, void *)
- , void *writedata, struct curl_httppost *post, char *fmt, ...)
-{
- va_list ap;
- char *p, *sval;
- unsigned int uval;
- size_t length = strlen(server_url) + strlen(fmt);
-
- va_start(ap, fmt);
- for (p = fmt; *p; p++) {
- if (*p != '%')
- continue;
- switch(*++p) {
- case 's':
- sval = va_arg(ap, char *);
- length += strlen(sval) - 2;
- break;
- case 'u':
- uval = va_arg(ap, unsigned int);
- do {
- length++;
- } while ((uval /= 10));
- length -= 2;
- break;
- case 'c':
- length++;
- break;
- default:
- break;
- }
- }
- va_end(ap);
+#include "rtclient/typedefs.h"
- char url[length + 1];
- length = 0;
- strcpy(url, server_url);
+struct body {
+ size_t num_pairs;
+ struct pair {
+ const char *key;
+ const char *value;
+ } pairs[20];
+};
- va_start(ap, fmt);
- for (p = fmt; *p; p++) {
- if (*p != '%')
- continue;
- switch(*++p) {
- case 's':
- sval = va_arg(ap, char *);
- strcat(url, sval);
- length = strlen(url);
- break;
- case 'u':
- uval = va_arg(ap, unsigned int);
- sprintf(url, "%s%u", url, uval);
- length = strlen(url);
- break;
- case 'c':
- url[length++] = (char)va_arg(ap, int);
- url[length] = '\0';
- break;
- default:
- break;
- }
- }
- va_end(ap);
+void request(void (*)(rtclient_response *), void (*)(void *), struct body *, char *, ...);
- curl_easy_setopt(curl, CURLOPT_URL, url);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunction);
- if (writedata)
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, writedata);
- else
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, stdout);
- if (post)
- curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
- else
- curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
-
-#ifdef DEBUG
- CURLcode res =
-#endif // DEBUG
- curl_easy_perform(curl);
-#ifdef DEBUG
- if (res != CURLE_OK) {
- const char *error = curl_easy_strerror(res);
-#ifdef ANDROID
- __android_log_print(ANDROID_LOG_ERROR, "librtclient", "%s: %s"
- , __func__, error);
-#else
- fprintf(stderr, "%s: %s\n", __func__, error);
-#endif // ANDROID
- }
-#endif // DEBUG
-}
-
-#endif // RTCLIENT_REQUEST_H
+#endif
diff --git a/rtclient.h b/rtclient.h
index dac2198..49541e3 100644
--- a/rtclient.h
+++ b/rtclient.h
@@ -1,13 +1,18 @@
#ifndef RTCLIENT_H
#define RTCLIENT_H
+#include "rtclient/typedefs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
- bool rtclient_init(const char *url, const char *certificate);
- void rtclient_login(const char *name, const char *password);
- void rtclient_cleanup();
+void rtclient_init(const char *url, const char *cookies,
+ const char *certificate);
+void rtclient_login(const char *name, const char *password,
+ void (*handler)(rtclient_response *));
+void rtclient_free_response(rtclient_response *response);
+void rtclient_cleanup();
#ifdef __cplusplus
}
diff --git a/rtclient/search.h b/rtclient/search.h
index e0e386a..25b7258 100644
--- a/rtclient/search.h
+++ b/rtclient/search.h
@@ -1,21 +1,15 @@
#ifndef RTCLIENT_SEARCH_H
#define RTCLIENT_SEARCH_H
-struct rtclient_search_ticket_list {
- size_t length;
- struct rtclient_ticket *tickets[];
-};
-
#ifdef __cplusplus
extern "C" {
#endif
- void rtclient_search_ticket(struct rtclient_search_ticket_list **listptr
- , const char *query);
- void rtclient_search_ticket_free(struct rtclient_search_ticket_list *list);
+void rtclient_search_ticket(const char *query,
+ void (*callback)(struct rtclient_ticket **));
#ifdef __cplusplus
}
#endif
-#endif // RTCLIENT_SEARCH_H
+#endif
diff --git a/rtclient/ticket.h b/rtclient/ticket.h
index 9fdd9a0..0600c34 100644
--- a/rtclient/ticket.h
+++ b/rtclient/ticket.h
@@ -56,11 +56,6 @@ struct rtclient_ticket_history {
struct rtclient_ticket_history_attachment_list *attachments;
};
-struct rtclient_ticket_history_list {
- size_t length;
- struct rtclient_ticket_history *histories[];
-};
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -79,12 +74,9 @@ void rtclient_ticket_new(const char *queue,
const char *starts,
const char *due,
const char *text);
- void rtclient_ticket_history(struct rtclient_ticket_history_list **listptr
- , unsigned int id, bool long_format);
- void rtclient_ticket_history_free
- (struct rtclient_ticket_history *history);
- void rtclient_ticket_history_list_free
- (struct rtclient_ticket_history_list *list);
+void rtclient_ticket_history_list(unsigned int id, bool long_format,
+ void (*callback)(struct rtclient_ticket_history **));
+void rtclient_ticket_history_free(struct rtclient_ticket_history *history);
#ifdef __cplusplus
}
diff --git a/rtclient/typedefs.h b/rtclient/typedefs.h
new file mode 100644
index 0000000..e15b1df
--- /dev/null
+++ b/rtclient/typedefs.h
@@ -0,0 +1,18 @@
+#ifndef RTCLIENT_TYPEDEFS_H
+#define RTCLIENT_TYPEDEFS_H
+
+#include <stddef.h>
+#ifdef __EMSCRIPTEN__
+#include <emscripten/fetch.h>
+typedef emscripten_fetch_t rtclient_response;
+#else
+#include <curl/curl.h>
+typedef struct {
+ void *userData;
+ char *data;
+ size_t numBytes;
+ CURL *curl;
+} rtclient_response;
+#endif
+
+#endif
diff --git a/rtclient/user.h b/rtclient/user.h
index 5f62d17..02b2daa 100644
--- a/rtclient/user.h
+++ b/rtclient/user.h
@@ -1,6 +1,8 @@
#ifndef RTCLIENT_USER_H
#define RTCLIENT_USER_H
+#include "typedefs.h"
+
enum rtclient_user_lang {
RTCLIENT_USER_LANG_NONE = 0,
RTCLIENT_USER_LANG_AR,
@@ -464,9 +466,9 @@ void rtclient_user_new(const char *name,
enum rtclient_user_timezone timezone,
bool disabled,
bool privileged);
- void rtclient_user_showid(struct rtclient_user **userptr, unsigned int id);
- void rtclient_user_showname(struct rtclient_user **userptr, const char *name);
- void rtclient_user_free(struct rtclient_user *user);
+void rtclient_user_showid(unsigned int id, void (*)(struct rtclient_user *));
+void rtclient_user_showname(const char *name, void (*)(struct rtclient_user *));
+void rtclient_user_free(struct rtclient_user *user);
#ifdef __cplusplus
}
diff --git a/search.c b/search.c
index 03ab593..b1a36a0 100644
--- a/search.c
+++ b/search.c
@@ -6,46 +6,38 @@
#endif
#endif
#include <stdlib.h>
+#include <string.h>
#include "request.h"
+#include "rtclient.h"
#include "rtclient/ticket.h"
#include "rtclient/search.h"
-typedef struct rtclient_ticket rtclient_ticket;
-typedef struct rtclient_search_ticket_list rtclient_search_ticket_list;
-
-static size_t ticket_handler(void *contents, size_t size, size_t nmemb
- , void *writedata)
+static void handle_search(rtclient_response *response)
{
- size_t realsize = size * nmemb;
- char response[realsize + 1];
- memcpy(response, contents, realsize);
- response[realsize] = '\0';
- char lines[strlen(response) + 1];
- strcpy(lines, response);
+ char data[response->numBytes];
+ strcpy(data, response->data);
+ char lines[response->numBytes];
+ strcpy(lines, response->data);
- char *line = strtok(response, "\n");
+ char *line = strtok(data, "\n");
if (strstr(line, "200 Ok")) {
line = strtok(NULL, "\n");
size_t length = 0;
do {
length++;
if (!strcmp(line, "No matching results."))
- return realsize;
+ return;
} while ((line = strtok(NULL, "\n")));
- rtclient_search_ticket_list **listptr
- = (rtclient_search_ticket_list **)writedata;
- *listptr = malloc(sizeof(rtclient_search_ticket_list)
- + length * sizeof(rtclient_ticket));
- rtclient_search_ticket_list *list = *listptr;
- list->length = length;
+ struct rtclient_ticket **list
+ = malloc(sizeof(struct rtclient_ticket) * (length + 1));
char *linesaveptr = NULL;
line = strtok_r(lines, "\n", &linesaveptr);
line = strtok_r(NULL, "\n", &linesaveptr);
for (size_t i = 0; i < length; i++) {
- list->tickets[i] = malloc(sizeof(rtclient_ticket));
- rtclient_ticket *ticket = list->tickets[i];
+ list[i] = malloc(sizeof(struct rtclient_ticket));
+ struct rtclient_ticket *ticket = list[i];
char *tokensaveptr = NULL;
char *token = strtok_r(line, ":", &tokensaveptr);
@@ -57,6 +49,8 @@ static size_t ticket_handler(void *contents, size_t size, size_t nmemb
line = strtok_r(NULL, "\n", &linesaveptr);
}
+ list[length] = NULL;
+ ((void (*)(struct rtclient_ticket **))response->userData)(list);
} else {
#ifdef DEBUG
#ifdef __ANDROID__
@@ -67,24 +61,12 @@ static size_t ticket_handler(void *contents, size_t size, size_t nmemb
#endif
#endif
}
-
- return realsize;
-}
-
-void rtclient_search_ticket(rtclient_search_ticket_list **listptr
- , const char *query)
-{
- request(ticket_handler, (void *)listptr, NULL, "%s%s"
- , "REST/1.0/search/ticket?query=", query);
+ rtclient_free_response(response);
}
-void rtclient_search_ticket_free(rtclient_search_ticket_list *list)
+void rtclient_search_ticket(const char *query,
+ void (*callback)(struct rtclient_ticket **))
{
- for (size_t i = 0; i < list->length; i++) {
- rtclient_ticket *ticket = list->tickets[i];
- free(ticket->subject);
- free(ticket);
- }
- free(list);
- list = NULL;
+ request(handle_search, (void (*)(void *))callback, NULL,
+ "%s%s", "REST/1.0/search/ticket?query=", query);
}
diff --git a/ticket.c b/ticket.c
index 9053d71..b3310be 100644
--- a/ticket.c
+++ b/ticket.c
@@ -1,13 +1,15 @@
#if defined __ANDROID__ && defined DEBUG
#include <android/log.h>
#endif
+#include <stdio.h>
#include <stdlib.h>
-#include "post.h"
+#include <string.h>
+#include <time.h>
+#include "request.h"
+#include "rtclient.h"
#include "rtclient/ticket.h"
typedef struct rtclient_ticket rtclient_ticket;
-typedef struct rtclient_ticket_history ticket_history;
-typedef struct rtclient_ticket_history_list history_list;
typedef struct rtclient_ticket_history_attachment history_attachment;
typedef struct rtclient_ticket_history_attachment_list attachment_list;
@@ -26,50 +28,45 @@ void rtclient_ticket_new(const char *queue,
const char *due,
const char *text)
{
- post("REST/1.0/ticket/new", (const char *[]){
- "ticket/new", "id"
- , queue, "Queue"
- , requestor, "Requestor"
- , subject, "Subject"
- , cc, "Cc"
- , admin_cc, "AdminCc"
- , owner, "Owner"
- , status, "Status"
- , priority, "Priority"
- , initial_priority, "InitialPriority"
- , final_priority, "FinalPriority"
- , time_estimated, "TimeEstimated"
- , starts, "Starts"
- , due, "Due"
- , text, "Text"
- }, 28);
+ request(NULL, NULL, &(struct body){ 15, {
+ { "id", "ticket/new" },
+ { "Queue", queue },
+ { "Requestor", requestor },
+ { "Subject", subject },
+ { "Cc", cc },
+ { "AdminCc", admin_cc },
+ { "Owner", owner },
+ { "Status", status },
+ { "Priority", priority },
+ { "InitialPriority", initial_priority },
+ { "FinalPriority", final_priority },
+ { "TimeEstimated", time_estimated },
+ { "Starts", starts },
+ { "Due", due },
+ { "Text", text }
+ }}, "%s", "REST/1.0/ticket/new");
}
-static size_t history_handler(void *contents, size_t size, size_t nmemb
- , void *writedata)
+static void handle_history(rtclient_response *response)
{
- size_t realsize = size * nmemb;
- char response[realsize + 1];
- memcpy(response, contents, realsize);
- response[realsize] = '\0';
+ char data[response->numBytes];
+ strcpy(data, response->data);
char *linesaveptr = NULL;
- char *line = strtok_r(response, "\n", &linesaveptr);
+ char *line = strtok_r(data, "\n", &linesaveptr);
if (strstr(line, "200 Ok")) {
line = strtok_r(NULL, "\n", &linesaveptr);
char *lengthstr = strtok(line, "/");
size_t length = atoi(&lengthstr[2]);
- history_list **listptr = (history_list **)writedata;
- *listptr = malloc(sizeof(history_list)
- + length * sizeof(ticket_history));
- history_list *list = *listptr;
- list->length = length;
+ struct rtclient_ticket_history **list
+ = malloc(sizeof(struct rtclient_ticket_history *)
+ * (length + 1));
for (size_t i = 0; i < length; i++) {
line = strtok_r(NULL, "\n", &linesaveptr);
- list->histories[i] = malloc(sizeof(ticket_history));
- ticket_history *ticket_history = list->histories[i];
+ list[i] = malloc(sizeof(struct rtclient_ticket_history));
+ struct rtclient_ticket_history *ticket_history = list[i];
char *tokensaveptr = NULL;
char *token = strtok_r(line, ":", &tokensaveptr);
@@ -94,6 +91,8 @@ static size_t history_handler(void *contents, size_t size, size_t nmemb
= malloc(sizeof(attachment_list));
ticket_history->attachments->length = 0;
}
+ list[length] = NULL;
+ ((void (*)(struct rtclient_ticket_history **))response->userData)(list);
} else {
#ifdef DEBUG
#ifdef __ANDROID__
@@ -104,33 +103,40 @@ static size_t history_handler(void *contents, size_t size, size_t nmemb
#endif
#endif
}
-
- return realsize;
+ rtclient_free_response(response);
}
-static size_t history_l_handler(void *contents, size_t size, size_t nmemb
- , void *writedata)
+static void handle_history_l(rtclient_response *response)
{
- size_t realsize = size * nmemb;
- char response[realsize + 1];
- memcpy(response, contents, realsize);
- response[realsize] = '\0';
+ char data[response->numBytes];
+ strcpy(data, response->data);
char *linesaveptr = NULL;
- char *line = strtok_r(response, "\n", &linesaveptr);
+ char *line = strtok_r(data, "\n", &linesaveptr);
if (strstr(line, "200 Ok")) {
- history_list **listptr = (history_list **)writedata;
- history_list *list = *listptr;
- for (size_t i = 0; i < list->length; i++) {
- ticket_history *ticket_history = list->histories[i];
- strtok_r(NULL, "\n", &linesaveptr);
- line = strtok_r(NULL, "\n", &linesaveptr);
+ line = strtok_r(NULL, "\n", &linesaveptr);
+ char *tokensaveptr = NULL;
+ strtok_r(line, "/", &tokensaveptr);
+ size_t length = atoi(strtok_r(NULL, "(", &tokensaveptr));
+ struct rtclient_ticket_history **list
+ = malloc(sizeof(struct rtclient_ticket_history *)
+ * (length + 1));
+
+ for (size_t i = 0; i < length; i++) {
line = strtok_r(NULL, "\n", &linesaveptr);
+ if (i)
+ line = strtok_r(NULL, "\n", &linesaveptr);
+ list[i] = malloc(sizeof(struct rtclient_ticket_history));
+ struct rtclient_ticket_history *ticket_history = list[i];
- char *tokensaveptr = NULL;
strtok_r(line, ":", &tokensaveptr);
char *token = strtok_r(NULL, ":", &tokensaveptr);
+ ticket_history->id = atoi(++token);
+ line = strtok_r(NULL, "\n", &linesaveptr);
+
+ strtok_r(line, ":", &tokensaveptr);
+ token = strtok_r(NULL, ":", &tokensaveptr);
ticket_history->ticket = atoi(++token);
line = strtok_r(NULL, "\n", &linesaveptr);
@@ -141,42 +147,60 @@ static size_t history_l_handler(void *contents, size_t size, size_t nmemb
strtok_r(line, ":", &tokensaveptr);
token = strtok_r(NULL, ":", &tokensaveptr);
- enum rtclient_ticket_history_type type
- = ticket_history->type;
if (!strcmp(++token, "AddLink"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_ADD_LINK;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_ADD_LINK;
else if (!strcmp(token, "AddMember"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_ADD_MEMBER;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_ADD_MEMBER;
else if (!strcmp(token, "AddMembership"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_ADD_MEMBERSHIP;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_ADD_MEMBERSHIP;
else if (!strcmp(token, "AddReminder"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_ADD_REMINDER;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_ADD_REMINDER;
else if (!strcmp(token, "AddWatcher"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_ADD_WATCHER;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_ADD_WATCHER;
else if (!strcmp(token, "Comment"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_COMMENT;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_COMMENT;
else if (!strcmp(token, "CommentEmailRecord"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_COMMENT_EMAIL_RECORD;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_COMMENT_EMAIL_RECORD;
else if (!strcmp(token, "Correspond"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_CORRESPOND;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_CORRESPOND;
else if (!strcmp(token, "Create"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_CREATE;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_CREATE;
else if (!strcmp(token, "DelWatcher"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_DEL_WATCHER;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_DEL_WATCHER;
else if (!strcmp(token, "Disabled"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_DISABLED;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_DISABLED;
else if (!strcmp(token, "EmailRecord"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_EMAIL_RECORD;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_EMAIL_RECORD;
else if (!strcmp(token, "ResolveReminder"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_RESOLVE_REMINDER;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_RESOLVE_REMINDER;
else if (!strcmp(token, "Set"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_SET;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_SET;
else if (!strcmp(token, "SetWatcher"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_SET_WATCHER;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_SET_WATCHER;
else if (!strcmp(token, "Status"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_STATUS;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_STATUS;
else if (!strcmp(token, "SystemError"))
- type = RTCLIENT_TICKET_HISTORY_TYPE_SYSTEM_ERROR;
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_SYSTEM_ERROR;
+ else
+ ticket_history->type
+ = RTCLIENT_TICKET_HISTORY_TYPE_NONE;
line = strtok_r(NULL, "\n", &linesaveptr);
strtok_r(line, ":", &tokensaveptr);
@@ -184,23 +208,28 @@ static size_t history_l_handler(void *contents, size_t size, size_t nmemb
if (token && strcmp(token, "")) {
ticket_history->field = malloc(strlen(token));
strcpy(ticket_history->field, ++token);
- }
+ } else
+ ticket_history->field = NULL;
line = strtok_r(NULL, "\n", &linesaveptr);
strtok_r(line, ":", &tokensaveptr);
token = strtok_r(NULL, ":", &tokensaveptr);
if (token && strcmp(token, "")) {
- ticket_history->old_value = malloc(strlen(token));
+ ticket_history->old_value
+ = malloc(strlen(token));
strcpy(ticket_history->old_value, ++token);
- }
+ } else
+ ticket_history->old_value = NULL;
line = strtok_r(NULL, "\n", &linesaveptr);
strtok_r(line, ":", &tokensaveptr);
token = strtok_r(NULL, ":", &tokensaveptr);
if (token && strcmp(token, "")) {
- ticket_history->new_value = malloc(strlen(token));
+ ticket_history->new_value
+ = malloc(strlen(token));
strcpy(ticket_history->new_value, ++token);
- }
+ } else
+ ticket_history->new_value = NULL;
line = strtok_r(NULL, "\n", &linesaveptr);
strtok_r(line, ":", &tokensaveptr);
@@ -208,9 +237,18 @@ static size_t history_l_handler(void *contents, size_t size, size_t nmemb
if (token && strcmp(token, "")) {
ticket_history->data = malloc(strlen(token));
strcpy(ticket_history->data, ++token);
- }
+ } else
+ ticket_history->data = NULL;
line = strtok_r(NULL, "\n", &linesaveptr);
+ strtok_r(line, ":", &tokensaveptr);
+ token = strtok_r(NULL, ":", &tokensaveptr);
+ if (token && strcmp(token, "")) {
+ ticket_history->description
+ = malloc(strlen(token));
+ strcpy(ticket_history->description, ++token);
+ } else
+ ticket_history->description = NULL;
line = strtok_r(NULL, "\n", &linesaveptr);
strtok_r(line, ":", &tokensaveptr);
@@ -220,9 +258,9 @@ static size_t history_l_handler(void *contents, size_t size, size_t nmemb
strcpy(content, ++token);
line = strtok_r(NULL, "\n", &linesaveptr);
while (strncmp(line, "Creator", 7)) {
- ticket_history->content = realloc(content
- , strlen(content)
- + strlen(line) + 2);
+ ticket_history->content = realloc(content,
+ strlen(content) + strlen(line)
+ + 2);
content = ticket_history->content;
sprintf(content, "%s\n%s", content, line);
line = strtok_r(NULL, "\n", &linesaveptr);
@@ -259,16 +297,19 @@ static size_t history_l_handler(void *contents, size_t size, size_t nmemb
if (!token)
break;
+ ticket_history->attachments
+ = malloc(sizeof(attachment_list));
+ ticket_history->attachments->length = 0;
size_t i = 0;
while (strcmp(line, "--")) {
ticket_history->attachments
- = realloc(ticket_history->attachments
- , sizeof
- (attachment_list)
+ = realloc(ticket_history->attachments,
+ sizeof(attachment_list)
+ (i + 1)
* sizeof
(history_attachment));
- attachment_list *list = ticket_history->attachments;
+ attachment_list *list
+ = ticket_history->attachments;
list->length++;
list->attachments[i]
= malloc(sizeof(history_attachment));
@@ -296,6 +337,9 @@ static size_t history_l_handler(void *contents, size_t size, size_t nmemb
token = strtok_r(line, ": ()", &tokensaveptr);
}
}
+ list[length] = NULL;
+ ((void (*)(struct rtclient_ticket_history **))
+ response->userData)(list);
} else {
#ifdef DEBUG
#ifdef __ANDROID__
@@ -306,21 +350,22 @@ static size_t history_l_handler(void *contents, size_t size, size_t nmemb
#endif
#endif
}
-
- return realsize;
+ rtclient_free_response(response);
}
-void rtclient_ticket_history(history_list **listptr
- , unsigned int id, bool long_format)
+void rtclient_ticket_history_list(unsigned int id, bool long_format,
+ void (*callback)(struct rtclient_ticket_history **))
{
- request(history_handler, (void *)listptr, NULL, "%s%u%s"
- , "REST/1.0/ticket/", id, "/history");
if (long_format)
- request(history_l_handler, (void *)listptr, NULL, "%s%u%s"
- , "REST/1.0/ticket/", id, "/history?format=l");
+ request(handle_history_l, (void (*)(void *))callback, NULL,
+ "%s%u%s", "REST/1.0/ticket/", id,
+ "/history?format=l");
+ else
+ request(handle_history, (void (*)(void *))callback, NULL,
+ "%s%u%s", "REST/1.0/ticket/", id, "/history");
}
-void rtclient_ticket_history_free(ticket_history *history)
+void rtclient_ticket_history_free(struct rtclient_ticket_history *history)
{
attachment_list *list = history->attachments;
for (size_t i = 0; i < list->length; i++) {
@@ -345,11 +390,3 @@ void rtclient_ticket_history_free(ticket_history *history)
free(history);
history = NULL;
}
-
-void rtclient_ticket_history_list_free(history_list *list)
-{
- for (size_t i = 0; i < list->length; i++)
- rtclient_ticket_history_free(list->histories[i]);
- free(list);
- list = NULL;
-}
diff --git a/user.c b/user.c
index c40c2e9..d4347c6 100644
--- a/user.c
+++ b/user.c
@@ -6,12 +6,12 @@
#endif
#endif
#include <stdlib.h>
+#include <string.h>
#include <stdbool.h>
-#include "post.h"
+#include "request.h"
+#include "rtclient.h"
#include "rtclient/user.h"
-typedef struct rtclient_user rtclient_user;
-
void rtclient_user_new(const char *name,
const char *password,
const char *email_address,
@@ -37,46 +37,40 @@ void rtclient_user_new(const char *name,
bool disabled,
bool privileged)
{
- post("REST/1.0/user/new", (const char *[]){
- name, "Name"
- , password, "Password"
- , email_address, "EmailAddress"
- , real_name, "RealName"
- , nick_name, "NickName"
- , organization, "Organization"
- , address1, "Address1"
- , address2, "Address2"
- , city, "City"
- , state, "State"
- , zip, "Zip"
- , country, "Country"
- , home_phone, "HomePhone"
- , work_phone, "WorkPhone"
- , mobile_phone, "MobilePhone"
- , pager_phone, "PagerPhone"
- , contact_info, "ContactInfo"
- , comments, "Comments"
- , signature, "Signature"
- , gecos, "Gecos"
- }, 40);
+ request(NULL, NULL, &(struct body){ 20, {
+ { "Name", name },
+ { "Password", password },
+ { "EmailAddress", email_address },
+ { "RealName", real_name },
+ { "NickName", nick_name },
+ { "Organization", organization },
+ { "Address1", address1 },
+ { "Address2", address2 },
+ { "City", city },
+ { "State", state },
+ { "Zip", zip },
+ { "Country", country },
+ { "HomePhone", home_phone },
+ { "WorkPhone", work_phone },
+ { "MobilePhone", mobile_phone },
+ { "PagerPhone", pager_phone },
+ { "ContactInfo", contact_info },
+ { "Comments", comments },
+ { "Signature", signature },
+ { "Gecos", gecos }
+ }}, "%s", "REST/1.0/user/new");
}
-static size_t show_handler(void *contents, size_t size, size_t nmemb
- , void *writedata)
+static void handle_show(rtclient_response *response)
{
- size_t realsize = size * nmemb;
- char response[realsize + 1];
- memcpy(response, contents, realsize);
- response[realsize] = '\0';
+ char data[response->numBytes];
+ strcpy(data, response->data);
char *linesaveptr = NULL;
- char *line = strtok_r(response, "\n", &linesaveptr);
+ char *line = strtok_r(data, "\n", &linesaveptr);
if (strstr(line, "200 Ok")) {
line = strtok_r(NULL, "\n", &linesaveptr);
-
- rtclient_user **userptr = (rtclient_user **)writedata;
- *userptr = malloc(sizeof(rtclient_user));
- rtclient_user *user = *userptr;
+ struct rtclient_user *user = malloc(sizeof(struct rtclient_user));
user->password = NULL;
user->email_address = NULL;
user->real_name = NULL;
@@ -100,7 +94,6 @@ static size_t show_handler(void *contents, size_t size, size_t nmemb
user->timezone = RTCLIENT_USER_TIMEZONE_NONE;
user->privileged = false;
user->disabled = true;
-
do {
char *tokensaveptr = NULL;
char *token = strtok_r(line, ":", &tokensaveptr);
@@ -192,6 +185,7 @@ static size_t show_handler(void *contents, size_t size, size_t nmemb
user->disabled = (bool)atoi(++token);
}
} while ((line = strtok_r(NULL, "\n", &linesaveptr)));
+ ((void (*)(struct rtclient_user *))response->userData)(user);
} else {
#ifdef DEBUG
#ifdef __ANDROID__
@@ -202,22 +196,20 @@ static size_t show_handler(void *contents, size_t size, size_t nmemb
#endif
#endif
}
-
- return realsize;
+ rtclient_free_response(response);
}
-void rtclient_user_showid(rtclient_user **userptr, unsigned int id)
+void rtclient_user_showid(unsigned int id, void (*callback)(struct rtclient_user *))
{
- request(show_handler, (void *)userptr, NULL, "%s%u", "REST/1.0/user/", id);
+ request(handle_show, (void (*)(void *))callback, NULL, "%s%u", "REST/1.0/user/", id);
}
-void rtclient_user_showname(rtclient_user **userptr, const char *name)
+void rtclient_user_showname(const char *name, void (*callback)(struct rtclient_user *))
{
- request(show_handler, (void *)userptr, NULL, "%s%s", "REST/1.0/user/"
- , name);
+ request(handle_show, (void (*)(void *))callback, NULL, "%s%s", "REST/1.0/user/", name);
}
-void rtclient_user_free(rtclient_user *user)
+void rtclient_user_free(struct rtclient_user *user)
{
if (user->gecos)
free(user->gecos);