1 /* base64编码 */
2 static const char* base64_enc_map =
3 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4 int base64_encode( char* dst, size_t* dlen, const unsigned char* src, size_t slen )
5 {
6 size_t i, n;
7 int C1, C2, C3;
8 char* p;
9
10 if ( slen == 0 )
11 {
12 return 0;
13 }
14
15 n = ( slen << 3 ) / 6;
16
17 switch ( ( slen << 3 ) - ( n * 6 ) )
18 {
19 case 2:
20 n += 3;
21 break;
22 case 4:
23 n += 2;
24 break;
25 default:
26 break;
27 }
28
29 if ( *dlen < n + 1 )
30 {
31 *dlen = n + 1;
32 return -1;
33 }
34
35 n = ( slen / 3 ) * 3;
36 for ( i = 0, p = dst; i < n; i += 3 )
37 {
38 C1 = *src++;
39 C2 = *src++;
40 C3 = *src++;
41 *p++ = base64_enc_map[( C1 >> 2 ) & 0x3F];
42 *p++ = base64_enc_map[( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F];
43 *p++ = base64_enc_map[( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F];
44 *p++ = base64_enc_map[C3 & 0x3F];
45 }
46
47 if ( i < slen )
48 {
49 C1 = *src++;
50 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
51 *p++ = base64_enc_map[( C1 >> 2 ) & 0x3F];
52 *p++ = base64_enc_map[( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F];
53 ( i + 1 ) < slen ? ( *p++ = base64_enc_map[( ( C2 & 15 ) << 2 ) & 0x3F] ) : ( *p++ = '=' );
54 *p++ = '=';
55 }
56
57 *dlen = p - dst;
58 *p = 0;
59
60 return 0;
61 }
62
63 /* 主动连接 */
64 static SOCKET tcp_connect( const char* host, unsigned short port = 25, int msec = 100 )
65 {
66 int ret;
67 SOCKET fd;
68 struct sockaddr_in sin;
69 struct hostent* h;
70 unsigned long ul;
71 struct timeval tv;
72 struct linger lg;
73 int nodelay;
74 fd_set fdset;
75
76 /* 填充服务器地址 */
77 memset( &sin, 0, sizeof( sin ) );
78 sin.sin_family = AF_INET;
79 if ( ( h = gethostbyname( host ) ) == NULL || h->h_addrtype != AF_INET )
80 {
81 return INVALID_SOCKET;
82 }
83 memcpy( &sin.sin_addr.S_un.S_addr, h->h_addr, h->h_length );
84 sin.sin_port = htons( port );
85
86
87 /* 建socket */
88 if ( ( fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET )
89 {
90 return INVALID_SOCKET;
91 }
92
93 /* 设置非阻塞 */
94 ul = 1;
95 if ( ioctlsocket( fd, FIONBIO, &ul ) != 0 )
96 {
97 closesocket( fd );
98 return INVALID_SOCKET;
99 }
100
101 /* 主动连接 */
102 if ( connect( fd, ( const struct sockaddr* ) &sin, sizeof( sin ) ) != 0 )
103 {
104 FD_ZERO( &fdset );
105 FD_SET( fd, &fdset );
106
107 memset( &tv, 0, sizeof( tv ) );
108 tv.tv_sec = msec / 1000;
109 tv.tv_usec = ( msec % 1000 ) * 1000;
110
111 /* 超时或报错 */
112 if ( select( fd + 1, 0, &fdset, 0, &tv ) != 1 )
113 {
114 closesocket( fd );
115 return INVALID_SOCKET;
116 }
117 }
118
119 /* 置为阻塞 */
120 ul = 0;
121 ret = ioctlsocket( fd, FIONBIO, &ul );
122 assert( ret == 0 );
123
124 /*消除滞留*/
125 memset( &lg, 0, sizeof( lg ) );
126 ret = setsockopt( fd, SOL_SOCKET, SO_LINGER, ( const char* ) &lg, sizeof( lg ) );
127 assert( ret == 0 );
128
129 /*禁用合并*/
130 nodelay = 1;
131 ret = setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, ( const char* ) &nodelay, sizeof( nodelay ) );
132 assert( ret == 0 );
133
134 return fd;
135 }
136
137
138 #define RECV(fd, buff, suc) do {
139 if (recv( (fd), (buff), sizeof( (buff) ), 0 ) <= 0 ||
140 memcmp((buff), (suc), 3))
141 {
142 closesocket((fd));
143 return -1;
144 }
145 }while(0)
146
147
148 #define SEND(fd, buff, len) do {
149 register size_t i = (len);
150 if (send( (fd), (buff), i, 0 ) < (int)i)
151 {
152 closesocket((fd));
153 return -1;
154 }
155 }while(0)
156
157
158 /* 发邮件 */
159 int send_mail( const char* server,
160 const char* user, const char* pwd,
161 const char* sender, const char* receiver,
162 const char* str, const unsigned char* data, size_t datalen )
163 {
164 SOCKET fd;
165 char buff[1024];
166 size_t len;
167 size_t pos;
168
169 /* 连接SMTP服务器 */
170 fd = tcp_connect( server );
171 if ( fd == INVALID_SOCKET )
172 {
173 ::MessageBox( NULL, "无法连接服务器,请检查网络设备!", "错误", MB_OK );
174 return -1;
175 }
176
177 /* 邮件问答 */
178 RECV( fd, buff, "220" );
179
180 sprintf( buff, "HELO %s
", server );
181 SEND( fd, buff, strlen( buff ) );
182 RECV( fd, buff, "250" );
183
184 /* 登录过程 */
185 SEND( fd, "AUTH LOGIN
", 12 ); /* 请求登录 */
186 RECV( fd, buff, "334" );
187
188 len = sizeof( buff );
189 base64_encode( buff, &len, ( const unsigned char* )user, strlen( user ) );
190 strcat( buff, "
" );
191 SEND( fd, buff, len + 2 ); /* 用户名 */
192 RECV( fd, buff, "334" );
193
194 len = sizeof( buff );
195 base64_encode( buff, &len, ( const unsigned char* )pwd, strlen( pwd ) );
196 strcat( buff, "
" );
197 SEND( fd, buff, len + 2 ); /* 密码 */
198 RECV( fd, buff, "235" );
199
200 /* 邮件头 */
201 sprintf( buff, "MAIL FROM:<%s>
", sender );
202 SEND( fd, buff, strlen( buff ) ); /* 发送者 */
203 RECV( fd, buff, "250" ); /* 250 Ok... */
204
205 sprintf( buff, "RCPT TO:<%s>
", receiver );
206 SEND( fd, buff, strlen( buff ) ); /* 接收者 */
207 RECV( fd, buff, "250" );
208
209 SEND( fd, "DATA
", 6 ); /* 请求发送数据 */
210 RECV( fd, buff, "354" );
211
212 sprintf( buff, "From:"javadotest"<%s>
"
213 "To:"javado"<%s>
"
214 "Subject:邮件标题
"
215 "MIME-Version: 1.0
"
216 "Content-Type: multipart/mixed; boundary="o0o0o0o0o"
",
217 sender, receiver );
218 SEND( fd, buff, strlen( buff ) );
219
220
221 /* 发送邮件内容 */
222 sprintf( buff, "--o0o0o0o0o
"
223 "Content-Type: text/plain; charset="gb2312"
"
224 "%s
", str );
225 SEND( fd, buff, strlen( buff ) );
226
227
228
229
230 /* 发送附件 */
231 strcpy( buff, "--o0o0o0o0o
"
232 "Content-Type: application/octet-stream; name="附件.doc"
"
233 "Content-Transfer-Encoding: base64
"
234 "Content-Disposition: attachment; filename="附件.doc"
" );
235 SEND( fd, buff, strlen( buff ) );
236 if ( datalen > 0 )
237 {
238 for ( pos = 0; pos < datalen; )
239 {
240 len = sizeof( buff );
241 memset( buff, 0, sizeof( buff ) );
242
243 if ( datalen - pos >= 765 )
244 {
245 base64_encode( buff, &len, data + pos, 765 );
246 strcat( buff, "
" );
247 SEND( fd, buff, 1022 );
248 pos += 765;
249 }
250 else
251 {
252 base64_encode( buff, &len, data + pos, datalen - pos );
253 strcat( buff, "
" );
254 SEND( fd, buff, strlen( buff ) );
255 break;
256 }
257 }
258 }
259
260
261
262 /* 完成发送 */
263 SEND( fd, "--o0o0o0o0o--
.
QUIT
", 24 ); /* 请求退出 */
264 RECV( fd, buff, "250" ); /* 250 Ok */
265
266 closesocket( fd );
267 return 0;
268 }