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 }