第233章 メール本文を読む


さて、今回は第231章で作ったJISからS-JISに変換する プログラムを利用して受信したメールを読んでみます。



左の図はOutlook Expressから送信したメールを受信したときの ものです。本文にはわざと1バイト文字と2バイト文字を 混在させています。サーバーからの返事はステータスバーに 表示するようにしました。



では、プログラムを見てみましょう。

mail02.rcとmail03.rcに変更はありません。

// mail03.cpp #ifndef STRICT #define STRICT #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #define ID_EDIT 100 #define ID_STATUS 101 #include <windows.h> #include <winsock2.h> #include <windowsx.h> #include <commctrl.h> #include <stdio.h> #include <stdlib.h> #include <mbstring.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MySettingProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyPopSetProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void MyConnect(HWND); void MyRcv(HWND, HWND, HWND); int GetMailSize(char *); void MyJisToSJis(char *, char *); char szClassName[] = "mail03"; //ウィンドウクラス char szStr[1024], szStrRcv[1024 * 50], szResult[1024 * 50]; char szServerName[256], szFrom[256], szReplyTo[256];//SMTP char szPopServer[256], szUserName[64], szPass[64];//POP3 HINSTANCE hInst;

コモンコントロール(ステータスバー)を使うので、その準備を 忘れないでください。(commctrl.hのインクルード、comctl32.libのリンクなど)

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるメーラー", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

これは、いつもと同じです。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HWND hEdit, hStatus; INITCOMMONCONTROLSEX ic; static int iStatusWy; RECT rc; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_BAR_CLASSES; InitCommonControlsEx(&ic); hEdit = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 0, 0, 0, 0, hWnd, (HMENU)ID_EDIT, hInst, NULL); hStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", hWnd, ID_STATUS); GetWindowRect(hStatus, &rc); iStatusWy = rc.bottom - rc.top; break; case WM_SIZE: MoveWindow(hEdit, 0, 0, LOWORD(lp), HIWORD(lp) - iStatusWy, TRUE); SendMessage(hStatus, WM_SIZE, wp, lp); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_SETSMTP: DialogBox(hInst, "MYSETDLG", hWnd, (DLGPROC)MySettingProc); break; case IDM_SETPOP: DialogBox(hInst, "MYPOPDLG", hWnd, (DLGPROC)MyPopSetProc); break; case IDM_CONNECT: MyConnect(hWnd); break; case IDM_RCV: MyRcv(hWnd, hEdit, hStatus); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

WM_CREATEが来たら、コモンコントロールを初期化して、エディットコントロール、 ステータスバーを作ります。

WM_SIZEが来たら、エディットコントロールとステータスバーの大きさを調整します。

メニューからIDM_RCVが選択されたらMyRcv関数を呼びますが、引数が以前より 増えているので注意してください。

MyConnect, MyDlgProc, MySettingProc, MyPopSetProcの各関数に変更はありません。

これらの関数は第230章を参照してください。

void MyRcv(HWND hWnd, HWND hEdit, HWND hStatus) { WSADATA wsaData; LPHOSTENT lpHost; SOCKET s; int iRtn, iNo, iMailSize, iGetSize; SOCKADDR_IN sockadd; char *lpszStr; HGLOBAL hMem; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) { MessageBox(hWnd, "エラーです", "Error", MB_OK); return; } while (strcmp(szPopServer, "") == 0 || strcmp(szUserName, "") == 0 || strcmp(szPass, "") == 0) { MessageBox(hWnd, "POP3の設定を行ってください。", "注意", MB_OK); DialogBox(hInst, "MYPOPDLG", hWnd, (DLGPROC)MyPopSetProc); } lpHost = gethostbyname(szPopServer); if (lpHost == NULL) { wsprintf(szStr, "%sが見つかりません", szPopServer); MessageBox(hWnd, szStr, "Error", MB_OK); return; } s = socket(PF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { MessageBox(hWnd, "ソケットをオープンできません", "Error", MB_OK); return; } sockadd.sin_family = AF_INET; sockadd.sin_port = htons(110);//POP3のポートは110番 sockadd.sin_addr = *((LPIN_ADDR)*lpHost->h_addr_list); if (connect(s, (PSOCKADDR)&sockadd, sizeof(sockadd))) { MessageBox(hWnd, "サーバーソケットに接続失敗", "Error", MB_OK); closesocket(s); WSACleanup(); return; } memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, (WPARAM)0 | 0, (LPARAM)szStrRcv); wsprintf(szStr, "USER %s\r\n", szUserName); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, (WPARAM)0 | 0, (LPARAM)szStrRcv); wsprintf(szStr, "PASS %s\r\n", szPass); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, (WPARAM)0 | 0, (LPARAM)szStrRcv); if (strstr(szStrRcv, "0 message") != NULL) { MessageBox(hWnd, "メッセージはありません", "No Message", MB_OK); strcpy(szStr, "QUIT\r\n"); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, (WPARAM)0 | 0, (LPARAM)szStrRcv); closesocket(s); WSACleanup(); return; } while (1) { iRtn = MessageBox(hWnd, "メールを読みますか", "Down Load", MB_YESNO); if (iRtn == IDYES) { Edit_SetText(hEdit, ""); MessageBox(hWnd, "メールの番号を入力してください", "NO", MB_OK); DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); iNo = atoi(szStr); wsprintf(szStr, "LIST %d\r\n", iNo); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStr)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, (WPARAM)0 | 0, (LPARAM)szStrRcv); iMailSize = GetMailSize(szStrRcv); iGetSize = 0; hMem = GlobalAlloc(GHND, iMailSize + 1024); if (hMem == NULL) { MessageBox(hWnd, "メモリを確保できません", "Error", MB_OK); closesocket(s); WSACleanup(); return; } lpszStr = (char *)GlobalLock(hMem); wsprintf(szStr, "RETR %d\r\n", iNo); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStrRcv)); iGetSize += recv(s, szStrRcv, sizeof(szStrRcv), 0); while (iMailSize >= iGetSize) { memset(szStrRcv, '\0', sizeof(szStrRcv)); iGetSize += recv(s, szStrRcv, sizeof(szStrRcv), 0); MyJisToSJis(szStrRcv, szResult); Edit_GetText(hEdit, lpszStr, iMailSize + 1024); strcat(lpszStr, szResult); Edit_SetText(hEdit, lpszStr); } GlobalUnlock(hMem); if (GlobalFree(hMem)) { MessageBox(hWnd, "メモリの開放に失敗しました", "Error", MB_OK); break; } } else { break; } } closesocket(s); WSACleanup(); MessageBox(hWnd, "通信を終了しました", "OK", MB_OK); return; }

引数が増えたので注意してください。

サーバーに接続後、サーバーからの返事はステータスバーに表示するようにしました。

サーバーにRETRを送信後は、サーバーからの返事はエディットコントロールに 表示するようにしました。ヘッダと本文を受け取るバッファは動的に確保するようにしました。 また、JISからS-JISへの変換は第231章で作ったMyJisToSJis 関数をそのまま流用しています。

GetMailSize, MyJisToSJis関数に変更はありません。

MyJisToSJis関数は第231章を参照してください。

これで何とかメールの本文は読めるようになりました。しかし、サブジェクト部分は まだ読めません。これは、ちょっと面倒です。研究してみてください。


[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 10/Oct/1999 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。