GoでTwitter

Goでつぶやくコマンドを書いてみたよ。http.Postを使おうとしたけどヘッダ(ベーシック認証)の設定が出来ないようなのでnetパッケージを使った。あとhttp.URLEscapeが日本語未対応なので英語メッセージしか送れないw SSLもまだか
(追記2) 内部文字コードunicodeなのね。unicodeからutf-8に変換してエンコードする処理書いたので日本語もOK
(追記3) stringはutf-8だった。rangeで取り出すとunicode(ucs-2)になるのか
(追記4) crypto/tlsがあった
twitter.go (USERとPASSを書き換えてね)

package main

import (
    "os";
    "net";
    "flag";
    "strings";
    "fmt";
    "io";
    "bufio";
    "strconv";
    "encoding/base64";
)

const (
    USER = "ユーザ";
    PASS = "パスワード";
    CRLF = "\r\n";
)

func encode(str string) (enc string) {
    var s = "";
    for pos, char := range str {
        if char <= 0x007f {
            s = fmt.Sprintf("%c", str[pos]);
	} else if char >= 0x0080 && char <= 0x07ff {
            b0 := char & 0x07c0 >> 6 + 0xc0;
            b1 := char & 0x003f + 0x80;
            s = fmt.Sprintf("%%%x%%%x", b0, b1);
	} else if char >= 0x0800 && char <= 0xffff {
            b0 := char & 0xf000 >> 12 + 0xe0;
            b1 := char & 0x0fc0 >> 6 + 0x80;
            b2 := char & 0x003f + 0x80;
            s = fmt.Sprintf("%%%x%%%x%%%x", b0, b1, b2);
	}
        enc += s;
    }
    return enc;
}

func main() {
    var result = 1;

    flag.Parse();

    if flag.NArg() != 1 {
        fmt.Println("Usage: twitter \"message\"");
        os.Exit(result);
    }

    // basic auth
    userinfo := USER + ":" + PASS;
    buf := make([]byte, base64.StdEncoding.EncodedLen(len(userinfo)));
    base64.StdEncoding.Encode(buf, strings.Bytes(userinfo));
    auth := string(buf);

    // body data
    body := "status=" + encode(flag.Arg(0));
    bodylen := strconv.Itoa(len(body));

    // request message
    req := "POST /statuses/update.xml HTTP/1.1" + CRLF
         + "Host: twitter.com" + CRLF
         + "User-Agent: Go" + CRLF
         + "Content-Type: application/x-www-form-urlencoded" + CRLF
         + "Authorization: Basic " + auth + CRLF
         + "Content-Length: " + bodylen + CRLF
         + CRLF
         + body;

    // connect
    conn, err := net.Dial("tcp", "", "twitter.com:80");
    if err != nil {
        os.Exit(result);
    }

    // send request
    io.WriteString(conn, req);

    // receive response
    reader := bufio.NewReader(conn);
    if line, err := reader.ReadString('\n'); err == nil {
        if line == "HTTP/1.1 200 OK" + CRLF {
	   result = 0;
	}
	fmt.Print(line);
    }

    conn.Close();
    os.Exit(result);
}

ビルド

$ 8g twitter.go
$ 8l -o twitter twitter.8

使い方

$ ./twitter "from Go"
HTTP/1.1 200 OK

「HTTP/1.1 200 OK」が表示されたらつぶやき成功

(追記1) ステータスコードの判定が間違ってたので直した