Adsense_top

2010年2月20日土曜日

Android開発のメモ その2 (Xperia スキン)

Sony Ericsson の開発者向けページに、ドコモが発売を予定しているXperiaの Android SDK用のAdd-onがありました。
Devloper WORLDDownloadsページのAndroidの所の「 All Android downloads 」の先にあるページから「Sony Ericsson Xperia X10 add-on for the Android SDK」を落とします。


解凍後、Android SDKのフォルダ内の「add-ons」に置くと、「AVD manager」から選ぶことができるようになります。



書き忘れていましたが、そのままAVDを起動すると大きすぎるので、起動時に、「Launch Options」で「Scale display to real size」にチェックを入れ、「Screen Size」の値を「6」か「7」にすると丁度良いぐらいのサイズになります。

2010年2月15日月曜日

Android開発のメモ その1

AndroidのSDKののインストール時にハマった事がいくつがあったので、備忘録がわりにメモっておきます。


・SDカードイメージファイルの作り方
 コマンドプロンプトで
 adb -l<ボリュームラベル>(オプション) <サイズ>[K|M] <イメージファイルパス>
 [例]1024MBのSDカードのイメージファイルをC:\直下に作成する
 >adb 1024M C:\Sdcard.img


 同じSDカードイメージファイルを別のAVDで共用出来る。



・PCからファイルをエミュレータにコピーする
 >adb push 転送元ファイル 転送先ファイル
 エミュレーからファイルタをPCにコピーする
 >adb pull 転送元ファイル 転送先ファイル
 [例]
 >adb push C:\Test.txt /sdcard/Test.txt
 >adb pull /sdcard/Test2.txt C:\Text2.txt


上記ファイルのコピーは、Eclipse上のDDMSから同様の操作可能



以下の作業は、Androidのシェルを起動した上でコマンドを送ります。
・シェル起動
 >adb shell


・フォルダの作成
 #mkdir 作成フォルダパス
 [例]
 #mkdir /sdcard/NewFolder


・ファイル削除
 #rm 削除ファイルパス
 [例]
 #rm /sdcard/Test.txt


・フォルダ削除
 #rmdir 削除フォルダパス
 [例]
 #rmdir /sdcard/NewFoder


ファイル操作については、Android MarketのPCページから「OI File Manager」というフリーのアプリケーションをダウンロードしてAVD上でインストールすれば、コマンド操作しなくても出来ました。


2010年2月9日火曜日

C# POP3でAPOP認証を使用する

予告していた通りAPOPについて書きます。
あまり使われていないらしいですが、パスワードを暗号化するので平文でやり取るするPOP3よりは、セキュリティ的には高いと言っていいと思います。(ただし、すでに破られているとのことですが..)


POP3の認証の部分のみ異なるだけですので、その部分だけの記述にします。他の部分は、先に書いた、「C# POP3サーバーからメールを受信する」をご覧ください。


以下に引用した以前のコードの「----------ココから----------」から「----------ココまで----------」の部分

/// 
/// POP3サーバのすべてのメールを受信しサーバより削除します。
///

/// POP3サーバ名
/// ポート番号
/// ユーザー名(アカウント)
/// パスワード
public void ReceiveAll(string host, int port,
string user, string pass)
{
string result;
Stream stream = null;
TcpClient tcp;
tcp = new TcpClient();
try
{
// 接続
tcp.Connect(host, port);
// NetworkStreamを得る
stream = tcp.GetStream();
// タイムアウト時間の設定
stream.ReadTimeout = 30 * 1000;
stream.WriteTimeout = 30 * 1000;
// StreamReader、StreamWriterを被せる
StreamReader reader =
new StreamReader(stream, Encoding.ASCII);
StreamWriter writer =
new StreamWriter(stream, Encoding.ASCII);
// 改行文字とバッファフラッシュを設定
writer.NewLine = "\r\n";
writer.AutoFlush = true;
// サーバーからの挨拶コードを得る
//----------ココから----------
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
// USERコマンド
writer.WriteLine("USER {0}", user);
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
// PASSコマンド
writer.WriteLine("PASS {0}", pass);
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
//----------ココまで----------

を下記のように書き換えるだけです。


    result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
Match challenge =
Regex.Match(result, @"^.+(<.+>).*$", RegexOptions.Compiled);
if (!challenge.Success)
throw new InvalidDataException(
string.Format(
"APOP認証のための識別子が見つかりません:{0}", result));
// チャレンジ文字列 + パスワードを元に生成します。
string plain = challenge.Groups[1].Value + pass;

// MD5に変換
MD5 md5 = MD5.Create();
byte[] bytes =
md5.ComputeHash(Encoding.ASCII.GetBytes(plain));

// 16進数小文字(x)の文字列にする
StringBuilder md5response = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
md5response.Append(data[i].ToString("x"));

writer.WriteLine("APOP {0} {1}", UserName,
md5response.ToString());
string result = ReadLine();
// 失敗
if (!result.StartsWith("+OK"))
throw new SecurityException(
string.Format("認証に失敗しました:{0}", result));

実際にテスト出来るサーバーのアカウントを持っていませんので、テストは出来ていません。
実際の使用する場合は必ずテストを行ってからにしてください。
また、テスト結果など教えていただければ嬉しいです。


2010年2月7日日曜日

Java Android、始めました。

なんとなく、Androidが気になりだしたので、今日は開発環境の準備などしていました。
わざわざ書かなくてもご存じだと思いますが、Androidとは、Googleが開発しオーぷソース化した、携帯端末(スマートフォンなど)用のOSです。日本でもドコモを皮切りに他のキャリアも春以降搭載スマートフォンが発表されてきます。


久しぶりのJavaでしたので、Eclipseと、Android Sdkを導入して、「Hellow Android」など初歩的な物を作り、Android エミュレータ上で動かして遊んでいました。
基礎的な部分を、まだよく読まずに遊んでいましたので、もう少し勉強して自分の独自に工夫できるようになったら、ここにも書いていきたいと思います。


先日から書いていた、C#でのメール受信は、もちろん続けます。明日か明後日ぐらいにAPOPに関して書きます。


2010年2月4日木曜日

C# DataGridViewTextBoxColumのMultiline入力枠を大きく

メール受信の方は、今回お休みして、DataGridViewTextBoxColumのMultiline入力用に改善してみました。

DataGridViewTextBoxColumnでは、WrapModeプロパティを設定する事により、複数行入力が可能になります。
また、AutoSizeRowModeを設定する事により、行(セル)の高さも調整されます。
ただ、入力時に表示される編集コントロールの高さは、編集コントロールが表示された、時点の行の高さであり、特に新規行など文字列1行分しか見えなくて入力に不便を感じる場合があります。

そこで、DataGridViewTextBoxColumを少しだけ改造してみました。
表示される編集コントロール(TextBox)の高さを設定できるように拡張してみました。
Visual StudioのデザイナでのTextBoxコントロールの Textプロパティの内容の入力時に表示される MultilineStringEditor ようにしようかとも思いましたが、結構大変そうなので簡単に出来る高さを広げるのみとしました。
そのため、DataGridViewのクライアント領域を超えて表示しない物になってしまいました。

クラスの構成は以下の通りです。
DataGridViewTextBoxColumn の派生クラスとして、DataGridViewTextBoxColumnEx。
DataGridViewTextBoxCell の派生クラスとして、DataGridViewTextBoxCellEx。
DataGridViewTextBoxEditingControlはそのまま使用します。
「Ex」と付けるほどの拡張はしていませんが、とりあえず以上のように命名しています。
まずは、DataGridViewTextBoxColumnExクラスから

public class DataGridViewTextBoxColumnEx
{
private int editingPanelHeight=65;

public DataGridViewTextBoxColumnEx() : base()
{
this.CellTemplate = new DataGridViewTextBoxCellEx();
}
// 今回の中心になる、TextBoxの高さを取得または設定するプロパティです。
[Category("配置")]
[Browsable(true)]
[DefaultValue(65)]
[Description("WrapMode プロパティが true の場合に表示される"
+ "編集コントロールの高さを指定します。")]
public int EditingPanelHeight
{
get
{
DataGridViewTextBoxCellEx cell =
(DataGridViewTextBoxCellEx)this.CellTemplate;
return cell.EditingPanelHeight;
}
set
{
if (this.editingPanelHeight == value)
return;
if(this.DataGridView != null)
{

if( value < this.DataGridView.RowTemplate.Height)
return;
}
else
{
if(value < 21)
return;
}

//CellTemplateの値を変更する
DataGridViewTextBoxCellEx cell =
(DataGridViewTextBoxCellEx)this.CellTemplate;
cell.EditingPanelHeight = value;
if (this.DataGridView == null)
return;
// 既に登録済みのセルの値を更新
int rowCount = this.DataGridView.RowCount;
for (int i = 0; i < rowCount; i++)
{
DataGridViewRow r = this.DataGridView.Rows.SharedRow(i);
DataGridViewTextBoxCellEx rCcell =
(DataGridViewTextBoxCellEx)r.Cells[this.Index];
rCell.EditingPanelHeight = value;
}
}
}

// EditingPanelHeight プロパティを追加しているので、
// Cloneメソッドをオーバーライド
public override object Clone()
{
DataGridViewTextBoxColumnEx col =
(DataGridViewTextBoxColumnEx)base.Clone();
col.editingPanelHeight = this.editingPanelHeight;
return col;
}
// CellTemplateをオーバーライド
public override DataGridViewCell CellTemplate
{
get { return base.CellTemplate; }
set
{
if (value != null &&
!value.GetType().IsAssignableFrom(
typeof(DataGridViewTextBoxCellEx)))
{
throw new InvalidCastException(
"Need DataGridViewTextBoxCellEx object");
}
base.CellTemplate = value;
}
}
}

大した事はしていませんが、大きく以下のような事を行っています。
コードを後述する DataGridViewTextBoxCellEx を CellTemplateに登録しています。
デザイナ用に属性を付けた形で EditingPanelHeight プロパティを追加し、それに伴い Clone() メソッドをオーバーライドしています。

次は、DataGridViewTextBoxCellEx です。
実際に 編集用のTextBox の高さの変更はこのクラスで行っています。

public class DataGridViewTextBoxCellEx
{
private int editingPanelHeight=65;
// Cloneメソッドをオーバーライド
public override object Clone()
{
DataGridViewTextBoxCellEx cell =
(DataGridViewTextBoxCellEx)base.Clone();
cell.EditingPanelHeight = this.EditingPanelHeight;
return cell;
}
// TextBoxの高さを取得または設定するプロパティです。
public int EditingPanelHeight
{
get { return editingPanelHeight; }
set { editingPanelHeight = value; }
}
// ホストされる編集コントロールの初期化部をオーバーライドします。
public override void InitializeEditingControl(
int rowIndex,
object initialFormattedValue,
DataGridViewCellStyle dataGridViewCellStyle)
{
base.InitializeEditingControl(
rowIndex, initialFormattedValue, dataGridViewCellStyle);
if (dataGridViewCellStyle.WrapMode ==
DataGridViewTriState.True)
{
// 境界線をセット
this.DataGridView.EditingPanel.BorderStyle =
BorderStyle.FixedSingle;
DataGridViewTextBoxEditingControl ctl =
DataGridView.EditingControl as
DataGridViewTextBoxEditingControl;
// スクロールバーをセット
ctl.ScrollBars = ScrollBars.Vertical;
}
}
// 編集パネルの位置とサイズを設定部をオーバーライドします。
public override Rectangle PositionEditingPanel(
Rectangle cellBounds,
Rectangle cellClip,
DataGridViewCellStyle cellStyle,
bool singleVerticalBorderAdded,
bool singleHorizontalBorderAdded,
bool isFirstDisplayedColumn,
bool isFirstDisplayedRow)
{
// 複数行である場合
if (cellStyle.WrapMode  == DataGridViewTriState.True)
{
Rectangle rect = cellBounds;
rect.Height = editingPanelHeight;
// 編集パネルの高さを広げた結果、
// DataGridViewのクライアント領域の下部よりはみ出さないか確認
if(rect.Bottom> this.DataGridView.ClientRectangle.Bottom)
{
下部にはみ出す場合はセルの上側に表示する。
rect.Y =
rect.Top - editingPanelHeight + cellBounds.Height;
//  DataGridViewのクライアント領域の上部よりはみ出さないか確認
if (rect.Top < 0)
{
// 上側表示の結果上部にはみ出す場合は上部ギリギリに調節
rect.Y = 0;
}
cellClip= cellBounds;
}

// セルにおけるセルの内容の場所を左上にします。
// 入力開始位置がこれによりパネルの左上からになります
cellStyle.Alignment =
DataGridViewContentAlignment.TopLeft;
cellClip = cellBounds = rect;
}
return base.PositionEditingPanel(
cellBounds,
cellClip,
cellStyle,
singleVerticalBorderAdded,
singleHorizontalBorderAdded,
isFirstDisplayedColumn,
isFirstDisplayedRow);
}
}

このクラスの中で編集コントロール(TextBox)の高さの変更と、境界線・スクロールバーを設定しています。
WrapMode が true 以外の場合は EditingPanelHeight プロパティを設定しても、通常の表示がおこなわれます。


実際に DataGridView の「列の編集」から、「DataGridViewTextBoxColumnEx」を列に追加し、入力を行うと以下の図のようになります。


最初に書いた、DataGridViewのクライアント領域を超えて表示できない件は、編集パネル部の高さを、クライアント領域より高くしなければ、どうにか使えると思うのですが...、いわゆる運用の方で....。




2010年2月3日水曜日

C# POP3サーバーからメールを受信する

今日は、POP3でメールボックス内の全てのメールを受信し、メールボックスから削除します。
前回書いた分は、大文字・小文字のタイプミスなどありました。すみませんでした。
重複する説明になる部分が出てくると思いますが、軽く流して下さい。
あっちこっち飛ぶと分かりにくいと思いますので、メソッドに割らないでダラダラ書いていきます。


カッコ等も省かず書きますので、コードをすべてまとめると、一つのメソッドになります。
/// 
/// POP3サーバのすべてのメールを受信しサーバより削除します。
///

/// POP3サーバ名
/// ポート番号
/// ユーザー名(アカウント)
/// パスワード
public void ReceiveAll(string host, int port,
string user, string pass)
{
string result;
Stream stream = null;
TcpClient tcp;
tcp = new TcpClient();
try
{
// 接続
tcp.Connect(host, port);
// NetworkStreamを得る
stream = tcp.GetStream();
// タイムアウト時間の設定
stream.ReadTimeout = 30 * 1000;
stream.WriteTimeout = 30 * 1000;
// StreamReader、StreamWriterを被せる
StreamReader reader =
new StreamReader(stream, Encoding.ASCII);
StreamWriter writer =
new StreamWriter(stream, Encoding.ASCII);
// 改行文字とバッファフラッシュを設定
writer.NewLine = "\r\n";
writer.AutoFlush = true;
// サーバーからの挨拶コードを得る
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
// USERコマンド
writer.WriteLine("USER {0}", user);
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
// PASSコマンド
writer.WriteLine("PASS {0}", pass);
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));

ここまでは前回とほぼ同じです。
サーバーに接続し USER 、PASS コマンドでログインしています。
"+OK"とあるのは、POP3サーバーでは、正常にコマンドが実行された場合には「+OK」、異常がある場合には「-ERR」を先頭しにして応答する為、正常応答かを確認しています。


    // 一覧を取得(LISTコマンド)
writer.WriteLine("LIST");
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new InvalidDataException(
string.Format("エラー応答:{0}", result));
// 「.」が出てくるまでループして一覧番号(UID)を取得
List uidList = new List();
while ((result = reader.ReadLine()) != ".")
{
// [UID サイズ]の形式で返ってくるので、UIDのみリストとして取得
string[] val = result.Split(new Char[] { ' ' });
uidList.Add(int.Parse(val[0]));
}

ここでは、LISTコマンドでメールボックス内のメールのリストを取得しています。
各メールに振られている UID(ユニークな識別番号)の一覧をとしてListに格納しています。


    StringBuilder builder = new StringBuilder();
foreach (int uid in uidList)
{
builder.Length = 0;
// メールを取りだす(RETRコマンド)
writer.WriteLine(string.Format("RETR {0}", uid));
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new InvalidDataException(
string.Format("エラー応答:{0}", result));
// メール終端までループして受信
while (true)
{
if ((result = reader.ReadLine()) == ".")
{
// "." のみの場合はメールの終端を表す
break;
}
builder.Append(result);
builder.Append("\r\n");
}
// ここではコンソールに出力
Console.WriteLine(builder.ToString());

メール受信の部分です。
先に取得した UID を RETRコマンド の引数として送る事により、対象のメールを要求します。
whileループしている部分で、メールを受信しています。コメントに書いている通り、「.」(ピリオド)のみの行がメールの終端を表していますので、出現するでループしています。


      // 削除フラグを送信(DELEコマンド)
// 実際の削除は QUITコマンドにて行われる。
writer.WriteLine(string.Format("DELE {0}", uid));
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception("エラー応答:{0}", result));
}

DELEコマンドに引数として UID を付けて送る事により、受信を完了したメールに削除フラグを付けています。
削除フラグと書いたのは、この後の QUIT を送る事により削除が実行されるからです。
QUITを送る前に何らかの理由で切断した場合は、メールは削除されません。


    // ログアウト(QUITコマンド)
writer.WriteLine("QUIT");
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
}
finally
{
if (stream != null)
stream.Close();
if (tcp != null && tcp.Connected)
tcp.Close();
}
}

QUIT コマンドでログアウトしています。先に書いたように、DELE コマンドで削除を指定したメールは正常にログアウトした時点で、削除された事になります。



メール受信に関するネタはもう少し続くと思います。