#include #include #include #include #include #include #define APP_NAME "wassr_todo" #ifdef _WIN32 # ifndef snprintf # define snprintf _snprintf # endif #endif #define TODO_MODIFY_URL "http://api.wassr.jp/todo/" #define TODO_JSON_EXT ".json" static char* response_cond = NULL; /* response condition */ static char* response_mime = NULL; /* response content-type. ex: "text/html" */ static char* response_data = NULL; /* response data from server. */ static size_t response_size = 0; /* response size of data */ static void initialize_http_response() { response_cond = NULL; response_mime = NULL; response_data = NULL; response_size = 0; } static void terminate_http_response() { if (response_cond) free(response_cond); if (response_mime) free(response_mime); if (response_data) free(response_data); response_cond = NULL; response_mime = NULL; response_data = NULL; response_size = 0; } static size_t handle_returned_data(char* ptr, size_t size, size_t nmemb, void* stream) { if (!response_data) response_data = (char*)malloc(size*nmemb); else response_data = (char*)realloc(response_data, response_size+size*nmemb); if (response_data) { memcpy(response_data+response_size, ptr, size*nmemb); response_size += size*nmemb; } return size*nmemb; } static size_t handle_returned_header(void* ptr, size_t size, size_t nmemb, void* stream) { char* header = NULL; header = (char*)malloc(size*nmemb + 1); memcpy(header, ptr, size*nmemb); header[size*nmemb] = 0; if (strncmp(header, "Content-Type: ", 14) == 0) { char* stop = header + 14; stop = strpbrk(header + 14, "\r\n;"); if (stop) *stop = 0; if (response_mime) free(response_mime); response_mime = strdup(header + 14); } if (strncmp(header, "Last-Modified: ", 15) == 0) { char* stop = strpbrk(header, "\r\n;"); if (stop) *stop = 0; if (response_cond) free(response_cond); response_cond = strdup(header); } if (strncmp(header, "ETag: ", 6) == 0) { char* stop = strpbrk(header, "\r\n;"); if (stop) *stop = 0; if (response_cond) free(response_cond); response_cond = strdup(header); } free(header); return size*nmemb; } char* get_http_data(char* url, char* user, char* pass) { CURLcode res; CURL* curl; char* ret = NULL; int status = 0; char auth[512]; initialize_http_response(); memset(auth, 0, sizeof(auth)); snprintf(auth, sizeof(auth)-1, "%s:%s", user, pass); curl = curl_easy_init(); if (!curl) return NULL; curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_USERPWD, auth); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handle_returned_header); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curl, CURLOPT_USERAGENT, APP_NAME); res = curl_easy_perform(curl); res = res == CURLE_OK ? curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &status) : res; curl_easy_cleanup(curl); if (res == CURLE_OK && status == 200) { ret = (char*)malloc(response_size+1); memset(ret, 0, response_size+1); memcpy(ret, (char*)response_data, response_size); } terminate_http_response(); return ret; } char* post_http_data(char* url, char* user, char* pass, char* data) { CURLcode res; CURL* curl; char* ret = NULL; int status = 0; char auth[512]; initialize_http_response(); memset(auth, 0, sizeof(auth)); snprintf(auth, sizeof(auth)-1, "%s:%s", user, pass); curl = curl_easy_init(); if (!curl) return NULL; curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_USERPWD, auth); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handle_returned_header); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curl, CURLOPT_USERAGENT, APP_NAME); curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (void*)data); res = curl_easy_perform(curl); res = res == CURLE_OK ? curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &status) : res; curl_easy_cleanup(curl); if (res == CURLE_OK && status == 200) { ret = (char*)malloc(response_size+1); memset(ret, 0, response_size+1); memcpy(ret, (char*)response_data, response_size); } terminate_http_response(); return ret; } char* string_to_utf8_alloc(const char* str) { if (!str) return NULL; #ifdef WIN32 UINT codePage; size_t in_len = strlen(str); codePage = GetACP(); size_t wcssize = MultiByteToWideChar(codePage, 0, str, in_len, NULL, 0); wchar_t* pszStrWC = (wchar_t*)malloc(sizeof(wchar_t)*(wcssize + 1)); wcssize = MultiByteToWideChar(codePage, 0, str, in_len, pszStrWC, wcssize + 1); pszStrWC[wcssize] = '\0'; codePage = CP_UTF8; size_t mbssize = WideCharToMultiByte(codePage, 0, pszStrWC, -1, NULL, 0, NULL, NULL); char* pszStrMB = (char*)malloc(mbssize + 1); mbssize = WideCharToMultiByte(codePage, 0, pszStrWC, -1, pszStrMB, mbssize, NULL, NULL); pszStrMB[mbssize] = '\0'; free(pszStrWC); return pszStrMB; #else return strdup(str); #endif } char* utf8_to_string_alloc(const char* str) { if (!str) return NULL; #ifdef WIN32 UINT codePage = CP_UTF8; const char* ptr = str; if (str[0] == (char)0xef && str[1] == (char)0xbb && str[2] == (char)0xbf) ptr += 3; size_t wcssize = MultiByteToWideChar(codePage, 0, ptr, -1, NULL, 0); wchar_t* pszStrWC = (wchar_t*)malloc(sizeof(wchar_t)*(wcssize + 1)); wcssize = MultiByteToWideChar(codePage, 0, ptr, -1, pszStrWC, wcssize + 1); pszStrWC[wcssize] = '\0'; codePage = GetACP(); size_t mbssize = WideCharToMultiByte(codePage, 0, pszStrWC,-1, NULL, 0, NULL, NULL); char* pszStrMB = (char*)malloc(mbssize + 1); mbssize = WideCharToMultiByte(codePage, 0, pszStrWC, -1, pszStrMB, mbssize, NULL, NULL); pszStrMB[mbssize] = '\0'; free(pszStrWC); return pszStrMB; #else return strdup(str); #endif } static char* url_encode_alloc(const char* str) { static const int force_encode_all = TRUE; const char* hex = "0123456789abcdef"; char* buf = NULL; unsigned char* pbuf = NULL; int len = 0; if (!str) return NULL; len = strlen(str)*3; buf = (char*)malloc(len+1); memset(buf, 0, len+1); pbuf = (unsigned char*)buf; while(*str) { unsigned char c = (unsigned char)*str; if (c == ' ') *pbuf++ = '+'; else if (c & 0x80 || force_encode_all) { *pbuf++ = '%'; *pbuf++ = hex[c >> 4]; *pbuf++ = hex[c & 0x0f]; } else *pbuf++ = c; str++; } return buf; } char* add_todo(char* user, char* pass, char* body) { int size; char* body_utf8; char* body_data; char* post; char* data; body_utf8 = string_to_utf8_alloc(body); if (!body_utf8) return NULL; body_data = url_encode_alloc(body_utf8); free(body_utf8); size = 5 + strlen(body_data); post = (char*)malloc(size + 1); memset(post, 0, size + 1); strcpy(post, "body="); strcat(post, body_data); free(body_data); data = post_http_data("http://api.wassr.jp/todo/add.json", user, pass, post); free(post); return data; } char* modify_todo(char* user, char* pass, char* command, char* todo_rid) { int size; char* url; char* post; char* data; size = 9 + strlen(todo_rid); post = (char*)malloc(size + 1); memset(post, 0, size + 1); strcpy(post, "todo_rid="); strcat(post, todo_rid); size = strlen(TODO_MODIFY_URL) + strlen(command) + strlen(TODO_JSON_EXT); url = (char*)malloc(size + 1); memset(url, 0, size + 1); strcpy(url, TODO_MODIFY_URL); strcat(url, command); strcat(url, TODO_JSON_EXT); data = post_http_data(url, user, pass, post); free(post); free(url); return data; } char* list_todo(char* user, char* pass, int done_fg) { char* data; if (done_fg) data = get_http_data("http://api.wassr.jp/todo/list.json?done_fg=1", user, pass); else data = get_http_data("http://api.wassr.jp/todo/list.json?done_fg=0", user, pass); if (!data) { perror("Unknown server response(server down or invalid authenticate?)"); return NULL; } return data; } int main(int argc, char* argv[]) { FILE* fp = NULL; char* home = NULL; char* user = NULL; char* pass = NULL; char conf[_MAX_PATH]; char buff[BUFSIZ]; char* data = NULL; struct json_object* obj = NULL; struct json_object* res = NULL; int i; home = getenv("HOME"); if (!home) home = getenv("USERPROFILE"); snprintf(conf, sizeof(conf), "%s/.wassr-todo", home); fp = fopen(conf, "rt"); if (!fp) { perror("404 ~/.wassr-todo NOT FOUND"); goto error; } while(fgets(buff, sizeof(buff), fp)) { char *ptr = strpbrk(buff, "\r\n"); if (*ptr) *ptr = 0; if (!strncmp(buff, "username: ", 10)) user = strdup(buff + 10); if (!strncmp(buff, "password: ", 10)) pass = strdup(buff + 10); } fclose(fp); if (argc == 1) data = list_todo(user, pass, FALSE); else { if (argc == 2 && !strcmp(argv[1], "list")) data = list_todo(user, pass, FALSE); else if (argc == 2 && !strcmp(argv[1], "listdone")) data = list_todo(user, pass, TRUE); else if (argc == 3 && !strcmp(argv[1], "add")) data = add_todo(user, pass, argv[2]); else if (argc == 3 && ( !strcmp(argv[1], "delete") || !strcmp(argv[1], "start") || !strcmp(argv[1], "stop") || !strcmp(argv[1], "done"))) data = modify_todo(user, pass, argv[1], argv[2]); else { puts("usage: wassr_todo [command] [argument]"); puts("\t* command"); puts("\t\tlist\t\tlist todo."); puts("\t\tlistdone\tlist todo which is done."); puts("\t\tadd [body]\tpost new todo to wassr."); puts("\t\tdelete [rid]\tdelete the todo."); puts("\t\tstart [rid]\tstart the todo."); puts("\t\tstop [rid]\tstop the todo."); puts("\t\tdone [rid]\tdone the todo."); goto error; } } if (!data) { perror("Unknown server response(server down or invalid authenticate?)"); goto error; } obj = json_tokener_parse(data); free(data); if (is_error(obj)) { perror("Unknown server response(not json?)"); goto error; } if (json_object_is_type(obj, json_type_object)) { res = json_object_object_get(obj, "error"); if (!is_error(res)) { char* _res = utf8_to_string_alloc(json_object_get_string(res)); if (_res) { printf("error: %s\n", _res); free(_res); goto error; } } res = json_object_object_get(obj, "message"); if (!is_error(res)) { char* _res = utf8_to_string_alloc(json_object_get_string(res)); if (_res) { printf("message: %s\n", _res); free(_res); } } } if (json_object_is_type(obj, json_type_array)) { for(i = 0; i < json_object_array_length(obj); i++) { struct json_object *item = json_object_array_get_idx(obj, i); struct json_object* todo_rid = json_object_object_get(item, "todo_rid"); struct json_object* body = json_object_object_get(item, "body"); if (!is_error(todo_rid) && !is_error(body)) { char* _todo_rid = utf8_to_string_alloc(json_object_get_string(todo_rid)); char* _body = utf8_to_string_alloc(json_object_get_string(body)); printf("TODO-%03d [%s] %s\n", i+1, _todo_rid, _body); free(_todo_rid); free(_body); } } } else if (json_object_is_type(obj, json_type_object)) { struct json_object* todo_rid = json_object_object_get(obj, "todo_rid"); if (!is_error(todo_rid)) { char* _todo_rid = utf8_to_string_alloc(json_object_get_string(todo_rid)); if (_todo_rid) { printf("%s\n", _todo_rid); free(_todo_rid); } } } return 0; error: if (user) free(user); if (pass) free(pass); return -1; }