POP3 with OpenSSL 0.9.8

自己写了一个小工具,用来检测POP3信箱是否有新邮件到了(其实邮件客户端outlook、foxmail等都可以检测,但不想在电脑上开太多的程序,所以自己写了一个),我一直用来检测公司邮箱,用得很好。前两天老婆说要用来检测gmail邮箱的邮件,却一直没反应,研究了一下gmail的说明,发现gmail的pop3需要ssl加密连接,所以就研究了一下OpenSSL的安装和使用

下载openssl-0.9.8.tar.gz,解压后,可以查看INSTALL.W32这个文件,告诉你在windows环境下如何编译和安装。

安装openssl之前你必须先安装Active Perl(http://www.activestate.com/ActivePerl)和NASM(http://www.kernel.org/pub/software/devel/nasm/binaries/win32/)(或者MASN,手册上说windows DDK里面包含了MASM,但是windows DDK不容易找,直接找MASM可能更容易些,比如asm.yeah.net里面就有下载的)。

我是在Borland C++ Builder 6环境下编译的,VC的方法也差不多。

进入到openssl解压后的目录,该目录下应该包含有README,NEWS等等文件,在windows控制台逐步执行下列步骤

> perl Configure BC-32
生成配置文件

> ms\do_nasm
生成makefile

> make -f ms\bcb.mak
生成结果

最终得到的lib文件在out32目录下,分别是libeay32.lib和ssleay32.lib
开发所用到的头文件在inc32目录下,你可以把这些文件组合到你同一个目录,以方便配置编译器选项

下面是一段用pop3来连接gmail的例子,供参考。


//—————————————————————————
// NOTE!!!
// Change gmail account and password first before begin test.
//—————————————————————————
#include “vcl.h”
#pragma hdrstop
#include “stdlib.h”
#include “stdio.h”
#include “conio.h”
#include “winsock2.h”
#include “openssl/ssl.h”
#include “openssl/bio.h”
#include “openssl/err.h”
//—————————————————————————
#pragma comment(lib, “ws2_32.lib”)
#pragma comment(lib, “openssl\\libeay32.lib”)
#pragma comment(lib, “openssl\\ssleay32.lib”)

#pragma warn-8004
#pragma argsused

int main(int argc, char* argv[])
{
SSL * ssl;
SSL_CTX * ctx;
SOCKET sock;
char* hostname = “pop.gmail.com”;
int port = 995;

fprintf(stdout, "HOST: %s\t PORT: %d\nConnecting, standby...", hostname, port);
// start winsock
WSAData ws;
WSAStartup(0×0101, &ws);

unsigned long ip = inet_addr(hostname);
hostent* h_entity;
if (ip == 0xFFFFFFFF) {
h_entity = gethostbyname(hostname);
if (!h_entity) {
fprintf(stdout, “Can’t reach the host\n”);
return -1;
}
memcpy(&ip, h_entity->h_addr_list[0], sizeof(int));
}

// create socket and connect to server
sockaddr_in server;
memcpy(&server.sin_addr, &ip, sizeof(int));
server.sin_port = htons(port);
server.sin_family = AF_INET;
memset(&server.sin_zero, 0×00, 0×08);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
connect(sock, (sockaddr*)&server, sizeof(server));

// Load ssl context with socket binded
SSL_library_init();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_client_method());
ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
int sslErr = SSL_connect(ssl);

char buff[1024];

// Read welcome info
memset(buff, 0×0, sizeof(buff));
int total = SSL_read(ssl, buff, 1023);
fprintf(stdout, “\n%s”, buff);

// Send account
char* p = “USER youraccount@gmail.com\r\n”;
SSL_write(ssl, p, strlen(p));

memset(buff, 0x0, sizeof(buff));
total = SSL_read(ssl, buff, 1023);
fprintf(stdout, “\n%s”, buff);

// Send password
p = “PASS yourpassword\r\n”;
SSL_write(ssl, p, strlen(p));
memset(buff, 0×0, sizeof(buff));
total = SSL_read(ssl, buff, 1023);
fprintf(stdout, “%s”, buff);

fprintf(stdout, "Disconnect from the server.\nPress any key to exit.\n");
getch();

// Clear and free
SSL_shutdown(ssl);
closesocket(sock);
SSL_free(ssl);
SSL_CTX_free(ctx);
WSACleanup();
return 0;
}

Comments

two decimal reserved, without any zero rounded

用C++Builder的QuickReport组件做几个报表,要求在查询的结果中所有的金额字段都要保留两位小数,并且不能丢失小数点后面的0。我用TListView呈现查询结果,用TQuickReport来设计报表样式。数据库是Sybase。

将查询结果直接填入到TListView之后,发现小数点后面是没有精度的,于是将查询语句里面加入了数据类型转换,如下:

SELECT convert(decimal(13,2), amount) FROM anytable

在DBArtisan里面显示的结果没有问题,然后放到C++Builder里面执行,填入TListView里面还是舍掉了后面的0,没想到好办法,就用如下代码:

char buff[15];
sprintf(buff, “%.02f”, anyQry->FieldByName(”amount”)->AsFloat);

来转换,再填充到TListView。

而对于TQuickReport,本来以为很难搞,后来发现TQRDBText有一个属性叫Mask,设置为0.00,就可以起作用了。

Comments

Unexpected error while installing Sybase ASE 15.0 for Linux in RHEL AS4

为了方便以后测试程序,昨天开始装RHEL4的虚拟机。
工作中用的服务器环境不是我装的,安装过程中遇到并解决了一点问题也算小有收获。

Red Hat的Enterprise Linux AS4算是比较成熟的商用Linux系统,整个安装过程十分顺利,为了确保以后安装Sybase等其他大型软件的方便,需要给虚拟机分配至少4G的虚拟硬盘空间。

安装Sybase之前,现创建了sybase用户和sybase组,sybase用户的根目录在/home/sybase下。同时在/opt下创建了sybase目录,供sybase程序使用,需设置chown sybase:sybase /opt/sybase

然后用sybase用户登录,安装Sybase ASE 15.0 for Linux。安装的时候最好选择custom方式,默认安装不包括ESQL/C的支持。
接下来的配置都比较简单,可以自己设置,也可以直接选择默认值。由于我只是在虚拟机下供测试用,所以我只装了Adaptive Server服务,其他的服务都没有装。

程序文件复制结束,安装程序会自动配置数据库,就在配置的时候报错了。
“/opt/sybase/ASE-15_0/bin/dataserver: error while loading shared libraries: libstdc++.so.5: cannot open shared object file: No such file or directory”

看来是libstdc++的库文件不兼容,于是就复制RHEL4 disc2中RPMS下的compat-libstdc++-33-3.2.3-47.3.i386.rpm和libstdc++-3.4.3-9.EL4.i386.rpm,并用rpm -Uvh *.rpm安装(我的安装是在X环境下进行的,所以出错之后没有退出),接着重试了配置数据库,就成功了。

手工启动数据库的命令在/opt/sybase/ASE-15_0/install/下,名为RUN_*,*为你的服务器名字。

默认情况下sybase只在127.0.0.1地址下监听TCP端口,所以在其他机器上是不能访问的,需要修改/etc/hosts文件中的域名解析。(如果启用了iptables,还需要开放sybase端口)

Comments

useful tips about sscanf

大家可能都或多或少在C/C++语言中用过sscanf处理字符串,不过我倒用得不多,上次用这个函数还是半年前了。
这回有同事在用sscanf读取一串字符到一个结构体,以填充结构体的各个项,测试时发现sscanf会过滤掉开头的空白字符。
比如有如下结构体:
typedef struct tagT
{
char a[3+1];
char b[5+1];
char c[3+1];
} T;
还有如下字符串:
char *s = “01 2 “;
用如下方法读取:
T t;
memset(&t, 0×00, sizeof(T));
sscanf(s, “%3s%5s%3s”, &t.a, &t.b, &t.c);
printf(”a=/%s/\tb=/%s/\tc=/%s/\n”, t.a, t.b, t.c);
运行之后,会发现读入的字符串跟想像中的不一样:
a=/01/ b=/2/ c=//
而我想要的结果是:
a=/01 / b=/ / c=/ 2 /

这里的问题解决方法非常简单,只要把”%3s%5s%3s”中的s改成c即可,在sscanf中,%s是遇到非空格字符才开始读取的,直到读取到空格字符结束,而%c会把空格也读进来。

正确的解法是:
sscanf(s, “%3c%5c%3c”, &t.a, &t.b, &t.c);

而通过这个问题,发现了一个使用sscanf函数滤掉字符串首尾空格的方法,即sscanf(str, “%s”, str);

Comments

char, wchar_t & TCHAR

以前写程序都不太注意UNICODE问题,因为做的东西基本上都是在固定的平台上跑,而一般的函数用char传递字符串都没有问题。

这几天写程序遇到一个函数调用,居然只支持wchar_t的宽字符,就在程序里面写了不少wchar_t的字符串定义。写着写着就发现这样的代码太难看了,一会儿char,一会儿wchar_t的,乱。于是就返工,把他们都改成了TCHAR,并且定义了全局宏UNICODE(或者_UNICODE),这样一来,代码里面就都是TCHAR了。至于那些只支持UNICODE的函数,在编译的时候加入编译条件,如果没有定义UNICODE宏,就忽略他们吧。

相应的,有关字符串操作的函数,都改用了TCHAR.H里面定义的,比如strcpy改成了_tcscpy,sprintf改成了_stprintf

Comments

« Previous entries