第234章 JISで送信する


メールを送信するとき、1行1行本文を入力していくのは、あまりにも めんどうです。また本文をJISに変換して送信する必要があります。 今回は送信部分を改良してみます。



メニューの「送信」を選択すると左のようなダイアログボックスが 出てきますので、必要事項を記入して「送信」ボタンを押します。

まだ、今回のプログラムでは「件名」に日本語は使えません。これには MIMEの知識が必要となります。

送信時の、サーバーからの返事はメインウィンドウのステータスバーに 表示されます。



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

// mail04.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "送信(&S)...", IDM_CONNECT MENUITEM "受信(&R)...", IDM_RCV MENUITEM SEPARATOR MENUITEM "終了(&X)...", IDM_END END POPUP "オプション(&O)" BEGIN MENUITEM "SMTPの設定(&S)...", IDM_SETSMTP MENUITEM "POP3の設定(&P)...", IDM_SETPOP END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 187, 53 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "文字列入力" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,7,7,173,20,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,7,32,50,14 PUSHBUTTON "キャンセル",IDCANCEL,130,32,50,14 END MYSETDLG DIALOG DISCARDABLE 0, 0, 187, 89 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "設定" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,78,7,102,12,ES_AUTOHSCROLL EDITTEXT IDC_EDIT2,78,25,102,12,ES_AUTOHSCROLL EDITTEXT IDC_EDIT3,78,43,102,12,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,27,68,50,14 PUSHBUTTON "キャンセル",IDCANCEL,103,68,50,14 LTEXT "SMTPアドレス",IDC_STATIC,7,7,41,8 LTEXT "差出人メールアドレス",IDC_STATIC,7,29,63,8 LTEXT "返信",IDC_STATIC,7,47,15,8 END MYPOPDLG DIALOG DISCARDABLE 0, 0, 158, 77 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "POP3設定" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,53,7,98,12,ES_AUTOHSCROLL EDITTEXT IDC_EDIT2,53,22,98,12,ES_AUTOHSCROLL EDITTEXT IDC_EDIT3,53,37,98,12,ES_PASSWORD | ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,7,56,50,14 PUSHBUTTON "キャンセル",IDCANCEL,101,56,50,14 LTEXT "POP3サーバー",IDC_STATIC,7,11,44,8 LTEXT "ユーザー名",IDC_STATIC,7,26,35,8 LTEXT "パスワード",IDC_STATIC,7,41,32,8 END MYNEWMAIL DIALOG DISCARDABLE 0, 0, 187, 187 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "新規メール" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,43,7,137,13,ES_AUTOHSCROLL EDITTEXT IDC_EDIT2,43,25,137,13,ES_AUTOHSCROLL EDITTEXT IDC_EDIT3,7,47,173,110,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL DEFPUSHBUTTON "送信",IDOK,7,166,50,14 PUSHBUTTON "取り消し",IDCANCEL,130,166,50,14 LTEXT "あて先",IDC_STATIC,7,7,20,8 LTEXT "件名",IDC_STATIC,7,25,15,8 END

今までに比べてMYNEWMAILダイアログボックスの部分が増えました。

// mail04.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); LRESULT CALLBACK MyNewMailProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void MySnd(HWND, char *, char *, char *); void MyRcv(HWND, HWND, HWND); int GetMailSize(char *); void MyJisToSJis(char *, char *); void MySJisToJis(char *, char *); char szClassName[] = "mail04"; //ウィンドウクラス 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;

新しく作ったダイアログボックスのプロシージャが増えました。

MyConnectと名づけていた関数を内容から考えてMySndに改名しました。引数も 変更になっています。

S-JISからJISに変換する関数も増えました。

WinMain, InitApp, InitInstanceの各関数に変更はありません。

//ウィンドウプロシージャ 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: DialogBoxParam(hInst, "MYNEWMAIL", hWnd, (DLGPROC)MyNewMailProc, (LPARAM)hStatus); 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; }

メニューから「送信」(IDM_CONNECT)を選択したときの処理が変更になっています。

void MySnd(HWND hStatus, char *lpszTo, char *lpszSubject, char *lpszMail) { WSADATA wsaData; LPHOSTENT lpHost; LPSERVENT lpServ; SOCKET s; int iProtocolPort; SOCKADDR_IN sockadd; char *seps = "\r", *token; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) { MessageBox(NULL, "エラーです", "Error", MB_OK); return; } if (strcmp(szServerName, "") == 0) { MessageBox(NULL, "サーバーアドレスを入力してください。", "サーバー", MB_OK); DialogBox(hInst, "MYDLG", hStatus, (DLGPROC)MyDlgProc); strcpy(szServerName, szStr); } lpHost = gethostbyname(szServerName); if (lpHost == NULL) { wsprintf(szStr, "%sが見つかりません", szServerName); MessageBox(NULL, szStr, "Error", MB_OK); return; } s = socket(PF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { MessageBox(NULL, "ソケットをオープンできません", "Error", MB_OK); return; } lpServ = getservbyname("mail", NULL); if (lpServ == NULL) { MessageBox(NULL, "ポート指定がされていないので、デフォルトを使います", "OK", MB_OK); iProtocolPort = htons(IPPORT_SMTP); } else { iProtocolPort = lpServ->s_port; } sockadd.sin_family = AF_INET; sockadd.sin_port = iProtocolPort; sockadd.sin_addr = *((LPIN_ADDR)*lpHost->h_addr_list); if (connect(s, (PSOCKADDR)&sockadd, sizeof(sockadd))) { MessageBox(NULL, "サーバーソケットに接続失敗", "Error", MB_OK); return; } memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, 0 | 0, (LPARAM)szStrRcv); strcpy(szStr, "HELO "); strcat(szStr, szServerName); strcat(szStr, "\r\n"); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, 0 | 0, (LPARAM)szStrRcv); if (strcmp(szFrom, "") == 0) { MessageBox(NULL, "差出人メールアドレスを入力してください", "差出人", MB_OK); DialogBox(hInst, "MYDLG", hStatus, (DLGPROC)MyDlgProc); strcpy(szFrom, szStr); } wsprintf(szStr, "MAIL FROM : <%s>\r\n", szFrom); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, 0 | 0, (LPARAM)szStrRcv); wsprintf(szStr, "RCPT TO :<%s>\r\n", lpszTo); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, 0 | 0, (LPARAM)szStrRcv); strcpy(szStr, "DATA\r\n"); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, 0 | 0, (LPARAM)szStrRcv); strcpy(szStr, "X-Mailer: Nekodemo_Wakaru-Mailer\r\n"); send(s, szStr, strlen(szStr), 0); if (strcmp(szReplyTo, "") != 0) { wsprintf(szStr, "Reply-To: %s\r\n", szReplyTo); send(s, szStr, strlen(szStr), 0); } wsprintf(szStr, "Subject: %s \r\n", lpszSubject); send(s, szStr, strlen(szStr), 0); //ここでもう一度「\r\n」を送信しておかないと //本文に日本語を使う場合1行目が文字化けします strcpy(szStr, "\r\n"); send(s, szStr, strlen(szStr), 0); token = strtok(lpszMail, seps); while (token != NULL) { if (token[0] == '\n') { strcpy(szStr, token + 1); } else { strcpy(szStr, token); } strcat(szStr, "\r\n"); send(s, szStr, strlen(szStr), 0); token = strtok(NULL, seps); } strcpy(szStr, ".\r\n"); send(s, szStr, strlen(szStr), 0); memset(szStrRcv, '\0', sizeof(szStrRcv)); recv(s, szStrRcv, sizeof(szStrRcv), 0); SendMessage(hStatus, SB_SETTEXT, 0 | 0, (LPARAM)szStrRcv); 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, 0 | 0, (LPARAM)szStrRcv); closesocket(s); WSACleanup(); SendMessage(hStatus, SB_SETTEXT, 0 | 0, (LPARAM)"通信を終了しました"); return; }

基本的には前章までのMyConnect関数と同じですが、サーバーからの 返事をメッセージボックスで表示していたのをステータスバーに表示するようにしました。

lpszMail(ダイアログのエディットコントロールから取得した本文)を改行で 切り分けて1行ずつ送信しています。このとき活躍するstrtok関数については 第78章を参照してください。

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

LRESULT CALLBACK MyNewMailProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hTo, hSubject, hMail, hStatus; char szTo[256], szSubject[256], *lpszMail, *lpszResult; int iLen; HGLOBAL hMem, hResult; switch (msg) { case WM_INITDIALOG: hTo = GetDlgItem(hDlg, IDC_EDIT1); hSubject = GetDlgItem(hDlg, IDC_EDIT2); hMail = GetDlgItem(hDlg, IDC_EDIT3); hStatus = (HWND)lp; return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: Edit_GetText(hTo, szTo, sizeof(szTo)); Edit_GetText(hSubject, szSubject, sizeof(szSubject)); iLen = Edit_GetTextLength(hMail) + 1; hMem = GlobalAlloc(GHND, iLen); hResult = GlobalAlloc(GHND, iLen + 1024); if (hMem == NULL || hResult == NULL) { MessageBox(hDlg, "メモリの確保に失敗しました", "Error", MB_OK); return FALSE; } lpszMail = (char *)GlobalLock(hMem); lpszResult = (char *)GlobalLock(hResult); Edit_GetText(hMail, lpszMail, iLen); MySJisToJis(lpszMail, lpszResult); MySnd(hStatus, szTo, szSubject, lpszResult); GlobalUnlock(hMem); GlobalFree(hMem); GlobalUnlock(hResult); GlobalFree(hResult); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }

「送信」ボタンが(IDOK)押されたら本文文字列を取得して、これをJISに変換します。 そしてMySnd関数に送ります。

void MySJisToJis(char *lpszOrg, char *lpszDest) { int i = 0, iR = 0, c; BOOL bSTART = FALSE; while (1) { if (_ismbblead(lpszOrg[i]) && bSTART == FALSE) { lpszDest[iR] = 0x1b; lpszDest[iR + 1] = 0x24; lpszDest[iR + 2] = 0x42; c = MAKEWORD(lpszOrg[i + 1], lpszOrg[i]); lpszDest[iR + 3] = (char)HIBYTE(_mbcjmstojis(c)); lpszDest[iR + 4] = (char)LOBYTE(_mbcjmstojis(c)); bSTART = TRUE; i += 2; iR += 5; if (!_ismbblead(lpszOrg[i])) { lpszDest[iR] = 0x1b; lpszDest[iR + 1] = 0x28; lpszDest[iR + 2] = 0x42; bSTART = FALSE; iR += 3; } continue; } if (_ismbblead(lpszOrg[i]) && bSTART) { c = MAKEWORD(lpszOrg[i + 1], lpszOrg[i]); lpszDest[iR] = (char)HIBYTE(_mbcjmstojis(c)); lpszDest[iR + 1] = (char)LOBYTE(_mbcjmstojis(c)); i += 2; iR += 2; if (!_ismbblead(lpszOrg[i])) { lpszDest[iR] = 0x1b; lpszDest[iR + 1] = 0x28; lpszDest[iR + 2] = 0x42; bSTART = FALSE; iR += 3; } continue; } if (lpszOrg[i] == '\r') { lpszDest[iR] = '\n'; i += 2; iR++; continue; } if (lpszOrg[i] == '\0') { lpszDest[iR] = lpszOrg[i]; break; } lpszDest[iR] = lpszOrg[i]; iR++; i++; } return; }

S-JISをJISに変換する関数です。 第232章のものをそのまま流用しています。

さて、今回で一応メールの送受信ができるようになりました。 残る大仕事?はヘッダ部分に日本語を埋め込んだり、埋め込まれた 日本語を解読することです。いろいろ調べてみてください。


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

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