2008/02/14


Flickr Uploadrがオープンソースで公開された模様です。
Flickr Uploadr: Open Source and Powered by XULRunner (Yahoo! Developer Network blog)
Flickr Uploadrは昔からあったのですが、XULを使ったオープンソースアプリケーションとして公開されました。
ライセンスはGPLv2で、ライセンスに従えば改造して公開する事も出来る様になりました。

ただし日本語ロケールがない。
中身を見るとそんなに量がなかったので、えいや!と翻訳してみました。
mattnが「日本だったらこういう言い回しだよなぁ」っていう感じで意訳しています。間違ってたら教えてください。
以下その翻訳物のインストール方法です。Windowsの場合のみ説明しますが、おそらく他の環境でも同じ様な作業になるかと思います。

続きを読む...

Posted at by



2008/02/13


ShareOnTumblr
「CShellExt::QueryContextMenu」でやれば出来なく無いけどコストがデカイし別のシェルエクステンション混ぜると落ちたりするんですよね。
Gyazowin tumblr for Windowsにファイルのアップロード機能を追加して名前をGyamblr for Windowsに変更 « ZeroMemory
Windowsのコンテキストメニューのコピーとかにcopy to tumblrみたいなのを追加できないかなと思ったんだけど、標準のやつはともかくアプリケーションの右クリックはアプリケーション管轄で制御されていてWindowsシロウト同然の自分には外からいじれなそうだったのであきらめました。
本当は「CShellExt::QueryContextMenu」でやるのがいいんだろうけど、今回はコマンドラインユーザでも使える様にコマンド形式で「送る」に登録する方法にした。

続きを読む...

Posted at by



2008/02/08


まぁ、id:tokuhirom氏が作ったwassr-todo.plがあるんですが...
(いいんです。C言語が書きたいんです!)

でっかく記事いっぱいにコードだけ...


ちなみに、json-cというライブラリとcURLを使っています。
昨日のパッチを使えばVC6でもビルド出来ます。
よろしければどうぞ。

最新ソースはCodeReposのコノ辺におきました。

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <curl/curl.h>
#include <json.h>

#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;
}
Posted at by