/* Import Library: Link with ws2_32.lib */
#include
<stdio.h>
#include <string.h>
#include
<mbstring.h>
#include <winsock2.h>
/**********************************************************************/
/*
文字列変換用関数
*/
//次の2つが外から呼ばれる
//void makeMineDecodeTable(void)
//int
mailconv(char *buff,int size)
//mime変換のためのテーブル
0123456789012345678901234567890123456789012345678901234567890123
const
char
MimeEncodeTable[70]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//逆mime変換のためのテーブル
char MimeDecodeTable[0x80];
//逆mime変換のためのテーブル作成(逆mime変換作業前に作っておく必要がある)
void
makeMineDecodeTable(void)
{
int
i;
for (i=0; i<0x40; i++)
MimeDecodeTable[MimeEncodeTable[i]]=i;
for (i=0;
i<0x80; i++) {
printf("
%02x,",MimeDecodeTable[i]);
if (i%0x10==0xf) printf("\n");
}
}
//文字列intext(mime
encoded)を文字列otext(normal)に変換
//otextの有効文字数を返す
int
PureMimeDecode(char *intext, char *otext)
{
char
*p;
char three[4]="ABC";
unsigned long int x;
int
del,op,len,i;
len=strlen(intext);
del=0;
if
(len) {
while
(intext[len-1-del]=='=') del++;
}
//printf("del=%d\n",del);
op=0;
p=intext;
while (*p)
{
x=MimeDecodeTable[*p++];
//123456
x<<=6;
//123456000000
if (!*p)
break;
x|=MimeDecodeTable[*p++];
//123456123456
x<<=6;
//123456123456000000
if
(!*p) break;
x|=MimeDecodeTable[*p++];
//123456123456123456
x<<=6;
//123456123456123456000000
if (!*p) break;
x|=MimeDecodeTable[*p++];
//123456123456123456123456
three[2]=(char)x;
x>>=8;
three[1]=(char)x;
x>>=8;
three[0]=(char)x;
for (i=0;
i<3; i++,op++) otext[op]=three[i];
}
otext[op]=0;
return
op-del;
}
//文字列intext(mime
encoded)を文字列otext(normal)に変換
//otextの有効文字数を返す
int MimeDecode(char
*intext, char *otext)
{
char
*p,*q;
int num;
q=NULL;
if (strstr(intext,"=?ISO-2022-JP?B?"))
{
q=strstr(intext,"?=");
if
(q) *q=0;
p=intext+strlen("=?ISO-2022-JP?B?");
} else
{
p=intext;
}
num=PureMimeDecode(p,otext);
if (q)
*q='?';
return num;
}
//strstr start From First character with toupper
int strstrfftu(char
*str, char *key)
{
int
same=1;
char tmp;
while (*key)
{
tmp=toupper(*str);
if
(tmp!=*key)
{
same=0;
break;
}
key++;
str++;
}
return same;
}
//文字列intext(mime encoded)を文字列otext(normal)に変換
//混合文字列に対して行う
void
strMimeDecode(char *intext, char *otext)
{
char
*next;
char tmp[10*1024];
while (*intext) {
if
(strstrfftu(intext,"=?ISO-2022-JP?B?"))
{
next=strstr(intext,"?=")+2;
MimeDecode(intext,tmp);
strcpy(otext,tmp);
otext+=strlen(tmp);
intext=next;
} else
{
*otext++=*intext++;
}
}
}
//文字列jistext(JIS)を文字列sjistext(Shift JIS)に変換
//改行は\r\nから\nに変換
void
Jisstr2Sjisstr(char *jistext, char *sjistext)
{
char one[4]="A";
char
two[4]="AB";
unsigned short int
sjis,jis;
const char shiftin[4]={ 0x1b, 0x24, 0x42,
0 };
const char shiftout[4]={ 0x1b, 0x28, 0x42, 0
};
unsigned char *p=(unsigned char
*)jistext;
int kanjimode=0;
while (*p) {
if
(strstr((char *)p,shiftin)==(char *)p)
{
p+=2;
kanjimode=1;
} else if
(strstr((char *)p,shiftout)==(char *)p)
{
p+=2;
kanjimode=0;
} else if
(kanjimode==1)
{
jis=((*p)<<8);
p++;
if (!(*p))
break;
jis+=((*p)&0xff);
sjis=_mbcjistojms(jis);
sjistext[1]=(char)sjis;
sjistext[0]=(char)(sjis>>8);
sjistext+=2;
} else if
(*p=='\r')
{
/*コピーしない*/
} else
{
*sjistext++=*p;
}
p++;
}
*sjistext=0;
}
//\nの次がスペースやタブだったら詰める(改行は\nのみの文字列が対象)
void reduceLine(char *in, char
*out)
{
while (*in && *in!='\n')
*out++=*in++;
while (*in)
{
if (*in=='\n' &&
(in[1]==' ' || in[1]=='\t'))
{
in+=2;
while (*in==' ' ||*in=='\t')
in++;
}
*out++=*in++;
}
*out=0;
}
//buffの位置から走査し最初の「"」から次の「"」までの文字列を抜き出す
void getquateword(char *buff,
char *txt)
{
while (*buff!='\"')
buff++;
buff++;
while
(*buff!='\"') *txt++=*buff++;
*txt=0;
}
//buffの位置から\r\nまでを抜き出しlineにコピーする
//buffの位置の次の行の先頭を返す
//lineに\r\nは含ませない
char
*getline(char *buff,char *line)
{
while(buff[0]!='\r'||buff[1]!='\n') *line++=*buff++;
*line=0;
return buff+2;
}
//各キーワードごとの表示にする
/* 例
+OK 2152 octets
Return-Path:
<xxxxx@tokyo-ct.ac.jp>
Received: from pwm-rg500-01.portmail.jp
(pwm-rg500-01.portmail.jp [10.56.25.21])by pwm-m500-01.portmail.jpwith
ESMTP id AEX53608;Sat, 22 Nov 2008 17:42:33 +0900 (JST)
Received: from
localhost (localhost [127.0.0.1])by pwm-rg500-01.portmail.jp (MOS
3.8.4-GA)id AJQ57917;Sat, 22 Nov 2008 17:42:33 +0900 (JST)
Received:
from pwm-rg100-04.portmail.jp (pwm-rg100-04.portmail.jp [10.56.25.42])by
pwm-rg500-01.portmail.jpwith ESMTP id AJQ57913;Sat, 22 Nov 2008 17:42:33
+0900 (JST)
Received: from pwm-m500-01.portmail.jp
(pwm-m500-01.portmail.jp [10.56.25.10])by pwm-rg100-04.portmail.jpwith
ESMTP id AID70274;Sat, 22 Nov 2008 17:42:32 +0900 (JST)
Received: (from
pwm-m500-01.portmail.jp [10.56.25.31])by pwm-m500-01.portmail.jp (MOS
3.8.4-GA)with HTTP/1.1 id AEX53602 (AUTH xxxxxx@tokyo-ct.ac.jp);Sat, 22
Nov 2008 17:42:32 +0900 (JST)
From: xxxxxx
<xxxxxx@tokyo-ct.ac.jp>
Subject: 11月29日の件
To:
xxxx@tokyo-ct.ac.jp, xxxxx@tokyo-ct.ac.jp,
xxxxxx@tokyo-ct.ac.jp,xxxxxxx@tokyo-ct.ac.jp, xxxxxx@tokyo-ct.ac.jp
Cc:
xxxxx@tokyo-ct.ac.jp, xxxxx@tokyo-ct.ac.jp,
xxxxx@tokyo-ct.ac.jp
X-Mailer: bbbbb Webmail Direct
3.8.4-GA
MIME-Version: 1.0
Content-Type: text/plain;
charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit
Message-Id:
<20081122174232.AEX53602@pwm-m500-01.portmail.jp>
Date: Sat, 22
Nov 2008 17:42:32 +0900 (JST)
X-Junkmail-Status: score=10/50,
host=pwm-rg100-04.portmail.jp
X-Junkmail-SD-Raw:
score=unknown,refid=str=0001.0A150203.4927C5F9.0032,ss=1,fgs=0,ip=10.56.25.10,so=2007-08-24
13:43:07,dmn=5.7.1/2008-09-02
X-bbbbb-Loop-Id:
bc332aab06d972e19852c1a25e6e711ebc332aab06d972e19852c1a25e6e711e
Body:
XXXX様
XXXX様
XXXX様
XXXX様
XXXX様
XXXX様
お世話になっております。XX工学科のXXです。
11月29日(土)の会議は、
12:00からXXX室で実施することになりました。
休日のところ、大変恐縮ですが、
11:30にXXX室にご集合いただきたく、
よろしくお願いいたします。
*/
int
mailconv(char *buff,int size)
{
char
*headerend,*p;
char
boundarystr[128];
char *body;
buff[size]=0;
headerend=strstr(buff,"\r\n\r\n");
if (headerend)
*headerend=0;
body=headerend+4;
strMimeDecode(buff,buff);
Jisstr2Sjisstr(buff,buff);
reduceLine(strchr(buff,'\n')+1,buff);
// reduceLine(buff,buff);
p=strstr(buff,"boundary=");
if (p)
{
getquateword(p,boundarystr);
if(p)
{
p=strstr(body,boundarystr);
p=strstr(p,"\r\n\r\n");
body=p+4;
p=strstr(body,boundarystr);
if (p)
{
*p--=0;
while (*p!='\n')
*p--=0;
*p--=0;*p--=0;
p--;
if (p[0]=='\r' && p[1]=='\n')
p[0]=0;
}
}
}
else {
p=strstr(body,"\r\n.\r\n");
if (p) *p=0;
}
Jisstr2Sjisstr(body,body);
strcat(buff,"\nBody:
\n");
strcat(buff,body);
return strlen(buff);
}
/**********************************************************************/
/*ソケットsに文字列データdataを送信する関数*/
void sendData(SOCKET
s, char *data)
{
send(s,data,strlen(data),0);
}
/*ソケットsからバッファサイズbuffsizeのデータバッファdatabuffに
データを受け取る関数 返す値は取得バイト数*/
int
receiveData(SOCKET s, char *databuff, int
buffsize)
{
char
*p=databuff;
int i;
for
(i=0;i<buffsize;i++) *p++=0;
return
recv(s,databuff,buffsize,0);
}
/**************** for printing information
HEAD ************************/
#ifdef REQUEST_INFO
void
printWinsockInfo(WSADATA *wsaData)
{
union
{
short int
s;
unsigned char
c[2];
} v,hv;
if
(wsaData==NULL) return;
v.s=wsaData->wVersion;
hv.s=wsaData->wHighVersion;
printf("== winsock
information ==\n");
printf("winsock
version = %d.%d\n",v.c[0],v.c[1]);
printf("winsock HighVer =
%d.%d\n",hv.c[0],hv.c[1]);
printf("Description =
%s\n",wsaData->szDescription);
printf("SystemStatus = %s\n"
,wsaData->szSystemStatus);
printf("Max
Sockets = %d\n"
,wsaData->iMaxSockets);
printf("Max UDP byte size
= %d\n" ,wsaData->iMaxUdpDg);
printf("\n");
}
void printServerInfo(LPHOSTENT
lpHost)
{
int i;
if
(lpHost==NULL) return;
printf("== server information
==\n");
printf("host
name = %s\n" ,
lpHost->h_name);
printf("address type
= %d\n" , lpHost->h_addrtype); /*AF_INETは2*/
printf("address length = %d\n" ,
lpHost->h_length);
for(i = 0 ;
lpHost->h_aliases[i] ; i++)
{
printf("aliases = %s\n" ,
lpHost->h_aliases[i]);
}
for(i = 0 ;
lpHost->h_addr_list[i] ; i++)
{
IN_ADDR
*ip;
ip = (IN_ADDR
*)lpHost->h_addr_list[i];
printf("IP address = %s\n" ,
inet_ntoa(*ip));
}
printf("\n");
}
void printServiceInfo(LPSERVENT
lpServ)
{
int i;
if
(lpServ==NULL) return;
printf("== service
information ==\n");
printf("service name = %s\n" ,
lpServ->s_name);
for(i = 0 ;
lpServ->s_aliases[i] ; i++)
{
printf("aliases = %s\n" ,
lpServ->s_aliases[i]);
}
printf("port number = %d\n" ,
lpServ->s_port);
printf("protocol = %s\n" ,
lpServ->s_proto);
printf("\n");
}
void
printPortInfo(int port)
{
printf("== port number
information ==\n");
printf("port number = %d\n" ,
ntohs((short)port));
/*ntohsはホストバイトオーダーに戻す関数*/
printf("\n");
}
#endif
/**************** for printing
information TAIL ************************/
/************************************************************
ソケットをオープンし,目的のサーバのポートに接続する
server:
サーバの名前(ドメイン名,ドメインを省略してはいけない)
例えばaaaa.tokyo-ct.ac.jp
servicename:"smtp"とか"http"などのサービスの名前,
次のところに名前の一覧がある
Windowsシステムのsystem32\drivers\etc\services
service:
サービスのポート番号,smtpなら25,httpなら80など
この情報は,servicenameが不明の場合に必要なだけで,
通常は使われない
不成功ならINVALID_SOCKETを返す
*************************************************************/
SOCKET
connectSocket(const char *server, char *servicename, short int
service)
{
WSADATA wsaData;
/*winsock*/
LPHOSTENT lpHost;
LPSERVENT lpServ;
SOCKET sock;
SOCKADDR_IN sockAddr;
int port;
/*ポート番号*/
int status;
/*winsockをver1.1で初期化を要求*/
status=WSAStartup(MAKEWORD(1, 1), &wsaData);
if
(status != 0) {
fprintf(stderr,"WSAStartup()
failed\n");
return
INVALID_SOCKET;
}
/*サーバ名からホストの情報を得る*/
lpHost =
gethostbyname(server);
if(lpHost == NULL)
{
fprintf(stderr,"server
name error\n");
WSACleanup();
return
INVALID_SOCKET;
}
/*サービス情報からポート番号取得*/
lpServ =
getservbyname(servicename, NULL);
if (lpServ ==
NULL) {
port=htons(service);
/*ホストバイトオーダーからネットワークバイトオーダー(ビッグエンディアン)に変換*/
} else
{
port=lpServ->s_port;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printWinsockInfo(&wsaData);
/*Winsocの情報表示*/
printServerInfo(lpHost);
/*サーバの情報表示*/
printServiceInfo(lpServ);
/*サービスの情報表示*/
printPortInfo(port);
/*ポート番号の情報表示*/
#endif
/*ソケットオープン*/
sock = socket(PF_INET, SOCK_STREAM,
0);
if (sock == INVALID_SOCKET)
{
fprintf(stderr,"socket()
error\n");
WSACleanup();
return
INVALID_SOCKET;
}
/*ソケット結合*/
sockAddr.sin_family = AF_INET;
sockAddr.sin_port =
port;
sockAddr.sin_addr =
*((LPIN_ADDR)*lpHost->h_addr_list);
status=connect(sock, (PSOCKADDR)&sockAddr,
sizeof(SOCKADDR_IN));
if (status)
{
fprintf(stderr,"connect()
error\n");
closesocket(sock);
WSACleanup();
return
INVALID_SOCKET;
}
return
sock;
}
#define sndBufSize 1024
#define rcvBufSize 1024*1024
//#define
rcvBufSize 100*1024+535
static char
sndBuf[sndBufSize],rcvBuf[rcvBufSize];
//最終バイトのアドレスより終了形かどうかを判定
//size直前の読み出しバイト数
int isTail(char
*lastbyte, int size)
{
char
*p1=lastbyte-3;
int result=0;
if (3<size) {
if
(p1[0]=='\n' && p1[1]=='.' && p1[2]=='\r' &&
p1[3]=='\n') result=1;
} else if (size==3)
{
if (p1[1]=='.' &&
p1[2]=='\r' && p1[3]=='\n') result=1;
} else
if (size==2) {
if
(p1[2]=='\r' && p1[3]=='\n') result=1;
}
else if (size==1) {
if
(p1[3]=='\n') result=1;
}
return result;
}
/*メールおよびリスト専用でソケットsからバッファサイズbuffsizeのデータバッファdatabuffに
データを受け取る関数 返す値は取得バイト数
失敗の場合は0を返す*/
int receiveMailData(SOCKET s, char *databuff, int
buffsize, int limit)
{
int
totalsize,size,completed;
static char
throwaway[1024],*throwaway3=throwaway+3;
char
*p;
totalsize=0;
do
{
size=receiveData(s,
databuff+totalsize,
buffsize-totalsize);
totalsize+=size;
Sleep(10);
if (1<size
&& databuff[0]=='-')
{
databuff[0]=0;
return 0;
}
completed=isTail(databuff+totalsize-1,size);
printf("[size,totalsize= %d
%d]\n",size,totalsize);
p=databuff+totalsize-1;
} while (!completed
&& totalsize<limit);
while (!completed)
{
throwaway[0]=p[-2];
throwaway[1]=p[-1];
throwaway[2]=p[0];
size=receiveData(s, throwaway3,
1000);
Sleep(10);
printf(size!=1000?"[size=
%d]\n":".",size);
completed=isTail(throwaway3+size-1,size);
p=throwaway3+size-1;
}
printf("xxx %d\n",totalsize);
return
totalsize;
}
/*loginし,メールリストを表示して終了する*/
int pop3(const char *server,const
char *user, const char *pass)
{
SOCKET
sock;
int loop=1, mailID;
char
buff[128];
FILE *fp;
char
fname[128];
int totalsize;
/*POPサーバへの接続*/
sock=connectSocket(server,"pop3",110);
if (sock ==
INVALID_SOCKET) return 1;
printf("connecting
Socket\n");
/*サーバから受信*/
receiveData(sock,rcvBuf,rcvBufSize);
printf("receiving : %s\n",rcvBuf);
/*ユーザlogin*/
sprintf(sndBuf,"USER %s\r\n",user);
sendData(sock,
sndBuf);
printf("sending :
%s",sndBuf);
receiveData(sock,rcvBuf,rcvBufSize);
printf("receiving : %s\n",rcvBuf);
/*パスワード*/
sprintf(sndBuf,"PASS
%s\r\n",pass);
sendData(sock,
sndBuf);
printf("sending :
%s",sndBuf);
receiveData(sock,rcvBuf,rcvBufSize);
printf("receiving : %s\n",rcvBuf);
while (loop)
{
printf("\n\n*********** menu
***********\n");
printf(" L : print mail
list\n");
printf("number :
save the mail in the mail
list\n");
printf(" Q :
quit\n");
printf(">");
gets(buff);
if (buff[0]=='L'
|| buff[0]=='l' )
{
/*メールリストの取得*/
sprintf(sndBuf,"LIST\r\n");
sendData(sock,
sndBuf);
printf("sending :
%s",sndBuf);
Sleep(100);
totalsize=receiveMailData(sock,rcvBuf,rcvBufSize,(int)(rcvBufSize*0.9));
printf("receiving :
%s\n",rcvBuf);
printf("[totalsize=
%d]\n",totalsize);
Sleep(100);
fp=fopen("maillist.txt","wb");
fwrite(rcvBuf,totalsize,1,fp);
fclose(fp);
} else if
(buff[0]=='Q' || buff[0]=='q' ) {
/*終了*/
sprintf(sndBuf,"QUIT\r\n");
sendData(sock,
sndBuf);
printf("sending :
%s",sndBuf);
Sleep(500);
receiveData(sock,rcvBuf,rcvBufSize);
printf("receiving :
%s\n",rcvBuf);
Sleep(500);
loop=0;
} else if
(sscanf(buff,"%d",&mailID)==1)
{
rcvBuf[0]=0;
sprintf(sndBuf,"RETR %d\r\n",
mailID);
sendData(sock,
sndBuf);
printf("sending :
%s",sndBuf);
Sleep(100);
totalsize=receiveMailData(sock,rcvBuf,rcvBufSize,(int)(rcvBufSize*0.9));
rcvBuf[totalsize]=0;
printf("receiving : %s\n",rcvBuf);
if
(totalsize!=0) totalsize=mailconv(rcvBuf,
totalsize);
rcvBuf[totalsize]=0;
printf("[totalsize= %d]\n",totalsize);
sprintf(fname,"mail%05d.txt",mailID);
fp=fopen(fname,"w");
fputs(rcvBuf,
fp);
fclose(fp);
printf("Completed\n");
}
}
closesocket(sock);
WSACleanup();
return 0;
}
int
main()
{
makeMineDecodeTable();
pop3(servername,username,password);
getchar();
return
0;
}