Hatena::ブログ(Diary)

Fly me to the Juno! このページをアンテナに追加 RSSフィード

2007-11-30

Gmailに認証後にメッセージの詳細を取得する

Gmailはメッセージの一覧をAtomで配信している。なので、メッセージのIDが埋め込まれたURLはそこから取得することができるが、そのままURLをブラウザに渡すとまだ認証されていないため、認証画面が出てくる。どうにかこうにかしてこの画面をすっ飛ばしたいなと思って書いたのが次のコード。例のごとくJUnit4です。で、CookieManagerを使いたかったので、Java6使ってます。もしあれだったらApache CommonsのHttpClientあたりを使うようにすればJava1.4くらいでも動きそうですな。それとHTMLのパースにJericho HTML Parser、ウィジェットにはSWTを使ってます。

public class LearningGmailConnection {
  private String email = "******";
  private String passwd = "*****";
  private String messageId = "******";
  
  private static String loginformId = "gaia_loginform";
  private static String gmailLoginURL = "https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fmail%2F%3Fui%3Dhtml%26zy%3Dl&ltmpl=default&ltmplcache=2";

  @Test
  public void learningGmailURL() throws Exception {
    CookieManager manager = new CookieManager();
    manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
    CookieHandler.setDefault(manager);

    URL url = new URL(gmailLoginURL);
    Source source = new Source(url);
    List<?> forms = source.findAllElements(Tag.FORM);
    for (Iterator<?> itr = forms.iterator(); itr.hasNext();) {
      Element form = (Element) itr.next();
      if (loginformId.equals(form.getAttributeValue("id"))) {
        authenticationToGmail(form);
        
      }
    }
        String script = makeCookies(manager);
    url = new URL(messageId);
    showBrowser(url,script);
  }


  private void authenticationToGmail(Element form)
      throws MalformedURLException, IOException, ProtocolException {
    URL action = new URL(form.getAttributeValue("action"));
    HttpURLConnection con = (HttpURLConnection) action
        .openConnection();
    con.setRequestMethod("POST");

    List<?> tags = form.findAllElements(Tag.INPUT);
    
    con.setDoOutput(true);
    DataOutputStream outStream = new DataOutputStream(con
        .getOutputStream());
    String params = buildParameters(tags);
    byte[] bytes = params.getBytes();
    outStream.write(bytes, 0, bytes.length);
    con.connect();
    BufferedReader br = new BufferedReader(new InputStreamReader(
        con.getInputStream()));
    while (br.readLine() != null){}
    con.disconnect();
  }

  private String buildParameters(List<?> tags) {
    StringBuilder builder = new StringBuilder(
        "Email=" + email + "&Passwd=" + passwd);
    for (Iterator<?> iitr = tags.iterator(); iitr.hasNext();) {
      Element tag = (Element) iitr.next();
      if ("hidden".equals(tag.getAttributeValue("type"))) {
        String name = tag.getAttributeValue("name");
        String value = tag.getAttributeValue("value");
        builder.append("&");
        builder.append(name);
        builder.append("=");
        builder.append(value);
      }
    }
    return builder.toString();
  }

  private String makeCookies(CookieManager manager) {
    CookieStore store = manager.getCookieStore();
    List<HttpCookie> cookies = store.getCookies();
    StringBuilder scriptBuilder = new StringBuilder();
    for (int i = 0; i < cookies.size(); i++) {
        HttpCookie cookie = cookies.get(i);
        scriptBuilder.append(createCookieScript(cookie));
    }
    String script = scriptBuilder.toString();
    return script;
  }

  private String createCookieScript(HttpCookie cookie) {
    StringBuilder builder = new StringBuilder("document.cookie=\"");
    builder.append(cookie.getName());
    builder.append("=");
    builder.append(cookie.getValue());
    builder.append(";");
    String domain = cookie.getDomain();
    if(domain != null){
      builder.append("domain=");
      builder.append(domain);
      builder.append(";");
    }
    builder.append("\"\n");
    return builder.toString();
  }
  
  private void showBrowser(URL url, String script) {
    showBrowser(url, null, script);
  }


  private void showBrowser(URL url, String html,String script) {
    if(url == null && html == null){
      throw new NullPointerException("url or html, which one is needed.");
    }
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    Browser browser = new Browser(shell, SWT.NONE);
    if(script != null){
      browser.execute(script);
    }
    if(url != null){
      browser.setUrl(url.toString());
    }
    if(html != null){
      browser.setText(html);
    }
    shell.open();

    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }

    display.dispose();
  }
}

前のエントリで書いたとおり、認証画面をどうにかこうにかしてPOSTすることでクッキーを取得し、それをブラウザに食わせるというやり方をとってみたらすんなりうまくいった。他のサイトでもFormで認証させる場合は同様のやり方でいける。

このコードを見ている限りコードの基盤はオブジェクト指向というよりも構造化なんだよなと思った。構造化されたコードをわかりやすく分類したものがクラスで、そのメッセージの飛ばし具合がオブジェクト指向っていうのがクラスベースオブジェクト指向。インスタンスベースオブジェクト指向はそもそもインスタンスがあるよねっていう世界だからJavaには合わないね。脱線。

2007-11-13

こみゅすけから参加者一覧を取得する

EclipsePlugin勉強会の参加者が増えてないかなーとわくわくしながらこみゅすけにアクセスしていたのだけれども、ふとHTMLで一覧を出力してくれないかなーと思った。よく考えてみたら、こみゅすけはAjaxを駆使して作られている。ん?そういえば一覧は不思議な動きをするぞ?

ということで、FireFoxのアドイン「Live HTTP headers」でどういうリクエストとレスポンスが飛んでるか見てみたら、受け口とJSONで通信していることがわかった。こみゅすけの管理人、よういちろうさんから公開してよいとお許しが出たので、駄コードをさらしてみる。例によってJUnit4を実行するランチャとして使ってみた。

package learning;

import static org.junit.Assert.assertNotNull;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Date;

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.junit.Test;

public class JSONLearning {

  @Test
  public void leaningJSON() throws Exception {
    // 2007 11 EclipsePlugin勉強会
    String meetingId = "57";
    URL url = new URL("http://commusuke.eisbahn.jp/ajax/attendances/"+meetingId);
    assertNotNull(url);
    BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
    String line = reader.readLine();
    JSONTokener tokener = new JSONTokener(line);
    JSONObject value = (JSONObject) tokener.nextValue();
    JSONArray array = value.getJSONArray("attendances");
    for(int i = 0; i < array.length(); i++){
      JSONObject jsonObject = array.getJSONObject(i);
      String name = jsonObject.getString("nick_name");
      String comment = jsonObject.getString("comment");
      Date date = new Date();
      long time = jsonObject.getLong("updated_at");
      date.setTime(time * 1000L);
      String formated = String.format("[%tF]%s:%s", date,name,comment);
      System.out.println(formated);
    }
  }
}

使用したJSONのライブラリorg.jsonを使ってみた。json-libも試したけど、とってもFatで使え切れません。

2007-11-01

ECF Learning

JUnit4の勉強と、ECFの勉強を兼ねて書いたコードを晒してみる。

ECFは幾つかのプロトコルのfacade役をしてくれるプラグイン。

今回晒したのはXMPPの例。GTalkやJabberサーバーに接続して、

通信をすることができる。

例えば21行目の"ecf.xmpp.smack"を"ecf.call.skype"にすると、

Skypeプラグインが導入されている環境ではSkypeを使って通信できる。

なお、ユーザー名とパスワードは適当に置き換えてくださいませ。


public class XMPPLearning {
    private XMPPContainer container;

    @SuppressWarnings("unchecked")
    public void learningXMPPRoasterAPI() throws Exception{
        connect();
        IRoster roster = container.getRosterManager().getRoster();
        System.out.println(roster.getUser().getName());
        Thread.sleep(1000);
        Collection items = roster.getItems();
        System.out.println(items.size());
        for(Object o : items){
            System.out.println(o);
        }
    }
    
    @Before
    public void createContainer(){
        IContainer c = null;
        try {
            c  = ContainerFactory.getDefault().createContainer("ecf.xmpp.smack");
        } catch (ContainerCreateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        assertNotNull(c);
        assertTrue(c instanceof XMPPContainer);
        container = (XMPPContainer) c;

    }
    
    @After
    public void disconnectContainer(){
        container.disconnect();        
    }
    
    @SuppressWarnings("unchecked")
    public void learningXMPPChatRoomAPI() throws Exception{
        connect();
        Map properties = new HashMap();
//        IChatRoomInfo info = container.getChatRoomManager().createChatRoom("kompiroroom", properties );
//        assertNotNull(info);
        String connectID = "kompiro@gmail.com";
        ID targetID = IDFactory.getDefault().createID(container.getConnectNamespace(), connectID);
        IIMMessageListener messageListener = new IIMMessageListener(){

            public void handleMessageEvent(IIMMessageEvent messageEvent) {
                System.out.println(messageEvent.toString());
                assertTrue(messageEvent instanceof IChatMessageEvent);
                IChatMessageEvent e = (IChatMessageEvent) messageEvent;
                System.out.println(e.getChatMessage());
            }
            
        };
        IChatMessageSender chatMessageSender = container.getChatManager().getChatMessageSender();
        chatMessageSender.sendChatMessage(targetID, "hello!");
        
    }

    @Test
    public void learningXMPPSharedObjectAPI() throws Exception{
        connect();
        Thread.sleep(2000);
        ID[] ids = container.getSharedObjectManager().getSharedObjectIDs();
        assertEquals(1,ids.length);
        System.out.println(ids[0]);
    }

    
    public void learningXMPPDataShareAPI() throws Exception{
        connect();
//        Thread.sleep(2000);
        IChannelContainerAdapter channelConntainerAdapter = (IChannelContainerAdapter) container.getAdapter(IChannelContainerAdapter.class);
        assertNotNull(channelConntainerAdapter);
        IChannelConfig newChannelConfig = new BaseChannelConfig();
        IChannel channel = channelConntainerAdapter.createChannel(newChannelConfig);
        assertNotNull(channel);
        channel.sendMessage("test".getBytes());
    }

    private void connect() throws IDCreateException, ContainerConnectException {
        String connectID = "kompiro1206@gmail.com";
        IConnectContext connectContext = ConnectContextFactory.createUsernamePasswordConnectContext(connectID, "fopcc17m");
        ID targetID = IDFactory.getDefault().createID(container.getConnectNamespace(), connectID);
        container.connect(targetID, connectContext);
    }

}

2007-10-29

TelnetClientって難しい?

Telnet接続をするためのラーニングコードを書いた。

でも下記の問題がどうにもならないし、どこから手をつけていいかさっぱりわからない

。- lsなどを実行すると各要素の前後に変な文字列が表示される。これってカラーコード?例を示したかったんですが、エントリ全体が文字化けするのでやめました。

  • ログアウトしてもDisconnectされない
  • viなどスクリーン編集したくても、うまくスクロールを制御できない。

TeraTermのコードを覗いてみたが、さっぱりわからない。どうしたらいいのか途方にくれた。標準入力から標準出力へ流すだけのコードをさらしておこう・・・。何かに使うかもしれないし。たぶんRFCを読んで何とかするしかないんだろうな・・・。

インデントが見づらい件はごめんなさい。はてなスーパーPRE記法で色づけしてますが、タブ幅の指定も分かりません。そのうち何とかしよう。

[2007-10-31 追記]

タブ幅が見づらい件は、HTML+CSSではなんともならないことが分かったので、半角4スペースに置換してから上げることに。

package leaning;

import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.net.telnet.TelnetClient;
import org.apache.commons.net.telnet.TelnetCommand;

public class TelnetClientLeaning {

    public static void main(String[] args) throws Exception {
        final TelnetClient client = new TelnetClient();
        Thread connectThread = new Thread(){
            @Override
            public void run() {
                InputStream inStream = client.getInputStream();
                byte[] buff = new byte[256];
                while(true){
                    try{
                        int numRead = inStream.read(buff);
                        if(TelnetCommand.isValidCommand(buff[0])){
                            System.out.println(TelnetCommand.getCommand(buff[0]));                            
                        }
                        if(numRead > 0){
                            System.out.print(new String(buff,0,numRead,"utf-8"));
                        }
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }
            }
        };
        Thread commandThread = new Thread(){
            @Override
            public void run() {
                OutputStream commandStream = client.getOutputStream();
                while(commandStream == null){
                    commandStream = client.getOutputStream();
                }
                byte[] buff = new byte[256];
                while(client.isConnected()){
                    try{
                        int numRead = System.in.read(buff);
                        if(numRead > 0){
                            commandStream.write(buff,0,numRead);
                            commandStream.flush();
                        }
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }
            }
        };
        client.connect("localhost", 8023);
        connectThread.start();
        commandThread.start();
    }
}