受信状況を取得するには?

解決


こんでんす  2007-03-19 17:41:05  No: 64711  IP: 192.*.*.*

メール受信プログラムを作成しています。

ソケットの初期化・生成
  ↓
POP3サーバー接続
  ↓
アカウント送信
  ↓
パスワード送信

・・・までは上手くいくのですが、STATコマンドでメールの状態を取得しようとすると、
-ERRが返ってきてしまいます。
STATコマンドを送るときに、何か注意することがあるのでしょうか?
何かお気づきの方、いらっしゃいましたら、ご教授して頂けると幸いです。
どうぞよろしくお願い致します。

以下、STATコマンド送信のコードです。

//STATコマンドの送信
sprintf(szBuffer, "STAT\r\n");
send(Sock, szBuffer, strlen(szBuffer), 0);
char szReBuff[MAX_BUFF];
memset(szReBuff, 0, sizeof(szReBuff));
int nRe = recv(Sock, szReBuff, sizeof(szReBuff), 0);
if (nRe == SOCKET_ERROR || strncmp(szReBuff, "+OK", 3)){
  closesocket(Sock);
  WSACleanup();
  return (FALSE);
}

編集 削除
瀬戸っぷ  2007-03-20 00:41:52  No: 64712  IP: 192.*.*.*

> パスワード送信
> ・・・までは上手くいくのですが、STATコマンドでメールの状態を取得しようとすると、
> -ERRが返ってきてしまいます。

ちゃんと認証通っていますか?

> int nRe = recv(Sock, szReBuff, sizeof(szReBuff), 0);
> if (nRe == SOCKET_ERROR || strncmp(szReBuff, "+OK", 3)){

recvで2バイトしか取れていなかったら失敗しますが、そのヘンは大丈夫ですか?
ブレークポイント設定して、szReBuff[]に何が入っているか、
nReはいくつになっているか確認してみてはどうでしょう?

編集 削除
こんでんす  2007-03-20 08:56:45  No: 64713  IP: 192.*.*.*

お答えありがとうございます。

パスワードまでの認証は通っております。
きちんと「+OK」が返ってきました。

STATコマンドに対するrecvの返り値は、「-ERR・・・・・・」状態です。
どうしてもここでエラーが返ってきてしまいます。
コードの書き方は、アカウントやパスワードのときと同じなのですが。

前回、環境を書き忘れておりました。申し訳ありません。
VC.Net 2003です。
開発はWindows XPで行っております。

引き続き、助言をお待ちしております。
どうぞよろしくお願い致します。

編集 削除
へむ  2007-03-20 11:53:38  No: 64714  IP: 192.*.*.*

手っ取り早く、パケットをキャプチャしてみては?

キャプチャツールは色々ありますが
FreePeekとか
http://www.vector.co.jp/soft/winnt/net/se125800.html

ソケット通信のプログラムを作るときはあると便利です。

#telnetで正しくやり取りできるのは確認済みですか?

編集 削除
YuO  2007-03-20 12:12:11  No: 64715  IP: 192.*.*.*

-ERRの後に何らかのメッセージは書いていないのですか?

編集 削除
こんでんす  2007-03-22 09:35:14  No: 64716  IP: 192.*.*.*

返信が遅くなりました。
お答え下さっていた、へむさん、YuOさん、申し訳ありません。

キャプチャツールは使ったことがありませんでした。
使ってみます。
「#telnet」は存在自体知りませんでした。
勉強不足ですね。調べてみようと思います。

「-ERR」のあとのメッセージなのですが、調べてみると
「-ERR Not yet authenticated」認証されていないとのメッセージでした。
何回か試しているうちに、時にエラーなく通ることもあるようです。

ご親切にお答え下さって、本当にありがとうございます。
ネットワークプログラムは学び始めたばかりで、至らない点ばかり
だと思いますが、もう少しお付き合い下さると幸いです。

編集 削除
みけにゃん  URL  2007-03-22 21:56:36  No: 64717  IP: 192.*.*.*

同じようなネタのプログラムを作っているようなので・・・。

TelnetはTeraTerm等のソフトの総称と考えてかまわないです。
Windowsにも標準でTelnetが付いているので、それを使って
試してみると良いと思います。

起動方法は[スタート]-[すべてのプログラム]-[アクセサリ]-[コマンドプロンプト]で
コマンドプロンプトを出して以下のコマンドを入れて実行します。

C:\>telnet POPサーバ名(またはアドレス) ポート番号(標準なら110)

例としてpop.yourdomain.comだとしたら以下の通りです。
C:\>telnet pop.yourdomain.com 110

実行するとPOPサーバに接続されるので、以下のように入力します。
USER ユーザ名[ENTER]
PASS パスワード[ENTER]

例でユーザ名がmikenyan、パスワードがpassだとすると以下の通りです。
USER mikenyan[ENTER]
PASS pass[ENTER]

認証が正しければこのあとに現在届いているメールの数とメールの総バイト数が出ます。
ホストによってはSTATをたたかないと見れない場合もあります。
+OK xxx xxxx

例でMac OSXでTelnetした結果を載せておきます。(ホスト、ユーザ名、パスは架空です)
Clover-Server:〜 user1$ telnet pop.yourdomain.com 110
Trying XXX.XXX.XXX.XXX...
Connected to pop.yourdomain.com.
Escape character is '^]'.
+OK pop.yourdomain.com <33838122.1174567749@XXX.XXX.XXX.XXX.XXXXX>
USER mikenyan
+OK password please
PASS pass
+OK Maildrop locked and ready
LIST
+OK scan listing follows
1 24530
2 24680
.
STAT
+OK 2 49210
quit
+OK 
Connection closed by foreign host

あとは奥の手なのですけれど、私の作っているプログラムのように
nMail.dllやBASP21.dllを使ってメールの件数を取得するのも手かもしれません。

編集 削除
瀬戸っぷ  2007-03-22 23:20:43  No: 64718  IP: 192.*.*.*

> 「-ERR Not yet authenticated」認証されていないとのメッセージでした。
> 何回か試しているうちに、時にエラーなく通ることもあるようです。

あまり考えられませんが…
PASS送ってから、STAT送るまでが短いとか。
サーバ側の処理が遅れているとかでしょうかね。
PASS送出後のレスポンスで"+OK"を確認してから送っているんですよね?
100msほどSleepしてみるとかはどうでしょう?

telnetに関してはみけにゃんさんが書かれているので…
「telnet POP3」でググると参考になるページが見つかるんじゃないでしょうか。
あと、RFCも一応見ておいた方がいいかもしれません。

# spamなんかはよくRFCに従わないカタチで送ってくれやがりますが。
# 最近はGOOD MailerのDateヘッダに泣かされてます。(バッファオーバーランかましてしまいました)

編集 削除
こんでんす  2007-03-23 11:06:33  No: 64719  IP: 192.*.*.*

ご丁寧な対応をありがとうございます。

みけにゃんさんの教えてくださった通りに、Telnetで確認を行いました。
問題なく受信状況を取得できるようです。

Sleepで待ってもみたのですが、改善されません。

いま作成しているのはWindowプログラムです。
試しにコンソールプログラムで作成してみたところ、何故か受信できるようになりました。
処理は特に変更していないのですが・・・
(ホスト・アカウントなどの情報取得方法がかわった程度です。
取得内容も同じであることを確認しました)

何か考えられる原因はありますでしょうか?
引き続き、どうぞよろしくお願い致します。

編集 削除
へむ  2007-03-23 13:29:40  No: 64720  IP: 192.*.*.*

>Trying XXX.XXX.XXX.XXX...
>Connected to pop.yourdomain.com.
>Escape character is '^]'.
>+OK pop.yourdomain.com <33838122.1174567749@XXX.XXX.XXX.XXX.XXXXX>

サーバーからの応答でこの辺の部分の処理がうまくできていないとかは
ありませんか?
USERの前に「+OK」を送信してくるので「+OK」をひとつずれて取得しているとか・・
#予想で書いているので多分ハズレです。

全ての箇所のsendとrecvの下にTRACEを入れて
送信文字と受信文字を処理順に表示させてみるとどうなりますか?

編集 削除
みけにゃん  URL  2007-03-23 23:03:37  No: 64721  IP: 192.*.*.*

とりあえず参考になるか分からないですけれど
Windowプログラム(SDK)であれば、猫でも分かるプログラミングの
SDK編3章にPOP3につないでメールの件名、差出人、受信日時
メールサイズをリストビューに一覧表示するプログラムが載っています。
http://www.kumei.jp/c_lang/sdk3/sdk_238.htm

>全ての箇所のsendとrecvの下にTRACEを入れて
WindowプログラムならMessageBox(NULL,デバッグ文字列変数,"DEBUG", MB_OK);を入れて
デバッグしてもよさそうな気がします・・・・。

編集 削除
瀬戸っぷ  2007-03-24 00:30:12  No: 64722  IP: 192.*.*.*

> >全ての箇所のsendとrecvの下にTRACEを入れて
> WindowプログラムならMessageBox(NULL,デバッグ文字列変数,"DEBUG", MB_OK);を入れて
> デバッグしてもよさそうな気がします・・・・。

MessageBox()で処理が止まってしまうので、場合によっては不向きです。
(何十回とループする中に入れた場合とか)
他に、WM_PAINT関係やWM_ACTIVATE等に反応するモノの場合は
ほぼ無限ループに陥ってしまいます。

ということで、ログファイルに書き出すか、TRACE(SDKの場合はOutputDebugString)を使った方が便利なこともあります。


さて、本題ですが…
Sleep()でもダメだったようで。
ヘムさんの指摘のように実際のサーバとりやりとりを確認するのがまずは行うべきコトかと。
あと…認証通った後、QUITコマンドでちゃんとログアウトしていますか?
POP3の場合、たいていのサーバで多重ログインはできません。
認証後、QUITコマンドで抜ける必要があります。
(とはいえ、マトモなサーバならTCP接続が切れた時点でログアウト扱いしてくれるハズですが)

# クセのあるサーバもあったりするので注意が必要ですが。
# 私の使っているISPのサーバだと、LISTコマンドで取得したサイズと、
# メールのサイズが微妙に食い違うコトがあります。
## Statusヘッダの内容の増分でしたが。

編集 削除
みけにゃん  URL  2007-03-24 07:58:44  No: 64723  IP: 192.*.*.*

>他に、WM_PAINT関係やWM_ACTIVATE等に反応するモノの場合は
>ほぼ無限ループに陥ってしまいます。

そこを考慮してなかったですね(>_<)
確認するものが単純にループしないものと想定して書いたんです。

さすがにWM_TIMER、WM_PAINT、WM_ACTIVATE等の
反応するものはログ出力(LogWrite()とかを自作して使う)した方が
良いのかもしれませんね。

編集 削除
へむ  2007-03-24 12:45:33  No: 64724  IP: 192.*.*.*

>みけにゃん
すみません。確認方法を書いただけですので
MessageBoxでも勿論確認はできると思います。
問題解決の方法が複数あったほうが質問したかたの
助けになると思います。

私も本題です。
未解決でしたら受信部分の(できれば検証(再現)できる)
ソース部分を載せてみてはいかがでしょう。

#もうそれしかなさそうな

編集 削除
みけにゃん  URL  2007-03-24 23:34:11  No: 64725  IP: 192.*.*.*

そういえば・・・メール受信プログラムとありますけれど
メールチェッカーか私のようなメールデータを受信して
ファイルにしてどこか指定したディレクトリに格納して
一覧にするような普通のメールソフトを作ろうとして
いるのでしょうか?

へむさんの言うようにソースを一部出した方が早期
解決につながるかもしれませんよ。

編集 削除
こんでんす  2007-03-26 09:31:53  No: 64726  IP: 192.*.*.*

皆さん、本当にご親切に解答して下さって、ありがとうございます。
返信が遅れてしまって、申し訳ありませんでした。

解決致しました。
へむさんのおっしゃる通り、「connect」のあとの送信取得が
通っておりませんでした。
その部分を修正すると、エラーなく処理が走るようになりました。

初歩的なミスで、皆さんを煩わせて申し訳ありません。
一緒に考えてくださったこと、うれしく思います。
また何かありましたら、相談させて頂こうと思いますので、
そのときはあきれず、ご相手して下されば幸いです。

瀬戸っぷさん、へむさん、YuOさん、みけにゃんさん、
本当にありがとうございました。

編集 削除