分类: 2010 April

GtkClist展示MySQL数据

What/Why

一个月前就应该交一个作业了,传说中的学生信息管理系统(笑~),一直没放在心上.可我软件工程已经有6个星期没去上过课了,作业也从来没交过,于是这两天还是交个作业上去给点老师面子..因为学着GTK+,所以尝试了下用GTK+来实现..

其实这个作业原理真的很简单,C语言下用mysql_query(&myconnection, sql)执行查询,然后用mysql_store_result(&myconnection)将查询得到的结果集保存下来,之后mysql_field_count(&myconnection)得到行数,然后逐行将行名打印出来,最后逐列将数据打印就搞定了.真正的难点在于如何将结果显示在窗口上,我拿着GtkClist和GtkTreeView左瞧右瞧,最终很悲情选定了GtkClist,仅仅是因为它的文档短了几十页罢了.(悲剧在后面.)

How

垒上代码如下,其中各主要widget从属关系为vbox -> scrolled_window -> clist, 其他需要注意的注释里写得很清楚了:

...

MYSQL myconnection;

MYSQL_RES *res_ptr;

MYSQL_ROW sqlrow;

MYSQL_FIELD *field;

int res;

...

//根据传入的conn(select * from *之类的语句执行),将得到的表内容显示在vbox上

static void make_clist(GtkWidget *vbox, MYSQL conn)

{

GtkWidget *scrolled_window; // 显示数据需要的滚动窗口scrolled_window和表单clist,

GtkWidget *clist, *entry;

int counter; // 迭代器,遍历结果集每一列

scrolled_window = gtk_scrolled_window_new (NULL, NULL); //创建scrolled_window,设置属性为自动

gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);

gtk_widget_show(scrolled_window); //将scrolled_window显示出来

gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0); //将scrolled_window添加道vbox中

int cols = mysql_field_count(&conn); // 得到数据表的列数

clist = gtk_clist_new_with_titles(cols, NULL); // 新建clist并显示,列数为cols

gtk_clist_column_titles_show (GTK_CLIST(clist)); //设置clist每列列名是否显示为真

res_ptr = mysql_store_result(&conn); //保存查询结果

for (counter = 0; counter < cols; counter++) //从第0列到最后1列

{

mysql_field_seek(res_ptr, counter); //跳到第counter列

field = mysql_fetch_field(res_ptr); //取出第counter列信息

entry = gtk_entry_new(); //新建文本框

gtk_entry_set_text(GTK_ENTRY(entry), field->name);//将文本框内容设置为数据表第counter列的名字

gtk_widget_show (entry);//显示文本框

gtk_clist_set_column_widget (GTK_CLIST (clist), counter, entry); //将文本框作为widget添加进clist中第counter列

gtk_clist_set_column_title(GTK_CLIST(clist), counter, field->name);//将数据表第counter列名作为clist中第counter列名

gtk_clist_set_column_width (GTK_CLIST (clist), counter, 85);//设置clist中每列长度

}

while((sqlrow = mysql_fetch_row(res_ptr)) != 0L)//取数据表中一整行的信息,遍历至表尾

gtk_clist_append(GTK_CLIST(clist), sqlrow);//将一整行信息压入clist

gtk_container_add (GTK_CONTAINER (scrolled_window), clist);//将clist添加scrolled_window中

gtk_widget_show(clist);//显示clist

}

...

Drawbacks

前面的其实都不是重点(哈哈~),因为有一些缺陷:

  • Clist中数据段不允许插入包括entry在内的所有widget,(尽管在其头文件enum中是有预留widget的),这也就意味着,假如想要可视化的修改数据表内容,那么只可能:
    1. 另外在程序主面板中再多添加行列按钮各一个,新内容输入框一个,最后还有确认按钮一个..虽然需要修改的数据所在的行列可以通过gtk_clist_get_text来得到,但这还是显得足够愚蠢和蹩脚..相信每个最终用户还是更希望可以体验到类似于在Excel中工作的快感的.
    2. 或者监听用户的鼠标事件,当鼠标在clist内点击时,弹出一个对话框,用户可以直接在上面敲入新的内容,回车后程序将自动连入mysql server更新内容.
  • Clist中数据类型全为gchar *,即便可以在读取数据表列名时预先判断其数据类型,然后用map<gchar *filename, gchar *datatype>做个映射,以后更新数据表时先得到数据所在列的列名,然后通过映射找到原来的数据类型,之后再update到数据表中,但这样还是太繁琐了.

前面列的一些不足虽然都有各自的解决方法,但都无法绕开下面这一点: 数据表的更新只能是每个单元每个单元进行的,无法实现逐行逐行的处理..设想一下,假如在Excel中,每修改/添加/删除一个单元后,都需要ctrl+s一下,这是多么的悲剧..

那么,要怎么解决这个问题呢..在mailing list里提问之后,我才发现,或许GtkTreeView天生就适合做展示..我的想法是这样的:先用time()得到当前时间做为一个新的数据表名称table_new,然后执行create table table_new select * from table_old将旧数据表复制到新数据表中,这样子各列的数据类型就得到了..然后delete from table_new将新数据表清空,然后设计一个函数func()将gtktreeview中数据逐行写入table_new,最后删掉table_old,将table_new重命名为table_old就可以了..至于func()怎么实现呢,明天再搞它.

PS

  1. 测试版源码在这http://godorz.info/wp-content/uploads/2010/04/main.test_.zip,编译命令为: gcc -o main.test main.test.c -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient `pkg-config –cflags –libs gtk+-2.0`,记得把源码里面的用户名,密码和数据库改了…galde文件其实是个xml,里面放的是各控件的属性(名字,位置,大小等),可以华丽地无视之..
  2. 原来博客真的是拿来记思路的..

md5 gui 小程序

昨晚将phoneyc检测网页的结果写入数据库时,想起可以顺手加个md5值作为每个url的签名,于是在终端里敲下echo “www.godorz.cn” | md5sum ,在这之前,一切都是美好的,可当我要拿出计算出的md5值时,才知道原来在终端里复制文本是这么繁琐,首先要选定文本,然后右键+c,后一步是很容易的,但是前一步选定文本对于鼠标不灵视力不好脾气火爆的我来说,就真的是个杯具了..正好最近在学gtk,干脆就写个计算md5的gui,然后将结果默认选定,酱紫就可以直接ctrl+c复制啦,呵呵..

md5算法是在这里找的,说来惭愧的是,,作为计算机系的学生,生平第一次真正见到request for comment文档,还是21页的文档,很长很恐怖,我马上把它关了..

有了md5源码,其余的就很简单了,打开glade,设计好界面如下:

然后新建一个c文件,用GtkBuilder *builder将glade设计好的界面引用下来,然后逐个传给GtkWidget组件,剩下需要作的就是捣鼓捣鼓每个组件回调函数了. 代码如下,注释已经很明了了:


#include<gtk/gtk.h>

GtkWidget *resultentry;
GtkWidget *filew;
GtkWidget *entry;
gchar filepath[512];
.....

void cb_okbutton(GtkWidget *widget, GtkWidget *entry)
{
//得到输入控件entry值,传入filename
const gchar *tmp;
tmp = gtk_entry_get_text(GTK_ENTRY(entry));
char filename[512];
sprintf(filename, "%s", tmp);

if (filename[0]==34) filename[strlen(filename)-1]=0,strcpy(filename,filename+1);  //支持文件拖曳,但会多出双引号,这里是处理多余的双引号
if (!(fp=fopen(filename,"rb"))) {printf("Can not open this file!\n"); return;}  //以二进制打开文件
fseek(fp, 0, SEEK_END);  //文件指针转到文件末尾
if((len=ftell(fp))==-1) {printf("Sorry! Can not calculate files which larger than 2 GB!\n");fclose(fp); return ;}  //ftell函数返回long,最大为2GB,超出返回-1
rewind(fp);  //文件指针复位到文件头
A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476; //初始化链接变量
flen[1]=len/0x20000000;     //flen单位是bit
flen[0]=(len%0x20000000)*8;
memset(x,0,64);   //初始化x数组为0
fread(&x,4,16,fp);  //以4字节为一组,读取16组数据
for(i=0;i<len/64;i++)
{    //循环运算直至文件结束
md5();
memset(x,0,64);
fread(&x,4,16,fp);
}
((char*)x)[len%64]=128;  //文件结束补1,补0操作,128二进制即10000000
if(len%64>55) md5(),memset(x,0,64);
memcpy(x+14,flen,8);    //文件末尾加入原文件的bit长度
md5();
fclose(fp);

// 将结果高低位逆反输出到buf
char buf[512];
sprintf(buf, "%08x%08x%08x%08x",PP(A),PP(B),PP(C),PP(D));  //高低位逆反输出

//printf("%08x%08x%08x%08x\n",PP(A),PP(B),PP(C),PP(D));  //高低位逆反输出

// printf("%s\n", buf);

// 将buf内容显示在输入控件resultentry上
gtk_entry_set_text(GTK_ENTRY(resultentry),buf);

// 输入控件resultentry内容默认选定,方便用户复制
gtk_editable_select_region(GTK_EDITABLE(resultentry), 0, GTK_ENTRY(resultentry)->text_length);

}

// 获得文件名,并将它打印到控制台(console)上
void file_ok_sel( GtkWidget *w, GtkFileSelection *fs )
{
// 将文件选择控件所选择的文件路径传给filepath
sprintf(filepath, "%s", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));

//printf("%s\n", filepath);

// 将文件选择控件所选择的文件路径显示在输入空间entry上
gtk_entry_set_text (GTK_ENTRY (entry), filepath);

//const gchar *tmp;
//tmp = gtk_entry_get_text(GTK_ENTRY(entry));
//printf("<<<<<<<<<< %s\n", tmp);

// 文件已选择完毕,隐藏文件选择控件,貌似不能直接destroy掉..
//gtk_widget_destroy(GTK_WIDGET(fs));
gtk_widget_hide(GTK_WIDGET(fs));
}

void cb_button(GtkWidget *widget, GtkWidget *entry)
{

// 创建一个新的文件选择构件
filew = gtk_file_selection_new ("File selection");

g_signal_connect (G_OBJECT (filew), "destroy", G_CALLBACK (gtk_widget_destroy), NULL);
// 为 ok_button 按钮设置回调函数,连接到 file_ok_sel function 函数
g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)->ok_button), "clicked", G_CALLBACK (file_ok_sel), filew);

// 为 cancel_button 设置回调函数,销毁构件
g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button), "clicked", G_CALLBACK (gtk_widget_destroy), filew);

// 设置文件名,比如这个一个文件保存对话框,我们给了一个缺省文件名
gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), "hello.cmp");

gtk_widget_show (filew);

}

....

编译命令为:  gcc -o gtkmd5 gtkmd5.c `pkg-config –cflags –libs gtk+-2.0` -export-dynamic

比较恶心的是文件选择控件filew,当点击button时它被new出来,但是选择好文件之后,filew应该是消失的,我理所当然的调用 gtk_widget_destroy(GTK_WIDGET(fs)); 将之destroy掉了,伴随而来的副作用是主窗口也将退出,于是搞了个很猥琐的方法,直接用gtk_widget_hide(GTK_WIDGET(fs)); 将它隐藏起来了..不过,现在想想这种做法是不错的,因为用户可能重新需要选择文件,其实也就没有必要将之destroy掉了,隐藏起来正好是歪打正着..

最后是测试,居然很傻的总是先用md5sum算出gtkmd5.c的md5值,然后在gtkmd5.c中这修改那调整一点,然后compile+link,用生成的程序再次计算gtkme5.c的值,然后目光呆滞的看着两个不同的结果,抱着脑袋纠结了半天不明所以..真成杯具批发商了..最后,怨妇般的在这里对着个helloworld般的小程序吐槽.莫非更年期到了?

完整代码和glade文件在这..

最最后: 程序写得仔细点的话,应该把计算文件夹里所有文件md5值的功能加上的,这样,就可以把图中蹩脚的result entry换成GTK_TEXT_VIEW了..HoHo~~其实还应该加上个选择按钮,计算文件或者字符串的..

phoneyc 安装笔记

What

honeynet是一个致力于研究蜜罐系统的非盈利组织,以了解黑客使用的工具,策略和行为.在honeynet的带领下,牛人门提出了多种不同的蜜罐系统,简单可以分为低交互和高交互两种,某些项目的入口可以在这里找到.其中,phoneyc是一种低交互的蜜罐系统,它提供了一个javascript引擎,用来执行网页中的js代码,依据其行为特征判断该网页是否含有恶意js代码.这里是某位跟着phoneyc的作者jose大牛混的北大学生对phoneyc的介绍,源码可以在google code下载.

顺便提一下,正如google code上phoneyc上的介绍一样,jose常在 irc.freenode.net/8001 的#phoneyc频道上混,按jose的话来说,他还有一个”helping communicate”: Angelo_Honeynet,两位都是相当相当热忱认真的大牛,//applause.

How

phoneyc虽然强大,但是安装起来却是极度繁琐的,下面记下我的安装过程 :

  1. sudo apt-get install libnspr4-0d libnspr4-dev #安装phoneyc依赖的nspr
  2. wget http://curl.haxx.se/download/curl-7.20.0.tar.gz && tar zvxf curl-7.20.0.tar.gz #以下3步安装phoneyc依赖的curl
  3. cd curl-7.20.0
  4. sudo ./install-sh
  5. cd ..
  6. wget http://godorz.info/wp-content/uploads/2010/04/pycurl-7.19.0.tar.gz && tar zvxf pycurl-7.19.0.tar.gz #以下4步安装 \ phoneyc同样依赖的pycurl <- curl的python版
  7. cd pycurl-7.19.0
  8. python setup.py build
  9. sudo setup.py install
  10. cd ..
  11. wget http://godorz.info/wp-content/uploads/2010/04/libemu-trunk.tar.bz2 && tar jvxf libemu-trunk.tar.bz2 #下载 \ phoneyc的依赖包并且解压缩 (请一定要在这里下载modified版,libemu官网那个版本是旧的,有些文件没有包含,我花了一天 \ 多在这里被搞得半死,Angelo提醒后才知道的.)
  12. cd libemu-trunk #以下4步安装libemu
  13. autoreconf -v -i
  14. /configure –prefix=/opt/libemu
  15. sudo make install
  16. cd ..
  17. sudo echo “/opt/libemu/lib/libemu” > /etc/ld.so.conf.d/libemu.conf #以下两步配置ld
  18. sudo ldconfig
  19. svn checkout https://phoneyc.googlecode.com/svn/phoneyc/trunk/ phoneyc  #下载phoneyc
  20. cd phoneyc/modules/libemu #根据jose的说法,以下3步将hook up the installed libemu to phoneyc
  21. python setup.py build
  22. sudo setup.py install
  23. cd .. #以下3步安装modules,包含hcalert,honeyjs,jscript,libemu等组件.
  24. sudo make
  25. sudo make install
  26. cd ..
  27. python phoneyc.py -v file://test/ssreader_0day.html #测试,如果返回结果与 \ phoneyc/result//home/arthur/phoneyc/result/ssreader_0day.txt一致,就说明phoneyc已经成功安装了.

Architecture

下面是phoneyc的结构图,要看源码的话还是对着这图看不容易头晕..XD.

phoneyc_future_archtecture

End

PS:

  1. 本文在ubuntu 9.10下测试,其他平台无法保证可以依照这里的方法成功安装phoneyc. 如果无法安装,或许你可以参考这里jose和Angelo对我孜孜不倦的回答.
  2. 赶紧把信安比赛酱油打完,要开始碰UNP(volume 1)了.