[Intel Mac, Big Sur 11.6.5, clang 13.0.0, NO IDE]
『C言語によるTCP/IPネットワークプログラミング』(2001年)第2章 SMTPプロトコルの所を学習しています。
仮想SMTPサーバー FakeSMTPにメールを送信しデータのやり取りをさせました。
サンプルコードにあったEUC-JP→ISO-2022-JP変換関数とBase64変換関数は大幅に変更しました。EUC-JP→ISO-2022-JP変換(MacはUTF-8から変換)はネットにあったコードを丸々拝借しました。libiconvライブラリを使用します。Base64変換についてはclxライブラリをダウンロードして使っています。これによりcppファイル2つを削減しました。
FakeSMTPのソースコードを入手しM1 Macでビルドしたものの、残念ながら起動しませんでした。
Apple Silicon版仮想SMTPサーバーを自製できれば良いのですが。
#include <mailtest.h>
#include <clx/base64.h>
int main(int argc,char *argv[])
{
struct passwd *pwd;
char hostname[MAXHOSTNAMELEN+1];
time_t t;
char from[65];
char b_subject[1024];
char j_data[1024*2];
char *ptr;
char buf[1024];
char boundary[80];
char *f_buf,*b_buf;
FILE *fpd;
struct stat st;
int i;
int soc;
if(argc <= 1){
fprintf(stderr,"mailtest recpient [file] [file] ...\n");
return 0;
}
// JIS:Base64のサブジェクトを標準入力から取得
GetSubject(b_subject);
// 本文データを標準入力から取得
GetData(j_data);
cout << "GetData pass" << endl;
// 送信者設定
pwd = getpwuid(getuid());
gethostname(hostname,MAXHOSTNAMELEN);
sprintf(from,"%s@%s",pwd->pw_name,hostname);
cout << "from: " << from << endl;
// ローカルホストのSMTPに接続
if((soc = ConnectHost("localhost","smtp",25)) == -1){
fprintf(stderr,"Cannot connect to local smtp.\n");
return 0;
}
// SMTPとの通信
SOCprintf(soc,"HELO %s\r\n",hostname);
SOCrecv(soc,buf);
SOCprintf(soc,"MAIL FROM:%s\r\n",from);
SOCrecv(soc,buf);
SOCprintf(soc,"RCPT TO:%s\r\n",argv[1]);
SOCrecv(soc,buf);
// データ送信開始
SOCprintf(soc,"DATA\r\n");
SOCrecv(soc,buf);
// ヘッダ部送信
t=time(&t);
SOCprintf(soc,"Date: %s",ctime(&t));
SOCprintf(soc,"From: %s\r\n",from);
SOCprintf(soc,"Subject: =?ISO-2022-JP?B?%s?=\r\n",b_subject);
SOCprintf(soc,"To: %s\r\n",argv[1]);
SOCprintf(soc,"MIME-Version: 1.0\r\n");
sprintf(boundary,"%010d_%09d",t,getpid()); // プロセスID取得
SOCprintf(soc,"Content-Type: MULTIPART/mixed; BOUNDARY=%s\r\n",boundary);
SOCprintf(soc,"\r\n");
// データ部送信
SOCprintf(soc,"--%s\r\n",boundary);
SOCprintf(soc,"Content-Type: TEXT/plain; charset=ISO-2022-JP\r\n");
SOCprintf(soc,"\r\n");
send(soc,j_data,strlen(j_data),0);
SOCprintf(soc,"\r\n");
// 添付ファイル送信
for(i = 2; i < argc; i++){
if((fpd = fopen(argv[i], "r"))!= NULL){
printf("argv[%d] %s\n",i,argv[i]);
fstat(fileno(fpd), &st); // ファイル状態を取得
f_buf=(char *)malloc(st.st_size);
b_buf=(char *)malloc(st.st_size * 2);
fread(f_buf, 1, st.st_size, fpd); // ファイルデータを1バイトずつ全サイズ分をf_bufに格納
fclose(fpd);
SOCprintf(soc,"--%s\r\n",boundary);
SOCprintf(soc,"Content-Type: application; name=%s; x-unix-mode=0777\r\n",argv[i]);
SOCprintf(soc,"Content-Transfer-Encoding: BASE64\r\n");
SOCprintf(soc,"Content-Description: %s\r\n",argv[i]);
SOCprintf(soc,"\r\n");
// Base64変換
string f_buf_str = string(f_buf);
string f_buf_64 = clx::base64::encode(f_buf_str);
f_buf_64.copy(b_buf, st.st_size *2 -1);
// base64(f_buf,st.st_size,b_buf); // base64関数は廃止
send(soc,b_buf,strlen(b_buf),0);
SOCprintf(soc,"\r\n");
SOCprintf(soc,"\r\n");
free(f_buf);
free(b_buf);
}
else{
fprintf(stderr,"%s cannot read.\n",argv[i]);
}
}
SOCprintf(soc,"--%s--\r\n",boundary);
// データ送信完了
SOCprintf(soc,".\r\n");
SOCrecv(soc,buf);
// 終了
SOCprintf(soc,"QUIT\r\n");
SOCrecv(soc,buf);
// ソケットクローズ
SocketClose(soc);
}
参考サイト