左の図はOutlook Expressから送信したメールを受信したときの
ものです。本文にはわざと1バイト文字と2バイト文字を
混在させています。サーバーからの返事はステータスバーに
表示するようにしました。
では、プログラムを見てみましょう。
mail02.rcとmail03.rcに変更はありません。
コモンコントロール(ステータスバー)を使うので、その準備を 忘れないでください。(commctrl.hのインクルード、comctl32.libのリンクなど)// 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;
これは、いつもと同じです。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; }
WM_CREATEが来たら、コモンコントロールを初期化して、エディットコントロール、 ステータスバーを作ります。//ウィンドウプロシージャ 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_SIZEが来たら、エディットコントロールとステータスバーの大きさを調整します。
メニューからIDM_RCVが選択されたらMyRcv関数を呼びますが、引数が以前より 増えているので注意してください。
これらの関数は第230章を参照してください。MyConnect, MyDlgProc, MySettingProc, MyPopSetProcの各関数に変更はありません。
引数が増えたので注意してください。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 関数をそのまま流用しています。
MyJisToSJis関数は第231章を参照してください。GetMailSize, MyJisToSJis関数に変更はありません。
これで何とかメールの本文は読めるようになりました。しかし、サブジェクト部分は まだ読めません。これは、ちょっと面倒です。研究してみてください。
Update 10/Oct/1999 By Y.Kumei