dポイントプレゼントキャンペーン実施中!

お世話になっています。
VC++2005、MFC、Win7、openssl で作業しています。

Gメールから、POP3S 接続でメールを受け取りたいと考えています。
メールヘッダーの受信後に、本文を取り出す前に接続が切れます。

最初に、接続の部分ですが、問題点がありましたら、アドバイスをください。

void CSQMailBoxTreeView::GmailMailDL(){
int nReturnCode;
WSADATA wsaData;
CFileException fileExpection;
#define MAJOR_VERSION_REQUIRED 1
#define MINOR_VERSION_REQUIRED 1

struct sockaddr_in server;


std::string req; // リクエスト
std::string res; // レスポンス
std::string host_url = "pop.googlemail.com";


strcpy_s(gszGmailServerName,(LPCTSTR)oc_Gmailpop3servername);
if(strlen(gszGmailServerName)==0){
MessageBox("設定 - Gmail POP3サーバー から、\n受信メール(POP3)サーバを\n入力して下さい。","POP Server", MB_OK);
}
strcpy_s(gszGmailUserId, (LPCTSTR)oc_Gmailpop3userid);
if(strlen(gszGmailUserId)==0){
MessageBox("設定 - Gmail POP3サーバー から、\nメールサーバのユーザ名を\n入力してください。","POP User ID", MB_OK);
}
strcpy_s(gszGmailPassword, (LPCTSTR)oc_Gmailpop3password);
if(strlen(gszGmailPassword)==0){
MessageBox("設定 - Gmail POP3サーバー から、\nパスワードを入力してください。","警告 PassWord", MB_OK);
}
strcpy_s(gszGmailPOP3Port, (LPCTSTR)oc_Gmailpop3port);
if(strlen(gszGmailPassword)==0){
MessageBox("設定 - Gmail POP3サーバー から、\nポート番号を入力してください。","POP3 PortNumber", MB_OK);
}

// Prepare version for WSAStartup()
WORD wVersionRequired = MAKEWORD(MAJOR_VERSION_REQUIRED, MINOR_VERSION_REQUIRED);
// Initialize the WinSock DLL
nReturnCode = WSAStartup(wVersionRequired, &wsaData);
if (nReturnCode != 0 ){
MessageBox("Error on WSAStartup()","CheckGMail", MB_OK);
return ;
}
// Confirm that the version requested is available.
if (wsaData.wVersion != wVersionRequired){
// Version needed is not available.
MessageBox("Wrong WinSock Version","CheckGMail", MB_OK);
WSACleanup();
return ;
}

sock = socket(AF_INET, SOCK_STREAM, 0);

server.sin_family = AF_INET;
server.sin_port = htons(995);

server.sin_addr.S_un.S_addr = inet_addr(host_url.c_str());
if (server.sin_addr.S_un.S_addr == 0xffffffff) {
struct hostent *host;
unsigned int **addrptr;

host = gethostbyname(host_url.c_str());
if (host == NULL) {
return ;
}

addrptr = (unsigned int **)host->h_addr_list;
while (*addrptr != NULL) {
server.sin_addr.S_un.S_addr = *(*addrptr);
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) {
break;
}
}
if (*addrptr == NULL) {
sprintf_s(outbuf3, "Fatal error: unable to connect to the server.\n");
MessageBox(outbuf3,"Error", MB_OK);
WSACleanup();
return;// -1;
}
}
else {
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) != 0){
return ;
}
}

SSL_load_error_strings();
SSL_library_init();
ctx = SSL_CTX_new(TLSv1_method());
if (ctx == NULL) {
return;// 1;
}

ssl = SSL_new(ctx);
if (ssl == NULL) {
return;// 1;
}

if (SSL_set_fd(ssl, sock) == 0) {
return;// 1;
}

RAND_poll();

while (RAND_status() == 0) {
unsigned short rand_ret = rand() % 65536;
RAND_seed(&rand_ret, sizeof(rand_ret));
}

int ev = SSL_connect(ssl);
if ( ev != 1) {
int ret = SSL_get_error(ssl, ev);
if(ret <= 0){
ERR_print_errors_fp(stderr);
return;// 1;
}
}

if (WSAAsyncSelect(sock, *this, SM_GASYNC3,
FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE) == SOCKET_ERROR){
MessageBox("WSAAsyncSelect() failed","Error", MB_OK);
closesocket(sock);
sock = INVALID_SOCKET;
return;
}

gnAppState = STATE_CONNECTING;
}

A 回答 (2件)

RETRコマンドで読み取り完了したら、そのメールを削除して、QUITコマンドで切断していますから1通しか読み込めないのは想定内の動作のハズですけど、そこらヘンはどうなんですかね?



CSQMailBoxTreeView::GmailProcessData()の呼び出し方次第ではココも正常動作が期待できませんが…。

前回の回答でも指摘しましたが普通のPOP3で正しく動作するもの作ってからの方がいいと思われますが…。
その際、LAN内の別マシンにPOP3サーバを構築すればWireSharkなどでパケットの内容は確認できますし。
# GmailのPOP3って…bad commandで切断されるのね……

あと…MessageBox()でもろもろの通知を出すと「そこで処理が止まる」ので通信扱う場合だと問題が発生することもありますのでご注意を。
# 私ならTRACE()やその類使いますね。(Win32SDKなんでOutputDebugString()ですが…)

この回答への補足

関連する残りの部分です。

POP3 では、メールは取り出せます。
新しく、POP3S で接続しようとしています。

ご指摘の部分を参考に、デバッグを続けます。
ありがとうございました。

// MailAsync(); corresponding to the message SM_GASYNC3.
LRESULT CSQMailBoxTreeView::GmailMailAsync(WPARAM , LPARAM lParam)
{
int GmailnBytesRead;
char buf1[256];

int nEvent = (int)WSAGETSELECTEVENT(lParam);
int nError = (int)WSAGETSELECTERROR(lParam);
sprintf_s(buf1,"hasm %d error\r\n",nError);
if( nError ){
MessageBox(buf1,"Error", MB_OK);
}

switch(nEvent){
case FD_CONNECT:
break;
case FD_WRITE:
break;
case FD_READ:
// Receive waiting data
GmailnBytesRead = SSL_read(
ssl, // socket
gbufRecv, // buffer
sizeof(gbufRecv)-1 // max len to read //はみだしそう -1 付けた
);// recv flags
// Check recv() return code
if (GmailnBytesRead == 0){
// Connection has been closed.
int erv = SSL_get_error(ssl, GmailnBytesRead);
if(erv <= 0){
MessageBox("Connection closed unexpectedly",
"recv() error", MB_OK);
}
break;
}
if (GmailnBytesRead < 0){
int erv = SSL_get_error(ssl, GmailnBytesRead);
if(erv <= 0){
wsprintf((LPSTR)gszTemp,
(LPSTR)"recv() error: %d", GmailnBytesRead);
MessageBox(gszTemp,"recv() error",MB_OK);
gszTemp[0] = '\0';
}
break;
}
// Null terminate the buffer
gbufRecv[GmailnBytesRead] = '\0'; //はみだしそう

// And pass it to be interpreted
GmailProcessData(gbufRecv, GmailnBytesRead);
break;
case FD_CLOSE:
break;
}
fRet = TRUE;
return 0;
}


LPSTR CSQMailBoxTreeView::GmailDecodeError(int ErrorCode)
{
static char Message[1024];

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)Message, 1024, NULL);
return Message;
}

void CSQMailBoxTreeView::GmailMailDL2(){
reached = download = 0;
in_header = 1;
((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar.SetWindowText("メール受信中です、しばらくお待ちください。");
GmailMailDL();
((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar.SetWindowText("終了。");
}

補足日時:2013/07/31 06:15
    • good
    • 0

>メールヘッダーの受信後に、本文を取り出す前に接続が切れます。



POP3Sで接続して、RETRコマンドの発行まで出来ているんでしょう?
であれば、接続の時のコードを掲示してもあまり意味が無いと思いますが。
# SSL接続の方法などについて意味があるかも知れませんけど、ログイン出来ているならSSL接続は出来ていることになりませんか?

実際のデータ受信処理の辺りがどうなっているのか?
が問題かと思いますが……。
LISTコマンドやTOPコマンド、RETRコマンドは1行受信して終了ではなく、
"."のみの行を受信するまで続きますがそこらヘン正しく処理していますか?
# "\r\n.\r\n"が正確なとこですかねぇ。


POP3Sが~ではなく通常のPOP3でちゃんと処理できるかどうかを先にやってはどうですか?
自由に使えるメールサーバがあれば、こういう時は楽…なんですけどね。
実行しているWindowsに一時的にメールサーバ構築する。なんてのもアリでしょう。
「Windows メールサーバ」辺りで検索すると情報も見つかるでしょう。
# 私はMercury辺りを使ったことがありますが。
# 今はLAN内のメールサーバ(Linux+Dovecot)があるので使っていませんけど。

この回答への補足

void CSQMailBoxTreeView::GmailProcessLine(LPSTR lpStr)
{
int nRet, ret;
long lCount;
long lSize;
CFileStatus fs;
CString sbuf;
BStringBuffer s("");
CSQMailBoxDoc* pDoc = GetDocument();


if(strlen(lpStr)==1 && in_header){
pDoc->GetHeaderInfor();
in_header = 0;
}

// Check response for error
if ((lpStr[0] == '-') && (lpStr[1] == 'E') && (lpStr[2] == 'R') && (lpStr[3] == 'R'))
{
//MessageBox("Negative response: ","Error",MB_OK);
switch(gnAppState)
{
case STATE_CONNECTING:
MessageBox("Connection denied","Error",MB_OK);
break;
case STATE_USER:
MessageBox("Unknown UserID\r\n","Error",MB_OK);
break;
case STATE_PASS:
MessageBox("Wrong Password","Error",MB_OK);
break;
case STATE_STAT:
MessageBox("STAT command not supported","Error",MB_OK);
break;
case STATE_LIST:
state = -STATE_LIST;
MessageBox("メールはありません。");
break;
case STATE_RETR:
state = -STATE_RETR;
MessageBox("Negative RETR response.");
break;
case STATE_QUIT:
MessageBox("QUIT command not supported","Error",MB_OK);
break;
}
wsprintf(gszTemp, "QUIT\r\n");
nRet = SSL_write(ssl, // socket
gszTemp, // data buffer
strlen(gszTemp)// length of data
);// send flags
gnAppState = STATE_QUIT;

SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
ERR_free_strings();
CloseSocket(sock);

return;
}

// We have a positive response
switch(gnAppState)
{
case STATE_CONNECTING:
// Send the USER portion of the login request and set the app state
wsprintf(gszTemp, "USER %s\r\n", gszGmailUserId);
nRet = SSL_write(ssl, // socket
gszTemp, // data buffer
strlen(gszTemp)// length of data
);// send flags
gnAppState = STATE_USER;
break;

case STATE_USER:
// Send the PASSword portion of the login request and set the app state
wsprintf(gszTemp, "PASS %s\r\n", gszGmailPassword);
nRet = SSL_write(ssl, // socket
gszTemp, // data buffer
strlen(gszTemp)// length of data
);// send flags
gnAppState = STATE_PASS;
break;

case STATE_PASS:
// Send the STAT command request and set the app state
wsprintf(gszTemp, "STAT\r\n");
nRet = SSL_write(ssl, // socket
gszTemp, // data buffer
strlen(gszTemp)// length of data
);// send flagsgs
gnAppState = STATE_STAT;
break;

case STATE_STAT:
// Read the STAT response and print the results
sscanf(lpStr, "%s %ld %ld",
gszTemp, &lCount, &lSize);
if(download == 0){reached = lCount;}
download += 1;
wsprintf(gszTemp, "LIST %d\r\n",download);
nRet = SSL_write(ssl, // socket
gszTemp, // data buffer
strlen(gszTemp)// length of data
);// send flags
gnAppState = STATE_LIST;
break;

case STATE_LIST:
sscanf(lpStr, "%s %ld %ld",
gszTemp, &lCount, &lSize);
_itoa(lSize, c_strSize,10);
wsprintf(gszTemp, "RETR %d\r\n",download);
nRet = SSL_write(ssl, // socket
gszTemp, // data buffer
strlen(gszTemp)// length of data
);// send flags
gnAppState = STATE_RETR;
break;

補足日時:2013/07/30 22:28
    • good
    • 0
この回答へのお礼

続きです。(一部重複)接続できていて不安定ですが一度だけメール本文も取得できました。

case STATE_LIST:
sscanf(lpStr, "%s %ld %ld",
gszTemp, &lCount, &lSize);
_itoa(lSize, c_strSize,10);
wsprintf(gszTemp, "RETR %d\r\n",download);
nRet = SSL_write(ssl, // socket
gszTemp, // data buffer
strlen(gszTemp)// length of data
);// send flags
gnAppState = STATE_RETR;
break;

case STATE_RETR:
if((lpStr[0]=='.') && (strlen(lpStr)==2)){

pDoc->D_hi.DoIt(pDoc->Mailstrs);
strcpy_s(c_strTo, pDoc->D_hi.GetTo());
strcpy_s(c_strSubject, pDoc->D_hi.GetSubject());
strcpy_s(c_strFrom, pDoc->D_hi.GetFrom());
strcpy_s(c_strAttach, "");
//strcpy(c_strSize, "");
strcpy_s(c_strPriority, "2");
strcpy_s(c_strRead, "1");//未読1 , 既読0
if(mailfilter == 1){
ret = pDoc->GetPrgbyAddr(c_strFrom);
if(ret == 0){
strcpy_s(c_strState, "3");//1:受信箱 2:送信済み 3:迷惑メール 4:ゴミ箱
}else{
strcpy_s(c_strState, "1");//1:受信箱 2:送信済み 3:迷惑メール 4:ゴミ箱
}
}else{
strcpy_s(c_strState, "1");//1:受信箱 2:送信済み 3:迷惑メール 4:ゴミ箱
}
strcpy_s(c_strDate, pDoc->D_hi.GetDate());
if(CFile::GetStatus("test2.bin", fs) == TRUE){CFile::Remove("test2.bin");}
u_CStringArray2File("test2.bin", pDoc->Mailstrs);
pDoc->AddNewMail("test2.bin");
pDoc->Mailstrs.RemoveAll();

// Send the QUIT command. And set the app state.
if(0 == atoi(oc_Gmailradio)){
wsprintf(gszTemp, "DELE %d\r\n",download);
nRet = SSL_write(ssl, // socket
gszTemp, // data buffer
strlen(gszTemp)// length of data
);// send flags
}
wsprintf(gszTemp, "QUIT\r\n");
nRet = SSL_write(ssl, // socket
gszTemp, // data buffer
strlen(gszTemp)// length of data
);// send flags
gnAppState = STATE_QUIT;
}
else{// by uyama
sbuf = lpStr;
sbuf += "\n";
pDoc->Mailstrs.Add(sbuf);//lpSt + "\n";
}
break;

case STATE_QUIT:

SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
ERR_free_strings();

CloseSocket(sock);

if((state == -STATE_LIST ) || (state == -STATE_RETR)){

}else{
pDoc->m_pTreeView->nImageID = 1;
if(reached == download){
pDoc->m_pListView->ShowReceived();
}
if(reached>download){
in_header = 1;
pDoc->Mailstrs.RemoveAll();
((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar.SetWindowText("メール受信中です、しばらくお待ちください。");
GmailMailDL();
((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar.SetWindowText("終了。");
}
}
}
}



void CSQMailBoxTreeView::GmailProcessData(LPSTR lpBuf, int nBytesRead)
{
static char szResponse[4096];
static int nLen = 0;
char *cp;

// Is there enough room in our buffer for the new data?
if ((nLen + nBytesRead) > sizeof(szResponse)){
MessageBox("Buffer overrun, data truncated","Error",MB_OK);
nLen = 0;
szResponse[0] = '\0';
return;
}
// Append the new data to our buffer
strcat_s(szResponse, sizeof(szResponse), lpBuf);
nLen = strlen(szResponse);

// Process all full lines
while(1){
// Does the buffer contain a full line?
cp = strchr(szResponse, '\n');
if (cp == NULL)
break;
// We have a CR/LF pair
// Replace the LF with a NULL
*cp = '\0';
// And pass it to the ProcesLine() function
GmailProcessLine( szResponse);

// Move the remaining data to the front
// of the buffer
cp++;
if (strlen(cp))
memmove(szResponse, cp, strlen(cp)+1);
else
szResponse[0] = '\0';
}

}

お礼日時:2013/07/30 22:31

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!