├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── autoclean.sh ├── autogen.sh ├── configure.ac ├── configure.opfetion ├── doc ├── msgformat ├── recvmsgfmt ├── serverreturns ├── table.sql ├── webqq登录过程分析 └── webqq解析 ├── pixmaps ├── Makefile.am ├── gtkqq.desktop └── gtkqq.png ├── src ├── Makefile.am ├── cli │ └── Makefile.am ├── comm │ ├── Makefile.am │ ├── cprint.c │ ├── cprint.h │ ├── log.c │ └── log.h ├── gui │ ├── Makefile.am │ ├── buddylist.c │ ├── buddylist.h │ ├── buddytree.c │ ├── buddytree.h │ ├── chattextview.c │ ├── chattextview.h │ ├── chatwidget.c │ ├── chatwidget.h │ ├── chatwindow.c │ ├── chatwindow.h │ ├── dao.c │ ├── dao.h │ ├── facepopupwindow.c │ ├── facepopupwindow.h │ ├── gqqconfig.c │ ├── gqqconfig.h │ ├── groupchatwindow.c │ ├── groupchatwindow.h │ ├── loginpanel.c │ ├── loginpanel.h │ ├── main.c │ ├── mainpanel.c │ ├── mainpanel.h │ ├── mainwindow.c │ ├── mainwindow.h │ ├── msgdispacher.c │ ├── msgdispacher.h │ ├── msgloop.c │ ├── msgloop.h │ ├── proxypanel.c │ ├── proxypanel.h │ ├── settingdialog.c │ ├── settingdialog.h │ ├── sound.c │ ├── sound.h │ ├── splashpanel.c │ ├── splashpanel.h │ ├── statusbutton.c │ ├── statusbutton.h │ ├── tencent │ │ ├── Makefile.am │ │ ├── constval.h │ │ ├── qq.c │ │ ├── qqbutton.c │ │ ├── qqbutton.h │ │ ├── qqwindow.c │ │ └── qqwindow.h │ ├── test │ │ ├── Makefile.am │ │ └── winmove.c │ ├── tray.c │ └── tray.h ├── libqq │ ├── Makefile.am │ ├── http.c │ ├── http.h │ ├── json.c │ ├── json.h │ ├── qq.h │ ├── qqhosts.h │ ├── qqimg.c │ ├── qqinit.c │ ├── qqlogin.c │ ├── qqmanageinfo.c │ ├── qqpoll.c │ ├── qqproxy.c │ ├── qqproxy.h │ ├── qqsendmsg.c │ ├── qqtypes.c │ ├── qqtypes.h │ ├── qqutils.c │ ├── unicode.c │ ├── unicode.h │ ├── url.c │ └── url.h ├── misc │ ├── Button_close_highlightBackground.bmp │ ├── Button_close_pushedBackground.bmp │ ├── Button_colse_normal.bmp │ ├── Button_max_highlightBackground.bmp │ ├── Button_max_normalBackground.bmp │ ├── Button_max_pushedBackground.bmp │ ├── Button_min_highlightBackground.bmp │ ├── Button_min_normalBackground.bmp │ ├── Button_min_pushedBackground.bmp │ ├── Button_restore_highlightBackground.bmp │ ├── Button_restore_normal.bmp │ ├── Button_restore_pushedBackground.bmp │ ├── ContactMainTabButton1.png │ ├── ContactMainTabButton2.png │ ├── GroupMainTabButton1.png │ ├── GroupMainTabButton2.png │ ├── MainPanel_Support_DownBackground.bmp │ ├── MainPanel_Support_NormalBackground.bmp │ ├── MainPanel_Support_highlightBackground.bmp │ ├── Makefile.am │ ├── RecentMainTabButton1.png │ ├── RecentMainTabButton2.png │ ├── avatar.gif │ ├── avatar.png │ ├── clearscreen.png │ ├── group.png │ ├── phone.png │ ├── qqfaces │ │ ├── 0.gif │ │ ├── 1.gif │ │ ├── 10.gif │ │ ├── 100.gif │ │ ├── 101.gif │ │ ├── 102.gif │ │ ├── 103.gif │ │ ├── 104.gif │ │ ├── 105.gif │ │ ├── 106.gif │ │ ├── 107.gif │ │ ├── 108.gif │ │ ├── 109.gif │ │ ├── 11.gif │ │ ├── 110.gif │ │ ├── 111.gif │ │ ├── 112.gif │ │ ├── 113.gif │ │ ├── 114.gif │ │ ├── 115.gif │ │ ├── 116.gif │ │ ├── 117.gif │ │ ├── 118.gif │ │ ├── 119.gif │ │ ├── 12.gif │ │ ├── 120.gif │ │ ├── 121.gif │ │ ├── 122.gif │ │ ├── 123.gif │ │ ├── 124.gif │ │ ├── 125.gif │ │ ├── 126.gif │ │ ├── 127.gif │ │ ├── 128.gif │ │ ├── 129.gif │ │ ├── 13.gif │ │ ├── 130.gif │ │ ├── 131.gif │ │ ├── 132.gif │ │ ├── 133.gif │ │ ├── 134.gif │ │ ├── 14.gif │ │ ├── 15.gif │ │ ├── 16.gif │ │ ├── 17.gif │ │ ├── 18.gif │ │ ├── 19.gif │ │ ├── 2.gif │ │ ├── 20.gif │ │ ├── 21.gif │ │ ├── 22.gif │ │ ├── 23.gif │ │ ├── 24.gif │ │ ├── 25.gif │ │ ├── 26.gif │ │ ├── 27.gif │ │ ├── 28.gif │ │ ├── 29.gif │ │ ├── 3.gif │ │ ├── 30.gif │ │ ├── 31.gif │ │ ├── 32.gif │ │ ├── 33.gif │ │ ├── 34.gif │ │ ├── 35.gif │ │ ├── 36.gif │ │ ├── 37.gif │ │ ├── 38.gif │ │ ├── 39.gif │ │ ├── 4.gif │ │ ├── 40.gif │ │ ├── 41.gif │ │ ├── 42.gif │ │ ├── 43.gif │ │ ├── 44.gif │ │ ├── 45.gif │ │ ├── 46.gif │ │ ├── 47.gif │ │ ├── 48.gif │ │ ├── 49.gif │ │ ├── 5.gif │ │ ├── 50.gif │ │ ├── 51.gif │ │ ├── 52.gif │ │ ├── 53.gif │ │ ├── 54.gif │ │ ├── 55.gif │ │ ├── 56.gif │ │ ├── 57.gif │ │ ├── 58.gif │ │ ├── 59.gif │ │ ├── 6.gif │ │ ├── 60.gif │ │ ├── 61.gif │ │ ├── 62.gif │ │ ├── 63.gif │ │ ├── 64.gif │ │ ├── 65.gif │ │ ├── 66.gif │ │ ├── 67.gif │ │ ├── 68.gif │ │ ├── 69.gif │ │ ├── 7.gif │ │ ├── 70.gif │ │ ├── 71.gif │ │ ├── 72.gif │ │ ├── 73.gif │ │ ├── 74.gif │ │ ├── 75.gif │ │ ├── 76.gif │ │ ├── 77.gif │ │ ├── 78.gif │ │ ├── 79.gif │ │ ├── 8.gif │ │ ├── 80.gif │ │ ├── 81.gif │ │ ├── 82.gif │ │ ├── 83.gif │ │ ├── 84.gif │ │ ├── 85.gif │ │ ├── 86.gif │ │ ├── 87.gif │ │ ├── 88.gif │ │ ├── 89.gif │ │ ├── 9.gif │ │ ├── 90.gif │ │ ├── 91.gif │ │ ├── 92.gif │ │ ├── 93.gif │ │ ├── 94.gif │ │ ├── 95.gif │ │ ├── 96.gif │ │ ├── 97.gif │ │ ├── 98.gif │ │ ├── 99.gif │ │ └── Makefile.am │ ├── selectface.png │ ├── selectfont.png │ ├── sendfile.png │ ├── sendpic.png │ ├── showhistory.png │ ├── sound │ │ ├── Classic │ │ │ ├── Audio.wav │ │ │ ├── Global.wav │ │ │ ├── msg.wav │ │ │ ├── shake.wav │ │ │ └── system.wav │ │ ├── Makefile.am │ │ └── Office │ │ │ ├── Audio.wav │ │ │ ├── Global.wav │ │ │ ├── msg.wav │ │ │ ├── shake.wav │ │ │ └── system.wav │ ├── status │ │ ├── Makefile.am │ │ ├── away.png │ │ ├── busy.png │ │ ├── callme.png │ │ ├── downarrow.png │ │ ├── hidden.png │ │ ├── offline.png │ │ ├── online.png │ │ └── silent.png │ ├── webqq.png │ └── webqq_icon.png ├── test │ ├── Makefile.am │ ├── test.json │ ├── testcprint.c │ ├── testhttp.c │ ├── testjson.c │ ├── testlog.c │ ├── testpro.c │ ├── testproxy.c │ └── testurl.c └── tool │ ├── Makefile.am │ ├── unidecode.c │ └── webqq.js └── todo /.gitignore: -------------------------------------------------------------------------------- 1 | *.in 2 | *.lo 3 | *.log 4 | *.o 5 | *.out 6 | *.swp 7 | *~ 8 | .deps/ 9 | .libs/ 10 | /eproject.cfg 11 | Makefile 12 | aclocal.m4 13 | autom4te.cache 14 | build-aux/ 15 | cscope* 16 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | HuangCongyu 2 | Xiang Wang 3 | mathslinux 4 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/ChangeLog -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS= src pixmaps 2 | ACLOCAL_AMFLAGS = -I m4 3 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | GtkQQ is a QQ client. It is written using gtk and based on the webqq protocol. 2 | 3 | The webqq protocol is based on the HTTP. 4 | Visit http://web.qq.com to see it. 5 | 6 | Maybe GtkQQ is a browser, whick can only visit http://web.qq.com. 7 | I think there is no copyright problem, because I just write a highly custommed 8 | broswer. 9 | 10 | src-| 11 | |--comm some common codes, such as log 12 | |--libqq the core library 13 | |--gui the gui version 14 | |--cli the command line version 15 | |--misc some resource files. such as pictures. 16 | |--tool some tool used to develop 17 | |--test the test codes. 18 | -------------------------------------------------------------------------------- /autoclean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | make distclean 3 | rm aclocal.m4 autom4te.cache/ config.h.in m4 usr build-aux -rf 4 | rm configure 5 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | aclocal \ 4 | && autoconf \ 5 | && libtoolize --copy --force --automake \ 6 | && autoreconf --install \ 7 | && [ -d usr ] || mkdir usr \ 8 | && ./configure --enable-debug --prefix=`pwd`/usr 9 | -------------------------------------------------------------------------------- /configure.opfetion: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.63]) 5 | AC_INIT([OpenFetion], [2.0.1], [http://basiccoder.com/openfetion]) 6 | AC_CONFIG_SRCDIR([src/fx_main.c]) 7 | AC_CONFIG_HEADERS([config.h]) 8 | 9 | AM_INIT_AUTOMAKE 10 | 11 | # Checks for programs. 12 | AC_PROG_CC 13 | AM_PROG_CC_C_O 14 | AC_PROG_INSTALL 15 | 16 | # libtools 17 | AC_PROG_RANLIB 18 | AC_PROG_LIBTOOL 19 | 20 | #gettext 21 | IT_PROG_INTLTOOL([0.40.0]) 22 | AC_SUBST([GETTEXT_PACKAGE], [openfetion]) 23 | AM_GNU_GETTEXT_VERSION([0.17]) 24 | AM_GLIB_GNU_GETTEXT 25 | AM_GNU_GETTEXT([external]) 26 | AC_DEFINE([GETTEXT_PACKAGE], [PACKAGE_TARNAME], [Define to the gettext 27 | package name.]) 28 | 29 | AC_CHECK_LIB([notify], [notify_init]) 30 | 31 | AC_CHECK_LIB([ssl], [SSL_library_init]) 32 | 33 | AC_CHECK_LIB([crypto], [RSA_new]) 34 | 35 | AC_CHECK_LIB([pthread], [pthread_create]) 36 | 37 | # Checks for header files. 38 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h unistd.h]) 39 | 40 | AC_ARG_ENABLE(screensaver, 41 | AS_HELP_STRING([--enable-screensaver], 42 | [Enable X screensaver extension (used to detect idleness) @<:@default=yes@:>@]),, 43 | enable_screensaver="yes") 44 | 45 | AC_ARG_ENABLE(libnotify, 46 | AS_HELP_STRING([--enable-libnotify], 47 | [Enable libnotify support (used to show message notifications) @<:@default=yes@:>@]),, 48 | enable_libnotify="yes") 49 | 50 | AC_ARG_ENABLE(gst, 51 | AS_HELP_STRING([--enable-gst], 52 | [Enable gstreamer support (used to play alert sounds) @<:@default=yes@:>@]),, 53 | enable_gst="yes") 54 | 55 | AC_ARG_ENABLE(nm, 56 | AS_HELP_STRING([--enable-nm], 57 | [Enable NetworkManager support (used to monitor network status) @<:@default=yes@:>@]),, 58 | enable_nm="yes") 59 | 60 | # checks for gtk+2.0 61 | PKG_CHECK_MODULES(GTK, [gtk+-2.0 >= 2.16], [ 62 | AC_DEFINE(USE_GTK, 1, [Use GTK]) 63 | AC_SUBST(GTK_CFLAGS) 64 | AC_SUBST(GTK_LIBS) 65 | ] , 66 | ) 67 | # checks for gthread-2.0 68 | PKG_CHECK_MODULES(GTHREAD, [gthread-2.0], [ 69 | AC_DEFINE(USE_GTHREAD, 1, [Use GTHREAD-2.0]) 70 | AC_SUBST(GTHREAD_CFLAGS) 71 | AC_SUBST(GTHREAD_LIBS) 72 | ] , ) 73 | 74 | # checks for libxml2 75 | PKG_CHECK_MODULES(LIBXML, [libxml-2.0], [ 76 | AC_DEFINE(USE_LIBXML, 1, [Use LIBXML]) 77 | AC_SUBST(LIBXML_CFLAGS) 78 | AC_SUBST(LIBXML_LIBS) 79 | ] , ) 80 | 81 | # checks for libsqlite3 82 | PKG_CHECK_MODULES(SQLITE3, [sqlite3 > 3.3], [ 83 | AC_DEFINE(USE_SQLITE3, 1, [Use sqlite3]) 84 | AC_SUBST(SQLITE3_CFLAGS) 85 | AC_SUBST(SQLITE3_LIBS) 86 | ] , [ 87 | echo "" 88 | echo "configure: error: " 89 | echo "libsqlite3 development headers not found." 90 | echo "If you're using debian or ubuntu,install it by" 91 | echo "\"sudo apt-get install libsqlite3-dev\"" 92 | echo "" 93 | exit -1 94 | ]) 95 | 96 | # checks for libxss 97 | if test "x$enable_screensaver" = "xyes" ;then 98 | PKG_CHECK_MODULES(LIBXSS, [xscrnsaver], [ 99 | AC_DEFINE(USE_LIBXSS, 1, [Use XScreenSaver for idleness]) 100 | AC_SUBST(LIBXSS_CFLAGS) 101 | AC_SUBST(LIBXSS_LIBS) 102 | ] , [ 103 | echo "" 104 | echo "configure: error: " 105 | echo "XScreenSaver development headers not found." 106 | echo "Use --disable-screensaver if you do not need it." 107 | echo "If you're using debian or ubuntu,install it by" 108 | echo "\"sudo apt-get install libxss-dev\"" 109 | echo "" 110 | exit -1 111 | ]) 112 | fi 113 | 114 | # checks for libnotify 115 | if test "x$enable_libnotify" = "xyes"; then 116 | PKG_CHECK_MODULES(LIBNOTIFY, [libnotify], [ 117 | AC_DEFINE(USE_LIBNOTIFY, 1, [Use libnotify for notification]) 118 | AC_SUBST(LIBNOTIFY_CFLAGS) 119 | AC_SUBST(LIBNOTIFY_LIBS) 120 | ] , [ 121 | echo "" 122 | echo "configure: error: " 123 | echo "libnotify development headers not found." 124 | echo "Use --disable-libnotify if you do not need it." 125 | echo "If you're using debian or ubuntu,install it by " 126 | echo "\"sudo apt-get install libnotify-dev\"" 127 | echo "" 128 | exit -1 129 | ]) 130 | fi 131 | 132 | # checks for gstreamer-0.10 133 | if test "x$enable_gst" = "xyes"; then 134 | PKG_CHECK_MODULES(GSTREAMER, [gstreamer-0.10], [ 135 | AC_DEFINE(USE_GSTREAMER, 1, [Use Gstreamer for playing sound]) 136 | AC_SUBST(GSTREAMER_CFLAGS) 137 | AC_SUBST(GSTREAMER_LIBS) 138 | ] , [ 139 | echo "" 140 | echo "configure: error: " 141 | echo "gstreamer development headers not found." 142 | echo "Use --disable-gst if you do not need it." 143 | echo "If you're using debian or ubuntu,install it by " 144 | echo "\"sudo apt-get install libgstreamer0.10-dev\"" 145 | echo "" 146 | exit -1 147 | ]) 148 | fi 149 | 150 | # checks for networkmanager 151 | if test "x$enable_nm" = "xyes"; then 152 | PKG_CHECK_MODULES(NETWORKMANAGER, [NetworkManager >= 0.5.0], [ 153 | AC_DEFINE(USE_NETWORKMANAGER, 1, [Use NetworkManager for monitoring network status]) 154 | AC_SUBST(NETWORKMANAGER_CFLAGS) 155 | AC_SUBST(NETWORKMANAGER_LIBS) 156 | ] , [ 157 | echo "" 158 | echo "configure: error: " 159 | echo "NetworkManager development headers not found." 160 | echo "Use --disable-nm if you do not need it." 161 | echo "If you're using debian or ubuntu,install it by " 162 | echo "\"sudo apt-get install libnm-glib-dev\"" 163 | echo "" 164 | exit -1 165 | ]) 166 | fi 167 | 168 | PKG_CHECK_MODULES(LIBSSL, [ 169 | openssl 170 | ]) 171 | 172 | PKG_CHECK_MODULES(GLIB2, [ 173 | glib-2.0 >= 2.14 174 | ]) 175 | 176 | PKG_CHECK_MODULES(GOBJECT2, [ 177 | gobject-2.0 >= 2.14 178 | ]) 179 | 180 | AC_ARG_ENABLE(debug, 181 | [ --enable-debug turn on debug], 182 | CPPFLAGS+="-DFETION_DEBUG_TRACE") 183 | 184 | # Checks for typedefs, structures, and compiler characteristics. 185 | 186 | # Checks for library functions. 187 | AC_FUNC_FORK 188 | AC_FUNC_MALLOC 189 | AC_CHECK_FUNCS([bzero gethostbyname memset mkdir select socket strstr strtol]) 190 | AC_CHECK_FUNCS([inet_ntoa]) 191 | 192 | AC_CONFIG_FILES( po/Makefile.in 193 | Makefile 194 | lib/Makefile 195 | lib/ofetion.pc 196 | src/Makefile 197 | skin/Makefile 198 | skin/face_images/Makefile 199 | include/Makefile 200 | include/openfetion/Makefile 201 | resource/Makefile 202 | ) 203 | AC_OUTPUT 204 | 205 | echo 206 | echo Use XScreenSaver Extension.... : $enable_screensaver 207 | echo Use libnotify................. : $enable_libnotify 208 | echo Use gstreamer0.10............. : $enable_gst 209 | echo Use NetworkManager............ : $enable_nm 210 | echo 211 | -------------------------------------------------------------------------------- /doc/msgformat: -------------------------------------------------------------------------------- 1 | //个人 2 | r={ 3 | "to":1242066617, 4 | "face":81, 5 | "content": 6 | "[\"测试。test.\" 7 | ,[\"font\" 8 | ,{\"name\":\"\\\"微软雅黑\\\"\" 9 | ,\"size\":\"11\" 10 | ,\"style\":[0,0,0] 11 | ,\"color\":\"000000\" 12 | } 13 | ] 14 | ]", 15 | "msg_id":57890008, 16 | "clientid":"30789207", 17 | "psessionid":"8368046764001e636f6e6e7365727..." 18 | } 19 | r={ 20 | "to":"1363755325", 21 | "face":519, 22 | "content": 23 | "[ 24 | [\"font\", 25 | {\"size\": 20, \"color\": \"0000FF\", \"style\":[0,1,1], \"name\":\"微软雅黑\"}] 26 | ,[\"face\", 20], 27 | [\"face\", 22], 28 | \"来自GtkQQ的测试!!Test ^v^...\",\"\"]", 29 | "msg_id":1001,"clientid":"66112734", 30 | "psessionid":"83ca7b3501c826d1d9b23e9ec4b2b23"} 31 | 32 | //群 33 | r={ 34 | "group_uin":2626552497 35 | ,"content": 36 | "[ 37 | [\"face\",110] 38 | ,\"test测试\" 39 | ,\"\\n【提示:此用户正在使用WebQQ:http://web.qq.com/】\" 40 | ,[\"font\", 41 | {\"name\":\"宋体\" 42 | ,\"size\":\"10\" 43 | ,\"style\":[0,0,0] 44 | ,\"color\":\"000000\" 45 | } 46 | ] 47 | ]" 48 | ,"msg_id":88520003 49 | ,"clientid":"59852093" 50 | ,"psessionid":"8368046764001e636f6e6e7c155..." 51 | }&clientid=59852093&psessionid=8368046764001e63... 52 | -------------------------------------------------------------------------------- /doc/table.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * Tables used in gtkqq 3 | */ 4 | 5 | /* 6 | * config table 7 | * contain all the configuration items. 8 | * The key is string. The value can be any type according to the key. 9 | */ 10 | create table if not exists config( 11 | id primary key asc autoinscrement, -- primary key int 12 | owner, -- the owner. string 13 | key, -- key. string 14 | value -- value. string 15 | ); 16 | 17 | /* 18 | * qquser table 19 | * All the users who has logined 20 | * `last` is used to mark the last login user. 21 | */ 22 | create table if not exists qquser( 23 | qqnumber primary key , -- primary key string 24 | last, -- int 25 | passwd, -- base64 encoded password 26 | status -- last status 27 | ); 28 | 29 | /* 30 | * buddies table 31 | * all the buddies 32 | */ 33 | create table if not exists buddies( 34 | id primary key asc autoinscrement, -- primary key int 35 | owner, -- the owner of this buddy. string 36 | qqnumber, -- string 37 | vip_info, -- int 38 | nick, -- string 39 | markname, -- string 40 | faceimgfile, -- the file path of the face image. string 41 | country, -- string 42 | province, -- string 43 | city, -- string 44 | gender, -- int 45 | face, -- int 46 | flag, -- int 47 | birthday_y, -- birthday year. int 48 | birthday_m, -- birthday month. int 49 | birthday_d, -- birthday day. int 50 | blood, -- int 51 | shengxiao, -- int 52 | constel, -- int 53 | phone, -- string 54 | mobile, -- string 55 | email, -- string 56 | occupation, -- string 57 | college, -- string 58 | homepage, -- string 59 | personal, -- string 60 | lnick, -- string 61 | cate_idx, -- the index of catogory which this buddy is belong to. 62 | 63 | -- foreign key 64 | foreign key(owner) references qquser(qqnumber) on delete cascade 65 | ); 66 | 67 | /* 68 | * groups table 69 | */ 70 | create table if not exists groups( 71 | gnumber primary key, -- group number. string 72 | owner, -- the owner of this buddy. string 73 | name, -- string 74 | code, -- string 75 | flag, -- string 76 | creater, -- string 77 | mark, -- string 78 | mask, -- string 79 | opt, -- int 80 | createtime, -- string 81 | gclass, -- int 82 | glevel, -- int 83 | face, -- int 84 | memo, -- string 85 | fingermemo -- sttring 86 | 87 | -- foreign key 88 | foreign key(owner) references qquser(qqnumber) on delete cascade 89 | ); 90 | 91 | /* 92 | * group member table 93 | */ 94 | create table if not exists gmemebers( 95 | gnumber, -- the group number. string 96 | qqnumber, -- qq number. string 97 | nick, -- string 98 | flag, -- string 99 | card -- string 100 | 101 | -- foreign key 102 | foreign key(gnumber) references groups(gnumber) on delete cascade 103 | ); 104 | 105 | /* 106 | * categories table 107 | */ 108 | create table if not exists categories( 109 | id primary key asc autoinscrement, -- primary key int 110 | owner, -- the owner of this buddy. string 111 | idx, -- index. int 112 | name, -- name. string 113 | 114 | -- foreign key 115 | foreign key(owner) references qquser(qqnumber) on delete cascade 116 | ); 117 | 118 | -------------------------------------------------------------------------------- /doc/webqq登录过程分析: -------------------------------------------------------------------------------- 1 | 写下这个标题的时候,您可能要问,webqq登录协议有什么用?很简单,qq所有产品都是采用统一的登录协议加密登录的。也就是说,当您能够通过使用它的协议来登录并获取到令牌后,那么就可以任意的使用qq的各项产品了,如webqq,空间,微博,校友。。等等的。而本文主要就是讲述下如何通过技术手段来使用webqq的协议,从而获取到登录令牌。所有完整的源代码,可以从我的开源项目 CDM SYSTEM中的pushblog插件获取并且试用。地址是:http://code.google.com/p/linblog/ 2 | 3 | 一、腾讯产品的登录与验证过程 4 | 5 | 腾讯产品的登录一共需要经过三次验证,分别是在登录页面1、验证帐号状态,并通过帐号获取令牌的原始密钥;2、对原始密钥进行运算生成令牌密钥并提交服务器,服务器进行一次验证;3、经过第二次验证通过,服务器自动跳转,进行第三此验证,最后返回登录令牌……终成功后才能获取到加密过后的登录令牌,而利用此令牌就可以顺利的操作任何腾讯的产品与服务了。接下来我们以腾讯微博为例来进行一些在合法的限度内的讲解,旨在开拓各位读者的思维与分享技术思路,因此如果您抱着想要通过本文的讲解来进行获利的目的,那我建议您可以就此打住了。因为,接下来的内容中我并不会去讲解或者说分享那些您会感兴趣的东西。 6 | 7 | 二、协议详解 8 | 9 | 1、言归正传,首先第一次的登录是发生在我们打开登录页面的时候。 还是以腾讯微博为例,当我们打开微博的登录页面时,页面上的js会触发一个地址:http://ptlogin2.qq.com/check?uin=939567050&appid=46000101&r=0.5354662109559408 10 | 11 | 这个地址是用来判断您的用户名是否是正常状态,以及是否有效用户名,并返回一个状态值以及一个验证码。其中uin就是你的用户名,appid指的是腾讯产品的编码。r是一个随机生成的数字,用来避免浏览器缓存。 12 | 13 | 14 | 15 | 正常时,请求这个地址,会获得类似ptui_checkVC('0','!AFO');这样的返回值,这其中0是代表正常状态,不采用图片验证。但是如果短时间内这个帐号多次在不同的ip登录,那么返回值就是另外的一种返回值了,那表明需要进行图片验证码验证。 16 | 此外,0还有可能变为其他的数值,用来标明诸如帐号不存在,帐号状态不正确,帐号已锁定等等的。。。。。而后面的!AFO是四位则是我们需要获得的原始令牌值,它是由腾讯服务器随机生成的一个令牌的原始密钥。当然也许您在获取的时候会发现这个值并不是4位,而是很多位。那么就要恭喜您了,您获得也是令牌的原始密钥,只不过不同的是,您获得是图片验证码的原始密钥而已。 17 | 18 | 当然其实图形验证码的自动识别也很简单,只是这已经超出本文的范围了,以后有机会可以与大家再次分享下。此时,当我们正确的获得!AFO时就已经完成了第一次的验证!但是有一点需要注意的是:腾讯的令牌是存储在cookies中的, 19 | 20 | 所以请注意每次操作都必须要保存好服务器返回来的cookies。以下为python语言写的的示例代码,此代码可以从http://code.google.com/p/linblog/ 中的pushmodel.py文件中获取。 21 | 22 | 23 | 24 | def Get_qq_msg_val(self,username,password): 25 | verifyURL = 'http://ptlogin2.qq.com/check?uin=%s&appid=46000101&r=%s'% (username,random.random()) 26 | loginURL = 'http://ptlogin2.qq.com/login?' 27 | redirectURL = '' 28 | cookie = '' 29 | qqn = username 30 | md5Pass = '' 31 | verifyCode = '' 32 | result = urlfetch.fetch(url=verifyURL,method=urlfetch.GET, 33 | follow_redirects = False,headers={ 34 | 'Content-Type': 'application/x-www-form-urlencoded', 35 | 'user-agent':'Mozilla/5.0 (Linux; U; Linux i686; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.4.2.80 Safari/525.13', 36 | },) 37 | cookie1 = Cookie.SimpleCookie(result.headers.get('set-cookie', '')) 38 | verifyCode=result.content[18:-3] 39 | if len(verifyCode)>4: 40 | return False,None 41 | loginURL += "u=%s&p="% username 42 | loginURL+=self.EncodePasswordWithVerifyCode(password,verifyCode) 43 | loginURL += "&verifycode="+verifyCode+"&aid=46000101&u1=http%3A%2F%2Ft.qq.com&ptredirect=1&h=1&from_ui=1&fp=loginerroralert" 44 | result=urlfetch.fetch(url=loginURL, 45 | headers={'Referer':'http://t.qq.com', 46 | 'Cookie' : self.make_cookie_header(cookie1), 47 | 'Content-Type': 'application/x-www-form-urlencoded', 48 | 'user-agent':'Mozilla/5.0 (Linux; U; Linux i686; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.4.2.80 Safari/525.13', 49 | }, 50 | method=urlfetch.GET, 51 | follow_redirects = False, 52 | ) 53 | setCookies = result.headers.get('set-cookie', '').split(';') 54 | cookie2 = '' 55 | cookie2+=setCookies[29] 56 | cookie2+=setCookies[7] 57 | cookie2+=setCookies[4] 58 | cookie2+=';'+setCookies[0] 59 | cookie2 = cookie2.replace(',', ';') 60 | cookie2 = cookie2[1:] 61 | callback_url = result.headers.get('location','http://t.qq.com') 62 | result,cookies = self.do_redirect(callback_url, cookie2) 63 | 64 | return result,cookies 65 | 66 | 67 | 68 | 69 | 70 | 71 | 2、此时我们需要对获取到的原始密钥进行一系列的运算,从而得到令牌密钥。这个算法其实也很简单,就是先把用户密码连续进行两次md5加密,每次md5加密输出二进制的结果,然后在对经过两次md5加密后的结果在进行一次md5加密,最后输出16进制大写的结果。在把我们第一步获取到的原始密钥合并在此结果之后,形成一个新的字符串。并且再次对此字符串进行md5加密,并输出16进制大写的字符串。此时,此字符串就为令牌密钥了。示例代码如下 72 | 73 | 74 | 75 | def md5hash(self,str): 76 | return hashlib.md5(str).digest() 77 | def hex_md5hash(self,str): 78 | return hashlib.md5(str).hexdigest().upper() 79 | def md5hash_3(self,str): 80 | return self.hex_md5hash(self.md5hash(self.md5hash(str))) 81 | def EncodePasswordWithVerifyCode(self,pwd, verifyCode): 82 | return self.hex_md5hash(self.md5hash_3(pwd) + verifyCode.upper()) 83 | EncodePasswordWithVerifyCode()即为此加密算法,pwd是密码,verifyCode为我们第一步获取到的4位的原始密钥。 84 | 3、接下来,我们需要把这个原始密钥送到腾讯的服务器进行验证,并返回令牌结果。服务器的地址为:http://ptlogin2.qq.com/login?u=alexliyu2012@qq.com&p=D265C1F4C6C1D36AF17A086448FA996D&verifycode=!NDJ&aid=46000101&u1=http%3A%2F%2Ft.qq.com&ptredirect=1&h=1&from_ui=1&dumy=&fp=loginerroralert 85 | 86 | 这其中,u代表是用户帐号,p就是我们第二步所生成的令牌密钥,verifycode为我们第一步获取的原始密钥,u1为我们登录的产品地址,至于后面的那些参数不用管它,写什么都无所谓的。我们只要生成此链接并请求后,服务器通过验证就会返回给我们最终的令牌。只是此令牌并不是返回一组数据,而是全部以cookies的形式返回。这是我们需要注意的第一点,其次是当我们请求此地址时,此地址会返回如下的cookies 87 | 88 | 89 | 90 | pt2gguin o0939567050 / qq.com Fri, 02-Jan-2020 00:00:00 GMT 91 | uin o0939567050 / qq.com End Of Session 92 | skey @aw6EH0ljo / qq.com End Of Session 93 | clientuin / qq.com Fri, 02-Jan-1970 00:00:00 GMT 94 | clientkey / qq.com Fri, 02-Jan-1970 00:00:00 GMT 95 | zzpaneluin / qq.com Fri, 02-Jan-1970 00:00:00 GMT 96 | zzpanelkey / qq.com Fri, 02-Jan-1970 00:00:00 GMT 97 | ptisp ctc / qq.com End Of Session 98 | ptcz f41721c4e7bc752fdeae10c9cb2db66ca66af1049a4835185acfdfe2a26860e5 / qq.com Fri, 02-Jan-2020 00:00:00 GMT 99 | airkey / qq.com Fri, 02-Jan-1970 00:00:00 GMT 100 | 这其中其他的都不用解释了,看命名就知道作用了。我要提醒的是,skey这个cookie以及ptcz是关键。为什么呢?因为skey这个值,在很多地方都非常有用,比如添加好友,或者qzone发布日志,都需要对此值进行验证。当然最保险的方法仍旧是cookies每次一次的都保留起来,一个都不放过,哈哈。 101 | 102 | 接下来当此地址验证通过后,腾讯会给你添加如上的cookies然后自动跳转到最后一个验证页面,一般来说此页面为你登录服务的主页,但是也有例外,比如qzone,就是一个successd的页面。这个自己嗅探一下就可以了。 103 | 104 | 还是以qq微博为例,这一步会跳转到t.qq.com页面去,在这个页面中会返回给一个诸如:mb_june SjrVWJyAbfrtNS5yh0cbbcZtCr%2FIvvqtBwVtFE6JCG4G0CY46WdpVX1%2FnGuAfXZE / t.qq.com Mon, 20-Sep-2010 14:48:27 GMT 这样的cookies值。此时,算是令牌已经获取到了。解析来,只要你一直保存有这些cookies,就可以操作腾讯任意的服务了。需要提醒大家注意一点就是,这个令牌是通用的,也就是你是在t.qq.com登录与获取的令牌,但是通过此令牌一样的可以操作webqq或者qzone,而不用再次的进行登录了。 105 | 106 | 107 | 108 | def do_redirect(self,url, cookie): 109 | logging.info(url) 110 | result = urlfetch.fetch( 111 | url=url, 112 | headers={'Cookie':cookie, 113 | 'Content-Type': 'application/x-www-form-urlencoded', 114 | 'user-agent':'Mozilla/5.0 (Linux; U; Linux i686; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.4.2.80 Safari/525.13',}, 115 | method=urlfetch.GET, 116 | follow_redirects = False, 117 | ) 118 | return result,cookie 119 | 三、如何操作腾讯的应用服务 120 | 121 | 这个其实就是苦功夫了,你可以通过socket直接与服务器进行通讯,或者使用webqq的协议,或者使用腾讯每个服务自己的web页面的接口来实现。但是,这些都需要您去进行嗅探并且分析协议的内容。相对来说,web页面直接的接口是最简单的,无非就是post表单过去,或者对页面进行get请求,然后得到返回值,在对返回值进行操作并再次的发起请求而已。其次是webqq协议也相对好解决它是通过与http://web-proxy24.qq.com/ (24这个数字是可以变化的,具体看你使用哪个服务器了,这只是腾讯的通信代理服务器)进行json格式的数据交换而已,而且所有信息都是明文的,也很好理解。自己尝试一段时间,就能搞清楚协议中每个参数以及api的含义了。对此,李昱有利用业余时间做了一个qq聊天机器人玩,但是讲起来太多了,也太敏感了,因此本文并不进行探讨,以后有空在与大家进行分享。下面就简单的给出发布qq微博与qzone文章的代码以便于大家理解,具体不再进行解释了。 122 | 123 | qq微博的发送代码: 124 | 125 | 126 | 127 | def send_qq_msgs(self,username,password,msg,memcachekey): 128 | """ 129 | send sina msgs. use qq username, password. 130 | the msgs parameter is a message list, not a single string. 131 | """ 132 | cookie='' 133 | if memcache.get(memcachekey): 134 | cookie=memcache.get(memcachekey) 135 | else: 136 | result,oldcookie=self.Get_qq_msg_val(username,password) 137 | if result==False: 138 | return False 139 | cookie='%s;%s'% (result.headers.get('set-cookie', ''),oldcookie) 140 | memcache.set(memcachekey,cookie,36000) 141 | msg=unescape(msg) 142 | form_fields = { 143 | "content": msg, 144 | "pic":'', 145 | "countType":'', 146 | "viewModel":1 147 | } 148 | form_data = urllib.urlencode(form_fields) 149 | try: 150 | result = urlfetch.fetch(url="http://t.qq.com/publish.php?rnd=0.5100760071072727", 151 | payload=form_data, 152 | method=urlfetch.POST, 153 | headers={'Referer':'http://t.qq.com', 154 | 'Cookie' : cookie, 155 | 'user-agent':'Mozilla/5.0 (Linux; U; Linux i686; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.4.2.80 Safari/525.13', 156 | 157 | },follow_redirects = False) 158 | except: 159 | return False 160 | if result.status_code == 200: 161 | return True 162 | else: 163 | return False 164 | -------------------------------------------------------------------------------- /doc/webqq解析: -------------------------------------------------------------------------------- 1 | WebQQ协议解析 2 | 3 | 1.登录1421032531 4 | WebQQ的登录是通过网址http://ui.ptlogin2.qq.com/cgi-bin/login完成。 5 | 访问这个网址的时候需要几个参数。首先,appid和s_url是必需的。这两个的值 6 | 可以设置为1003903和http://web2.qq.com/loginproxy.html。通常在通过webqq登录的时 7 | 后还会有其他参数,但不是必需的。比如style表示的是风格。应该是腾讯给其他版本的 8 | QQ提供不同的登录风格。由于不同style的登录页面代码有差别,因此,下面的分析采用 9 | webqq使用的风格4。还有下面的参数target=self,appid=1003903,enable_qlogin=0, 10 | no_verifyimg=1。发现这几个参数是硬编码在html文件中的。因此用这些默认的值就可以。 11 | 通过这个地址可以获取到登录窗口的所有源码。最重要的就是那个登录form。 12 | form中有用的参数有三个,action="http://ptlogin2.qq.com/login",method="post"和 13 | onsubmit="ptui_onLoginEx(loginform,'qq.com')"。在提交登录信息之前,通过函数 14 | ptui_onLoginEx函数处理提交的信息。 15 | 完成所有源码的下载之后,webqq需要获得一个叫做vc_type的变量。这个变量在 16 | 后面的通讯中有用。首先,发送GET请求http://ptlogin2.webqq.com/check?uin=xxxxxx& 17 | appid=1003903&r=xx其中,uin是qq号。appid是前面加载验证码图片的ptui_changeImg函 18 | 数的第二个参数。r是一个小于1的随机数。服务器返回下面的数据:ptui_checkVC('1', 19 | '44657d96f141ad5fc9ced861e2ba1a48b32e0dc974505ad7');。第二个参数就是vc_type的 20 | 值。这同时也是检测是否需要输入验证码。 21 | 在加载验证码图片的时候,会调用imgLoadReport函数来检测是否需要验证码。 22 | 服务器会返回前面提到的vc_type的值。通过下面的请求获取新的验证码图片: 23 | http://captcha.qq.com/getimage?&uin=xxx&vc_type=xxx&aid=1002101&random。 24 | aid后面紧跟着一个小于1的随机数。验证码的生成估计和这个发送的随机数有关。 25 | 当用户点击提交,也就是登录之后。如果用户选择记住密码,那么调用函数 26 | ptui_onLoginEx(form, "qq.com")来完成登录,否则调用ptui_onLogin(form)。最终调用函数 27 | ajax_Submit提交登录申请。在ajax_Submit中拼接发送个登录网址的参数。 28 | 主要的参数如下: 29 | u = QQ号码 30 | p = 对密码进行三次MD5运算,加上全部大写的验证码,再进行一次MD5运算。 31 | verifycode = 验证码 32 | webqq_type = 1 33 | remember_uin = 1 or 0 是否记住用户名 34 | 下面的几个参数都是从页面的隐藏标签中获得。 35 | aid = 1002101 36 | ul = http://web2.qq.com 37 | ptredirect=1 38 | ptlang=2052 39 | from_ui=1 40 | pttype=1 41 | fp=loginerroralert 42 | 43 | 发送出去之后。服务器返回为: 44 | 1.ptuiCB('4','0','','0','\346\202\250\350\276\223\345\205\245\347\232\204 45 | \351\252\214\350\257\201\347\240\201\346\234\211\350 46 | \257\257\357\274\214\350\257\267\351\207\215\350\257 47 | \225\343\200\202') 48 | 表示密码或者验证码错误。 49 | 50 | 2.ptuiCB('0','0','http://web2.qq.com/loginproxy.html?login_level=3','0', 51 | '\347\231\273\345\275\225\346\210\220\345\212\237\357 52 | \274\201') 53 | 表示登录成功。 54 | (注:上面的\xxx是utf8编码的字符,glib可以直接识别。不需要做任何处理, 55 | glib会以正确的形式输出和现实。) 56 | 0:登录成功! 57 | 1:系统繁忙,请稍后重试。 58 | 2:已经过期的QQ号码。 59 | 3:您输入的密码有误,请重试。 60 | 4:您输入的验证码有误,请重试。 61 | 5:校验失败。 62 | 6:密码错误。如果您刚修改过密码, 请稍后再登录. 63 | 7:您的输入有误, 请重试。 64 | 8:您的IP输入错误的次数过多,请稍后再试。 65 | 66 | 67 | 然后,通过POST方法向http://d.web2.qq.com/channel/login2发送数据r={"status":"", 68 | "ptwebqq":"83274d9a158ec3151bcb47cea852a518c4f6ed590420ae33bd03df0fc8f57a91", 69 | "passwd_sig":"","clientid":"59790248","psessionid":null}获取登录后的信息。这个数 70 | 据需要url转码。ptwebqq在前面登录的form提交后,返回的response中的cookie中。 71 | 72 | 服务器返回,{"retcode":0,"result":{"uin":494498045,"index":1074,"port":33237, 73 | "status":"hidden","vfwebqq":"6c8fdacdba15f2f9c666c114be65afa7de1d5e37eaff87e 74 | 1ac37099ef1d2421010d8d4452510a211", 75 | "psessionid":"8368046764001e636f6e6e7365727665725f77656271714031302e3132382e3 76 | 6362e31313500000e030000039e026e0400fd70791d6d0000000a40784c74344a4f666d786d00 77 | 0000286c8fdacdba15f2f9c666c114be65afa7de1d5e37eaff87e1ac37099ef1d2421010d8d44 78 | 52510a211"}}其中,vfwebqq和pesssionid是每次通讯必需使用的。 79 | 80 | 至此,登录成功。 81 | 82 | 获取好友和分组: 83 |   地址:http://web2-b.qq.com/api/get_user_friends 84 | 提交参数 r=%7B%22vfwebqq%22%3A%22{0}%22%7D {0}为登陆成功后返回的vfwebqq 85 | 提交方式:post 86 | 返回结果包含了好友分组 好友 好友信息 87 | 88 | 这里获取的好友唯一一点不足就是无法区别好友是否在线,还得专门去获取在线好友。倒是QQ空间获取好友的方式比较适用 89 | 90 | 获取在线好友: 91 | 地址:http://web2-b.qq.com/channel/get_online_buddies?clientid={0}&psessionid={1}&t={2} 92 | {0}登陆时生成的clientid,{1}登陆后获取的psessionid参数 {2}时间戳 93 | 提交方式:get 94 | 95 | 获取群: 96 | 地址:http://web2-b.qq.com/api/get_group_name_list_mask 97 | 参数:r=%7B%22vfwebqq%22%3A%22{0}%22%7D {0}为登陆后获取的vfwebqq 98 | 提交方式:post 99 | 100 | 获取个性签名: 101 | 地址:http://web2-b.qq.com/api/get_single_long_nick?tuin={0}&t={1} {0}QQ号码 {1}时间戳 102 | 提交方式 get 103 | 104 | 设置个性签名: 105 | 地址:"http://web2-b.qq.com/api/set_long_nick 106 | 提交参数:r=%7B%22nlk%22%3A%22{0}%22%2C%22vfwebqq%22%3A%22{1}%22%7D 107 | {0}为签名内容 {1}为登陆后获取的vfwwebqq参数 108 | 提交方式 post 109 | 110 | 2.登出 111 | 3.获取个人信息 112 | 4.获取好友列表及信息 113 | 5.获取群信息 114 | 6.发送和接收好友消息 115 | 7.发送和接收群消息 116 | 8.传送和接收文件 117 | 9.其他 118 | 119 | 120 | 121 | 客户端密码的加密: 122 | 首先将密码用md5加密三次。 123 | 然后将加密结果和验证码链接成字符串。 124 | 再对这个字符串用md5加密。 125 | 126 | 127 | clientid = String(m.random(0, 99)) + String((new Date()).getTime() % 1000000) 128 | 129 | msg_id 130 | v = (new Date()).getTime(); 131 | v = (v - v % 1000) / 1000; 132 | v = v % 10000 * 10000; 133 | var u = function() { 134 | p++; 135 | return v + p; 136 | }; 137 | clientType: {1: "PC",2: "PC",3: "PC",4: "PC",5: "PC",6: "PC",10: "PC",21: "Phone",22: "Phone",23: "Phone",24: "Phone",41: "WebQQ",42: "PC",1E4: "PC"} 138 | 139 | -------------------------------------------------------------------------------- /pixmaps/Makefile.am: -------------------------------------------------------------------------------- 1 | appicondir = $(datadir)/pixmaps 2 | appicon_DATA = gtkqq.png 3 | 4 | desktopdir = $(datadir)/applications 5 | desktop_DATA = gtkqq.desktop 6 | 7 | EXTRA_DIST = $(appicon_DATA) $(desktop_DATA) 8 | 9 | -------------------------------------------------------------------------------- /pixmaps/gtkqq.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Name=GTKQQ 4 | Name[es]=GTKQQ 5 | GenericName=QQ Client 6 | GenericName[es]=QQ Client 7 | Comment=QQ client written in GTK 8 | Comment[es]=QQ client written in GTK 9 | Exec=gtkqq 10 | Icon=gtkqq 11 | Terminal=false 12 | Type=Application 13 | Categories=Network; 14 | StartupNotify=true 15 | -------------------------------------------------------------------------------- /pixmaps/gtkqq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/pixmaps/gtkqq.png -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS=comm libqq gui cli tool test misc 2 | -------------------------------------------------------------------------------- /src/cli/Makefile.am: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/cli/Makefile.am -------------------------------------------------------------------------------- /src/comm/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = cprint.c cprint.h log.c log.h 2 | -------------------------------------------------------------------------------- /src/comm/cprint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define FMTMARK "\e[%dm" 8 | 9 | int cprintf(FgColor fc, BgColor bc, Ptype t 10 | , const char *fmt,...) 11 | { 12 | va_list ap; 13 | va_start(ap, fmt); 14 | int r = fvcprintf(STDOUT_FILENO, fc, bc, t, fmt, ap); 15 | va_end(ap); 16 | return r; 17 | } 18 | 19 | int fcprintf(int fd, FgColor fc, BgColor bc, Ptype t 20 | , const char *fmt,...) 21 | { 22 | va_list ap; 23 | va_start(ap, fmt); 24 | int r = fvcprintf(fd, fc, bc, t, fmt, ap); 25 | va_end(ap); 26 | return r; 27 | } 28 | 29 | int fvcprintf(int fd, FgColor fc, BgColor bc, Ptype t 30 | , const char *fmt, va_list ap) 31 | { 32 | char nfmt[5000]; 33 | int idx = 0; 34 | 35 | if(fc != UNSET_F){ 36 | idx += snprintf(nfmt + idx, 5000 - idx, FMTMARK, fc); 37 | } 38 | 39 | if(bc != UNSET_B){ 40 | idx += snprintf(nfmt + idx, 5000 -idx, FMTMARK, bc); 41 | } 42 | 43 | if(t != UNSET_T){ 44 | idx += snprintf(nfmt + idx, 5000 -idx, FMTMARK, t); 45 | } 46 | 47 | idx += snprintf(nfmt + idx, 5000 - idx, "%s", fmt); 48 | snprintf(nfmt + idx, 5000 - idx, "\e[0m"); 49 | 50 | return vprintf(nfmt, ap); 51 | } 52 | -------------------------------------------------------------------------------- /src/comm/cprint.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMM__CPRINT_H 2 | #define __COMM__CPRINT_H 3 | /* 4 | * color print 5 | */ 6 | #include 7 | /* 8 | * 背景色: 9 | * 40:黑 41:深红 42:绿 43:黄色 44:蓝色 45:紫色 46:深绿 47:白色 10 | * 前景色: 11 | * 30:黑 31:红 32:绿 33:黄 34:蓝色 35:紫色 36:深绿 37:白色 12 | */ 13 | /* 14 | * foreground color 15 | */ 16 | typedef enum{ 17 | BLACK_F = 30, //black 18 | RED_F = 31, //red 19 | GREEN_F = 32, //green 20 | YELLOW_F = 33, //yellow 21 | BLUE_F = 34, //blue 22 | PURPLE_F = 35, //purple 23 | DARKBLUE_F = 36, //dark blue 24 | WHITE_F = 37, //white 25 | UNSET_F = -1 //do not set the foreground color 26 | }FgColor; 27 | 28 | /* 29 | * background color 30 | */ 31 | typedef enum{ 32 | BLACK_B =40, //black 33 | DARKRED_B =41, //dark red 34 | GREEN_B =42, //green 35 | YELLOW_B =43, //yellow 36 | BLUE_B =44, //blue 37 | PURPLE_B =45, //purple 38 | DARKGREEN_B =46, //dark green 39 | WHITE_B =47, //white 40 | UNSET_B = -1 //do not set the background color 41 | }BgColor; 42 | 43 | /* 44 | * The type of the string. 45 | * \033[1m 设置高亮度 46 | * \033[4m 下划线 47 | * \033[5m 闪烁 48 | * \033[7m 反显 49 | * \033[8m 消隐 50 | */ 51 | 52 | typedef enum{ 53 | HIGHLIGHT = 1, //highlight 54 | UNDERLINE = 4, //under line 55 | BLINKING = 5, //blink 56 | REVERSE = 7, //reverse 57 | HIDE = 8, //hide 消隐 58 | UNSET_T = -1 //do not set the print type 59 | }Ptype; 60 | 61 | /* 62 | * The same as printf. 63 | * It can print color string on the console. 64 | */ 65 | int cprintf(FgColor fc, BgColor bc, Ptype t 66 | , const char *fmt, ...); 67 | 68 | int fvcprintf(int fd, FgColor fc, BgColor bc, Ptype t 69 | , const char *fmt, va_list ap); 70 | 71 | int fcprintf(int fd, FgColor fc, BgColor bc, Ptype t 72 | , const char *fmt,...); 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/comm/log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | /* 5 | * the log handler 6 | */ 7 | static void log_handler(const gchar *log_domain, 8 | GLogLevelFlags log_level, 9 | const gchar *message, 10 | gpointer user_data) 11 | { 12 | switch(log_level) 13 | { 14 | case G_LOG_LEVEL_MESSAGE: 15 | fcprintf(STDOUT_FILENO, GREEN_F, UNSET_B, HIGHLIGHT 16 | , "MESSAGE : "); 17 | fcprintf(STDOUT_FILENO, UNSET_F, UNSET_B, UNSET_T, message); 18 | fcprintf(STDOUT_FILENO, UNSET_F, UNSET_B, UNSET_T, "\n"); 19 | break; 20 | case G_LOG_LEVEL_DEBUG: 21 | #ifdef GTKQQ_DEBUG 22 | fcprintf(STDOUT_FILENO, BLUE_F, UNSET_B, HIGHLIGHT 23 | , "DEBUG : "); 24 | fcprintf(STDOUT_FILENO, UNSET_F, UNSET_B, UNSET_T, message); 25 | fcprintf(STDOUT_FILENO, UNSET_F, UNSET_B, UNSET_T, "\n"); 26 | #endif 27 | break; 28 | case G_LOG_LEVEL_WARNING: 29 | fcprintf(STDERR_FILENO, PURPLE_F, UNSET_B, HIGHLIGHT 30 | , "** WARNING ** : "); 31 | fcprintf(STDOUT_FILENO, UNSET_F, UNSET_B, UNSET_T, message); 32 | fcprintf(STDOUT_FILENO, UNSET_F, UNSET_B, UNSET_T, "\n"); 33 | break; 34 | case G_LOG_LEVEL_ERROR: 35 | case G_LOG_FLAG_FATAL: 36 | case G_LOG_FLAG_RECURSION: 37 | fcprintf(STDOUT_FILENO, RED_F, UNSET_B, HIGHLIGHT 38 | , "!!ERROR!! : "); 39 | fcprintf(STDOUT_FILENO, UNSET_F, UNSET_B, UNSET_T, message); 40 | fcprintf(STDOUT_FILENO, UNSET_F, UNSET_B, UNSET_T, "\n"); 41 | break; 42 | default: 43 | break; 44 | } 45 | } 46 | 47 | 48 | void log_init() 49 | { 50 | g_log_set_handler(NULL, G_LOG_LEVEL_MESSAGE, log_handler, NULL); 51 | g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, log_handler, NULL); 52 | g_log_set_handler(NULL, G_LOG_LEVEL_WARNING, log_handler, NULL); 53 | } 54 | -------------------------------------------------------------------------------- /src/comm/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_LOG_H 2 | #define __GTKQQ_LOG_H 3 | 4 | #include 5 | 6 | /* 7 | * Initial the log.Set the log handler. 8 | * 9 | * Only set the message, debug and warning loggs' handler. 10 | * 11 | */ 12 | void log_init(); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/gui/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS=tencent test 2 | 3 | AM_CFLAGS=-I$(srcdir)/../libqq/\ 4 | -I$(srcdir)/../comm/\ 5 | -I$(srcdir)/.\ 6 | $(GTK_CFLAGS)\ 7 | $(SQLITE3_CFLAGS)\ 8 | $(GSTREAMER_CFLAGS)\ 9 | $(GSTINTERFACES_CFLAGS)\ 10 | -DIMGDIR=\"$(pkgdatadir)/misc/\"\ 11 | -DCONFIGDIR=\"$(HOME)/.gtkqq/\"\ 12 | -DSOUNDDIR=\"$(pkgdatadir)/misc/sound\"\ 13 | -Wall -Werror 14 | 15 | bin_PROGRAMS=gtkqq 16 | gtkqq_LDADD = $(GTK_LIBS) $(GSTREAMER_LIBS) $(GSTINTERFACES_LIBS) ${srcdir}/../libqq/libwebqq.la $(SQLITE3_LIBS) 17 | gtkqq_SOURCES=main.c \ 18 | msgloop.c msgloop.h\ 19 | dao.c dao.h\ 20 | msgdispacher.c msgdispacher.h\ 21 | tray.c tray.h\ 22 | facepopupwindow.c facepopupwindow.h\ 23 | chatwindow.c chatwindow.h\ 24 | groupchatwindow.c groupchatwindow.h\ 25 | chatwidget.c chatwidget.h\ 26 | chattextview.c chattextview.h\ 27 | buddytree.c buddytree.h\ 28 | buddylist.c buddylist.h\ 29 | loginpanel.c loginpanel.h \ 30 | mainpanel.h mainpanel.c\ 31 | mainwindow.h mainwindow.c \ 32 | ${srcdir}/../comm/log.c\ 33 | ${srcdir}/../comm/cprint.c\ 34 | splashpanel.h splashpanel.c\ 35 | gqqconfig.h gqqconfig.c\ 36 | statusbutton.h statusbutton.c\ 37 | sound.h sound.c\ 38 | proxypanel.c proxypanel.h 39 | 40 | -------------------------------------------------------------------------------- /src/gui/buddylist.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_BUDDY_LIST_H_ 2 | #define __GTKQQ_BUDDY_LIST_H_ 3 | #include 4 | #include 5 | // 6 | // Inherit from GtkTreeView 7 | // Used to show the groups and recent contancts 8 | // 9 | 10 | #define QQ_TYPE_BUDDY_LIST (qq_buddy_list_get_type()) 11 | #define QQ_BUDDY_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj)\ 12 | , QQ_TYPE_BUDDY_LIST\ 13 | , QQBuddyList)) 14 | #define QQ_IS_BUDDY_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj\ 15 | , QQ_TYPE_BUDDY_LIST))) 16 | #define QQ_BUDDY_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass)\ 17 | , QQ_TYPE_BUDDY_LIST\ 18 | , QQBuddyListClass)) 19 | #define QQ_IS_BUDDY_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass)\ 20 | , QQ_TYPE_BUDDY_LIST)) 21 | #define QQ_BUDDY_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj)\ 22 | , QQ_TYPE_BUDDY_LIST\ 23 | , QQBuddyListClass)) 24 | 25 | // 26 | // List store columns 27 | // 28 | enum{ 29 | BDY_LIST_TYPE = 0, // GDK_TYPE_PIXBUF, client type image 30 | BDY_LIST_IMG, // GDK_TYPE_PIXBUF, face image 31 | BDY_LIST_UIN, // G_TYPE_STRING, buddy uin or group code 32 | BDY_LIST_CLASS, // G_TYPE_INT, buddy or group. 1: buddy, 2:group 33 | // 3: group member 34 | BDY_LIST_NAME, // G_TYPE_STRING, buddy markname or group name 35 | BDY_LIST_LNICK, // G_TYPE_STRING, buddy long nick 36 | BDY_LIST_NUMBER, // G_TYPE_STRING, qq number of the group number 37 | // or group fingermemo 38 | BDY_LIST_COLUMNS // column number 39 | }; 40 | 41 | typedef struct __QQBuddyList QQBuddyList; 42 | typedef struct __QQBuddyListClass QQBuddyListClass; 43 | 44 | struct __QQBuddyList{ 45 | GtkTreeView parent; 46 | }; 47 | 48 | struct __QQBuddyListClass{ 49 | GtkTreeViewClass parent; 50 | }; 51 | 52 | GType qq_buddy_list_get_type(); 53 | GtkWidget * qq_buddy_list_new(); 54 | 55 | // 56 | // Add qq buddy , qq group and qq group member 57 | // 58 | void qq_buddy_list_add_buddy(GtkWidget *widget, QQBuddy *bdy); 59 | void qq_buddy_list_add_group(GtkWidget *widget, QQGroup *grp); 60 | void qq_buddy_list_add_group_member(GtkWidget *widget, QQGMember *gm); 61 | 62 | // 63 | // Add multiple buddies and groups and group members 64 | // 65 | void qq_buddy_list_add_buddies(GtkWidget *widget, GPtrArray *bdies); 66 | void qq_buddy_list_add_groups(GtkWidget *widget, GPtrArray *grps); 67 | void qq_buddy_list_add_group_members(GtkWidget *widget, GPtrArray *gms); 68 | 69 | // 70 | // Update the information of the qq buddy and qq group and member 71 | // 72 | void qq_buddy_list_update_buddy_info(GtkWidget *widget, QQBuddy *bdy); 73 | void qq_buddy_list_update_group_info(GtkWidget *widget, QQGroup *grp); 74 | void qq_buddy_list_update_group_member_info(GtkWidget *widget, QQGMember *gm); 75 | 76 | // 77 | // Update buddies and groups info and group members 78 | // 79 | void qq_buddy_list_update_buddies_info(GtkWidget *widget, GPtrArray *bdies); 80 | void qq_buddy_list_update_groups_info(GtkWidget *widget, GPtrArray *grps); 81 | void qq_buddy_list_update_group_members_info(GtkWidget *widget 82 | , GPtrArray *gms); 83 | #endif 84 | -------------------------------------------------------------------------------- /src/gui/buddytree.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_BUDDY_TREE_H 2 | #define __GTKQQ_BUDDY_TREE_H 3 | #include 4 | #include 5 | 6 | // 7 | // Create the buddy tree view 8 | // 9 | GtkWidget* qq_buddy_tree_new(); 10 | // 11 | // Update the buddy tree view model 12 | // 13 | void qq_buddy_tree_update_model(GtkWidget *tree, QQInfo *info); 14 | // 15 | // Update the buddies' face images. 16 | // 17 | void qq_buddy_tree_update_faceimg(GtkWidget *tree, QQInfo *info); 18 | // 19 | // Update the online buddies 20 | // 21 | void qq_buddy_tree_update_online_buddies(GtkWidget *tree, QQInfo *info); 22 | // 23 | // Update the buddy info 24 | // 25 | void qq_buddy_tree_update_buddy_info(GtkWidget *tree, QQInfo *info); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/gui/chattextview.h: -------------------------------------------------------------------------------- 1 | #ifndef __QQ_CHAT_TEXT_VIEW_H_ 2 | #define __QQ_CHAT_TEXT_VIEW_H_ 3 | #include 4 | #include 5 | 6 | // 7 | // The chat text view 8 | // The chat text view need to show the qq face images and show 9 | // the message like this: 10 | // 11 | // ------------------------------------------ 12 | // | kernel 2010-9-10 12:20:10 | <-- blue 13 | // | hello! | <-- custom color 14 | // | | 15 | // | memory 2010-9-10 12:20:30 | <-- green 16 | // | hello. Need help? | <-- custom color 17 | // | | 18 | // | kernel 2010-9-10 12:21:10 | 19 | // | Yes. Give me more memory. Thanks. | 20 | // | | 21 | // | memory 2010-9-10 12:22:30 | 22 | // | Ok. | 23 | // | | 24 | // | ... ... | 25 | // ------------------------------------------ 26 | // 27 | 28 | #define QQ_CHAT_TEXTVIEW(obj) G_TYPE_CHECK_INSTANCE_CAST(obj\ 29 | , qq_chat_textview_get_type()\ 30 | , QQChatTextview) 31 | #define QQ_CHAT_TEXTVIEWCLASS(c) G_TYPE_CHECK_CLASS_CAST(c\ 32 | , qq_chat_textview_get_type()\ 33 | , QQChatTextviewClass) 34 | #define QQ_IS_CHAT_TEXTVIEW(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj\ 35 | , qq_chat_textview_get_type()) 36 | 37 | typedef struct __QQChatTextview QQChatTextview; 38 | typedef struct __QQChatTextviewClass QQChatTextviewClass; 39 | 40 | struct __QQChatTextview{ 41 | GtkTextView parent; 42 | }; 43 | 44 | struct __QQChatTextviewClass{ 45 | GtkTextViewClass parent; 46 | }; 47 | 48 | GtkWidget* qq_chat_textview_new(); 49 | GType qq_chat_textview_get_type(); 50 | 51 | // 52 | // Clear the view 53 | // 54 | void qq_chat_textview_clear(GtkWidget *widget); 55 | 56 | // 57 | // Add messages 58 | // 59 | void qq_chat_textview_add_recv_message(GtkWidget *widget, QQRecvMsg *msg); 60 | void qq_chat_textview_add_send_message(GtkWidget *widget, QQSendMsg *msg); 61 | 62 | // 63 | // Add face or string 64 | // 65 | void qq_chat_textview_add_face(GtkWidget *widget, gint face); 66 | void qq_chat_textview_add_string(GtkWidget *widget, const gchar *str, gint len); 67 | 68 | // 69 | // Set font 70 | // This function will create a new font tag and the new inserted string is setted 71 | // to the new font. Old strings will not change. 72 | // @param name : font name 73 | // @param color : foreground color 74 | // @param size : font size 75 | // @param a, b, c : bold? italic? underline? 76 | // 77 | void qq_chat_textview_set_font(GtkWidget *widget, const gchar *name 78 | , const gchar *color 79 | , gint size 80 | , gint a, gint b, gint c); 81 | 82 | // 83 | // Set the default font the the text view widget 84 | // 85 | void qq_chat_textview_set_default_font(GtkWidget *widget, const gchar *name 86 | , const gchar *color 87 | , gint size 88 | , gint a, gint b, gint c); 89 | 90 | // 91 | // Get the QQMsgContent of the text view. 92 | // Save them in the contents. 93 | // Return the number of the contents 94 | // 95 | gint qq_chat_textview_get_msg_contents(GtkWidget *widget, GPtrArray *contents); 96 | #endif 97 | -------------------------------------------------------------------------------- /src/gui/chatwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_CHATWIDGET_H 2 | #define __GTKQQ_CHATWIDGET_H 3 | #include 4 | #include 5 | 6 | // 7 | // Chat widget 8 | // Contians: 9 | // message text view, font tool bar, tool bar 10 | // Both the buddy chat window and the group chat window use this widget. 11 | // 12 | // ---------------------------------------------- 13 | // | | 14 | // | | 15 | // | message text view | <-- message text view 16 | // | | 17 | // | | 18 | // ---------------------------------------------- 19 | // | font|v| size|v| |a| |a| |a| |clor| | <-- font tool bar (may hide) 20 | // ---------------------------------------------- 21 | // | |font| |face| ....... |clrscr| | <-- tool bar 22 | // ---------------------------------------------- 23 | // | | 24 | // | input text view | <-- input text view 25 | // | | 26 | // ---------------------------------------------- 27 | // 28 | #define QQ_CHATWIDGET(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, qq_chatwidget_get_type()\ 29 | , QQChatWidget) 30 | #define QQ_CHATWIDGETCLASS(c) G_TYPE_CHECK_CLASS_CAST(c\ 31 | , qq_chatwidget_get_type()\ 32 | , QQChatWidgetClass) 33 | #define QQ_IS_CHATWIDGET(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, qq_chatwidget_get_type()) 34 | 35 | typedef struct __QQChatWidget QQChatWidget; 36 | typedef struct __QQChatWidgetClass QQChatWidgetClass; 37 | 38 | struct __QQChatWidget{ 39 | GtkVBox parent; 40 | 41 | }; 42 | 43 | struct __QQChatWidgetClass{ 44 | GtkVBoxClass parent; 45 | }; 46 | 47 | GtkWidget* qq_chatwidget_new(); 48 | GType qq_chatwidget_get_type(); 49 | 50 | // 51 | // Add messages 52 | // 53 | void qq_chatwidget_add_recv_message(GtkWidget *widget, QQRecvMsg *msg); 54 | void qq_chatwidget_add_send_message(GtkWidget *widget, QQSendMsg *msg); 55 | 56 | // 57 | // Get the text view 58 | // 59 | GtkWidget* qq_chatwidget_get_message_textview(GtkWidget *widget); 60 | GtkWidget* qq_chatwidget_get_input_textview(GtkWidget *widget); 61 | 62 | // 63 | // Get the font of font tool bar 64 | // 65 | QQMsgContent* qq_chatwidget_get_font(GtkWidget *widget); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/gui/chatwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_CHATWINDOW_H 2 | #define __GTKQQ_CHATWINDOW_H 3 | #include 4 | #include 5 | 6 | #define QQ_CHATWINDOW(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, qq_chatwindow_get_type()\ 7 | , QQChatWindow) 8 | #define QQ_CHATWINDOWCLASS(c) G_TYPE_CHECK_CLASS_CAST(c\ 9 | , qq_chatwindow_get_type()\ 10 | , QQChatWindowClass) 11 | #define QQ_IS_CHATWINDOW(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, qq_chatwindow_get_type()) 12 | 13 | typedef struct __QQChatWindow QQChatWindow; 14 | typedef struct __QQChatWindowClass QQChatWindowClass; 15 | 16 | struct __QQChatWindow{ 17 | GtkWindow parent; 18 | 19 | }; 20 | 21 | struct __QQChatWindowClass{ 22 | GtkWindowClass parent; 23 | }; 24 | 25 | GtkWidget* qq_chatwindow_new(const gchar *uin); 26 | GType qq_chatwindow_get_type(); 27 | 28 | // 29 | // Add messages 30 | // 31 | void qq_chatwindow_add_recv_message(GtkWidget *widget, QQRecvMsg *msg); 32 | void qq_chatwindow_add_send_message(GtkWidget *widget, QQSendMsg *msg); 33 | #endif 34 | -------------------------------------------------------------------------------- /src/gui/dao.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_DAO_H 2 | #define __GTKQQ_DAO_H 3 | #include 4 | #include 5 | #include 6 | 7 | // 8 | // The DAO 9 | // Manage the connection to the database. 10 | // 11 | 12 | // 13 | // Open a connection to the databases. 14 | // 15 | // If databases not exist, create it. 16 | // The tables will also be created too. 17 | // 18 | sqlite3* db_open(); 19 | 20 | // 21 | // Close the connection to the databases. 22 | // 23 | void db_close(sqlite3 *db); 24 | 25 | // 26 | // Set the all the row's value of col to value. 27 | // 28 | gint db_update_all(sqlite3 *db, const gchar *table 29 | , const gchar *col, const gchar *value); 30 | // 31 | // Get all the users in qquser 32 | // The result array must be free when no use. 33 | // 34 | gint db_get_all_users(sqlite3 *db, GPtrArray **result); 35 | // 36 | // Delete all the data in all tables. 37 | // NOT delete the tables. 38 | // 39 | gint db_clear_db(sqlite3 *db); 40 | // 41 | // Delete all the data in table where key = value 42 | // 43 | gint db_clear_table(sqlite3 *db, const gchar *table 44 | , const gchar *key, const gchar *value); 45 | 46 | // 47 | // Store qq user into db 48 | // 49 | gint db_qquser_save(sqlite3 *db, const gchar *qqnum, const gchar *passwd 50 | , const gchar *status, gint last, gint rempw, gint mute); 51 | 52 | // 53 | // Store key:value into db 54 | // Use g_free to free the value after using it. 55 | // 56 | gint db_config_save(sqlite3 *db, const gchar *owner 57 | , const gchar *key, const gchar *value); 58 | 59 | // 60 | // Store buddy, group into db 61 | // 62 | 63 | // Just create the sql statement 64 | void db_buddy_save_sql_append(GString *sql, const gchar *owner, QQBuddy *bdy); 65 | gint db_buddy_save(sqlite3 *db, const gchar *owner, QQBuddy *bdy); 66 | 67 | // Just create the sql statement 68 | void db_group_save_sql_append(GString *sql, const gchar *owner, QQGroup *grp); 69 | gint db_group_save(sqlite3 *db, const gchar *owner, QQGroup *grp); 70 | 71 | // 72 | // Get key:value 73 | // 74 | gint db_config_get(sqlite3 *db, const gchar *owner 75 | , const gchar *key, gchar **value); 76 | // 77 | // Get the buddy and group. 78 | // @param cnt : the number of the recoders found in the db 79 | // 80 | gint db_get_buddy(sqlite3 *db, const gchar *owner, QQBuddy *bdy, gint *cnt); 81 | gint db_get_group(sqlite3 *db, const gchar *owner, QQGroup *grp, gint *cnt); 82 | 83 | // 84 | // Execute the sql 85 | // 86 | gint db_exec_sql(sqlite3 *db, const gchar *sql); 87 | 88 | /** 89 | * Update qq user's config 90 | * 91 | * @param db 92 | * @param qqnumber User's qq number 93 | * @param col 94 | * @param value 95 | * 96 | * @return 97 | */ 98 | gint db_update_user(sqlite3 *db, const gchar *qqnumber, const gchar *col, const gchar *value); 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /src/gui/facepopupwindow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern QQInfo *info; 5 | extern GQQConfig *cfg; 6 | 7 | static void qq_face_popup_window_init(QQFacePopupWindow *win); 8 | static void qq_face_popup_windowclass_init(QQFacePopupWindowClass *klass); 9 | 10 | static gint face_transfer_table[] = {14, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 11 | , 12, 13, 0, 50, 51, 96, 53, 54, 73 12 | , 74, 75, 76, 77, 78, 55, 56, 57, 58 13 | , 79, 80, 81, 82, 83, 84, 85, 86, 87 14 | , 88, 97, 98, 99, 100, 101, 102, 103 15 | , 104, 105, 106, 107, 108, 109, 110, 111 16 | , 112, 32, 113, 114, 115, 63, 64, 59, 33 17 | , 34, 116, 36, 37, 38, 91, 92, 93, 29, 117 18 | , 72, 45, 42, 39, 62, 46, 47, 71, 95, 118 19 | , 119, 120, 121, 122, 123, 124, 27, 21, 23 20 | , 25, 26, 125, 126, 127, 128, 129, 130 21 | , 131, 132, 133, 134, 52, 24, 22, 20, 60 22 | , 61, 89, 90, 31, 94, 65, 35, 66, 67, 68 23 | , 69, 70, 15, 16, 17, 18, 19, 28, 30, 40 24 | , 41, 43, 44, 48, 49}; 25 | typedef struct{ 26 | }QQFacePopupWindowPriv; 27 | 28 | GType qq_face_popup_window_get_type() 29 | { 30 | static GType t = 0; 31 | if(!t){ 32 | const GTypeInfo info = 33 | { 34 | sizeof(QQFacePopupWindowClass), 35 | NULL, /* base_init */ 36 | NULL, /* base_finalize */ 37 | (GClassInitFunc)qq_face_popup_windowclass_init, 38 | NULL, /* class finalize*/ 39 | NULL, /* class data */ 40 | sizeof(QQFacePopupWindow), 41 | 0, /* n pre allocs */ 42 | (GInstanceInitFunc)qq_face_popup_window_init, 43 | 0 44 | }; 45 | 46 | t = g_type_register_static(GTK_TYPE_WINDOW, "QQFacePopupWindow" 47 | , &info, 0); 48 | } 49 | return t; 50 | } 51 | 52 | GtkWidget* qq_face_popup_window_new() 53 | { 54 | return GTK_WIDGET(g_object_new(qq_face_popup_window_get_type() 55 | , "type", GTK_WINDOW_TOPLEVEL, NULL)); 56 | } 57 | // 58 | // Focus out event handler 59 | // 60 | static gboolean qq_face_popup_window_focus_out(GtkWidget *widget 61 | , GdkEvent* event 62 | , gpointer data) 63 | { 64 | gtk_widget_hide(GTK_WIDGET(data)); 65 | return TRUE; 66 | } 67 | 68 | // 69 | // Face clicked event handler parameter 70 | // 71 | struct FaceClickedPar 72 | { 73 | gint face; 74 | GtkWidget *win; 75 | }; 76 | 77 | // 78 | // Face clicked event handler 79 | // 80 | static gboolean face_popup_window_clicked(GtkWidget *widget 81 | , GdkEvent *event 82 | , gpointer data) 83 | { 84 | struct FaceClickedPar *par = data; 85 | g_debug("Clicked face %d.gif (%s, %d)", par -> face, __FILE__, __LINE__); 86 | g_signal_emit_by_name(par -> win, "face-clicked", par -> face); 87 | gtk_widget_hide(par -> win); 88 | return FALSE; 89 | } 90 | 91 | static gboolean face_enter_notify_event(GtkWidget *widget 92 | , GdkEvent *event 93 | , gpointer data) 94 | { 95 | GtkFrame *frame = data; 96 | gtk_frame_set_shadow_type(frame, GTK_SHADOW_OUT); 97 | GdkWindow *gdkwin = gtk_widget_get_window(widget); 98 | gdk_window_set_cursor(gdkwin, gdk_cursor_new(GDK_HAND1)); 99 | return FALSE; 100 | } 101 | static gboolean face_leave_notify_event(GtkWidget *widget 102 | , GdkEvent *event 103 | , gpointer data) 104 | { 105 | GtkFrame *frame = data; 106 | gtk_frame_set_shadow_type(frame, GTK_SHADOW_ETCHED_IN); 107 | GdkWindow *gdkwin = gtk_widget_get_window(widget); 108 | gdk_window_set_cursor(gdkwin, NULL); 109 | return FALSE; 110 | } 111 | static void qq_face_popup_window_init(QQFacePopupWindow *win) 112 | { 113 | gtk_window_set_decorated(GTK_WINDOW(win) , FALSE); 114 | gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DIALOG); 115 | gtk_window_set_default_size(GTK_WINDOW(win) , 450 , 250); 116 | gtk_window_set_skip_taskbar_hint(GTK_WINDOW(win), TRUE); 117 | 118 | g_signal_connect(win, "focus-out-event" 119 | , G_CALLBACK(qq_face_popup_window_focus_out), win); 120 | 121 | GtkWidget *table, *img, *eventbox, *frame; 122 | gint i, j, k; 123 | table = gtk_table_new(7, 15, TRUE); 124 | gchar path[500]; 125 | struct FaceClickedPar *par; 126 | 127 | k = 0; 128 | for(i = 0; i < 7; ++i){ 129 | for(j = 0; j < 15; ++j){ 130 | g_snprintf(path, 500, IMGDIR"/qqfaces/%d.gif", k); 131 | img = gtk_image_new_from_file(path); 132 | eventbox = gtk_event_box_new(); 133 | gtk_widget_set_events(eventbox, GDK_ALL_EVENTS_MASK); 134 | gtk_container_add(GTK_CONTAINER(eventbox), img); 135 | par = g_slice_new0(struct FaceClickedPar); 136 | par -> face = face_transfer_table[k]; 137 | par -> win = GTK_WIDGET(win); 138 | ++k; 139 | g_signal_connect(eventbox , "button-release-event" 140 | , G_CALLBACK(face_popup_window_clicked) 141 | , par); 142 | frame = gtk_frame_new(NULL); 143 | gtk_container_add(GTK_CONTAINER(frame), eventbox); 144 | g_signal_connect(eventbox , "enter-notify-event" 145 | , G_CALLBACK(face_enter_notify_event) 146 | , frame); 147 | g_signal_connect(eventbox , "leave-notify-event" 148 | , G_CALLBACK(face_leave_notify_event) 149 | , frame); 150 | gtk_table_attach_defaults(GTK_TABLE(table), frame 151 | , j, j + 1, i, i + 1); 152 | } 153 | } 154 | 155 | frame = gtk_frame_new(NULL); 156 | gtk_container_add(GTK_CONTAINER(frame) , table); 157 | gtk_container_add(GTK_CONTAINER(win) , frame); 158 | } 159 | 160 | // 161 | // Default signal handler 162 | // 163 | static void default_handler(gpointer instance, gint face 164 | , gpointer usr_data) 165 | { 166 | //do nothing. 167 | return; 168 | } 169 | static void qq_face_popup_windowclass_init(QQFacePopupWindowClass *klass) 170 | { 171 | //install the 'face-clicked' signal 172 | klass -> face_clicked_default_handler = default_handler; 173 | //void signal_handler(gpointer instance, gint face, gpointer data) 174 | klass -> face_clicked_signal_id = 175 | g_signal_new("face-clicked" 176 | , G_TYPE_FROM_CLASS(klass) 177 | , G_SIGNAL_RUN_LAST //run after the default handler 178 | , G_STRUCT_OFFSET(QQFacePopupWindowClass 179 | , face_clicked_default_handler) 180 | , NULL, NULL //no used 181 | , g_cclosure_marshal_VOID__INT 182 | , G_TYPE_NONE 183 | , 1, G_TYPE_INT); 184 | } 185 | 186 | void qq_face_popup_window_popup(GtkWidget *win, gint x, gint y) 187 | { 188 | gtk_window_move(GTK_WINDOW(win), x - 30, y - 280); 189 | gtk_widget_show_all(GTK_WIDGET(win)); 190 | } 191 | -------------------------------------------------------------------------------- /src/gui/facepopupwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef __QQ_FACE_POPUP_WINDOW_H_ 2 | #define __QQ_FACE_POPUP_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define QQ_TYPE_FACE_POPUP_WINDOW qq_face_popup_window_get_type() 8 | #define QQ_FACE_POPUP_WINDOW(obj) G_TYPE_CHECK_INSTANCE_CAST(obj\ 9 | , QQ_TYPE_FACE_POPUP_WINDOW\ 10 | , QQFacePopupWindow) 11 | #define QQ_FACE_POPUP_WINDOWCLASS(c) G_TYPE_CHECK_CLASS_CAST(c\ 12 | , QQ_TYPE_FACE_POPUP_WINDOW\ 13 | , QQFacePopupWindowClass) 14 | #define QQ_IS_FACE_POPUP_WINDOW(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj\ 15 | , QQ_TYPE_FACE_POPUP_WINDOW) 16 | 17 | typedef struct __QQFacePopupWindow QQFacePopupWindow; 18 | typedef struct __QQFacePopupWindowClass QQFacePopupWindowClass; 19 | 20 | struct __QQFacePopupWindow{ 21 | GtkTextView parent; 22 | }; 23 | 24 | struct __QQFacePopupWindowClass{ 25 | GtkTextViewClass parent; 26 | 27 | void (*face_clicked_default_handler)(gpointer instance 28 | , gint face 29 | , gpointer usrdata); 30 | guint face_clicked_signal_id; 31 | }; 32 | 33 | GtkWidget* qq_face_popup_window_new(); 34 | GType qq_face_popup_window_get_type(); 35 | 36 | void qq_face_popup_window_popup(GtkWidget *win, gint x, gint y); 37 | #endif 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/gui/gqqconfig.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_CONFIG_H 2 | #define __GTKQQ_CONFIG_H 3 | #include 4 | #include 5 | #include 6 | 7 | // 8 | // Configuration 9 | // The configuration directory is $HOME/.gtkqq. 10 | // See doc/table.sql for details 11 | // 12 | 13 | typedef struct __GQQLoginUser{ 14 | gchar qqnumber[100]; 15 | gchar passwd[100]; 16 | gchar status[100]; 17 | gint last; 18 | gint rempw; 19 | gint mute; 20 | }GQQLoginUser; 21 | 22 | #define GQQ_TYPE_CONFIG (gqq_config_get_type()) 23 | #define GQQ_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj)\ 24 | , GQQ_TYPE_CONFIG\ 25 | , GQQConfig)) 26 | #define GQQ_IS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj\ 27 | , GQQ_TYPE_CONFIG))) 28 | #define GQQ_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass)\ 29 | , GQQ_TYPE_CONFIG\ 30 | , GQQConfigClass)) 31 | #define GQQ_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass)\ 32 | , GQQ_TYPE_CONFIG)) 33 | #define GQQ_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj)\ 34 | , GQQ_TYPE_CONFIG\ 35 | , GQQConfigClass)) 36 | 37 | typedef struct __GQQConfig GQQConfig; 38 | typedef struct __GQQConfigClass GQQConfigClass; 39 | 40 | struct __GQQConfig{ 41 | GObject parent_instance; 42 | }; 43 | 44 | struct __GQQConfigClass{ 45 | GObjectClass parent_class; 46 | 47 | guint changed_signal_id; 48 | // 49 | // The default handler for 'gtkqq-config-changed' signal. 50 | // 51 | void (*signal_default_handler)(gpointer instance 52 | , const gchar *key 53 | , const GVariant *value 54 | , gpointer usr_data); 55 | }; 56 | 57 | GQQConfig* gqq_config_new(QQInfo *info); 58 | GType gqq_config_get_type(); 59 | // 60 | // Load the configuration of qq number 61 | // 62 | gint gqq_config_load(GQQConfig *cfg, const gchar *qqnum); 63 | // 64 | // Save all the configuration items 65 | // 66 | gint gqq_config_save(GQQConfig *cfg); 67 | 68 | // 69 | // Get all the users who has logined. 70 | // 71 | GPtrArray* gqq_config_get_all_login_user(GQQConfig *cfg); 72 | // 73 | // Save the last login user 74 | // 75 | gint gqq_config_save_last_login_user(GQQConfig *cfg); 76 | 77 | // 78 | // Get and set configurations. 79 | // For getter, if no key found, return -1, else return 0. 80 | // 81 | 82 | // Do NOT free *value! 83 | gint gqq_config_get_str(GQQConfig *cfg, const gchar *key, const gchar **value); 84 | gint gqq_config_get_int(GQQConfig *cfg, const gchar *key, gint *value); 85 | gint gqq_config_get_bool(GQQConfig *cfg, const gchar *key, gboolean *value); 86 | // 87 | // If successed, return 0. If failed, return -1. 88 | // If the key already exists, set the value to the new value. 89 | // 90 | gint gqq_config_set_str(GQQConfig *cfg, const gchar *key, const gchar *value); 91 | gint gqq_config_set_int(GQQConfig *cfg, const gchar *key, gint value); 92 | gint gqq_config_set_bool(GQQConfig *cfg, const gchar *key, gboolean value); 93 | 94 | // 95 | // Save buddy and group into db 96 | // @return 0 for success of -1 for failed 97 | // 98 | gint gqq_config_save_buddy(GQQConfig *cfg, QQBuddy *bdy); 99 | gint gqq_config_save_group(GQQConfig *cfg, QQGroup *grp); 100 | 101 | // 102 | // Get buddy and group from the db 103 | // @return 0 : success but find no recoder 104 | // > 0 : the recoders which are found. Set the LAST one to bdy 105 | // < 0 : failed 106 | // 107 | gint gqq_config_get_buddy(GQQConfig *cfg, QQBuddy *bdy); 108 | gint gqq_config_get_group(GQQConfig *cfg, QQGroup *grp); 109 | 110 | // 111 | // The string key hash table. 112 | // NOTE: 113 | // These functions are thread-safe. 114 | // 115 | 116 | // 117 | // Create a hash table named `name`. 118 | // 119 | GHashTable* gqq_config_create_str_hash_table(GQQConfig *cfg, const gchar *name); 120 | 121 | // Delete the hash table named `name` 122 | gint gqq_config_delete_ht_ht(GQQConfig *cfg, const gchar *name); 123 | // 124 | // Operate the hash table named `name` 125 | // 126 | gpointer gqq_config_lookup_ht(GQQConfig *cfg, const gchar *name 127 | , const gchar *key); 128 | gpointer gqq_config_remove_ht(GQQConfig *cfg, const gchar *name 129 | , const gchar *key); 130 | gint gqq_config_clear_ht(GQQConfig *cfg, const gchar *name); 131 | gint gqq_config_insert_ht(GQQConfig *cfg, const gchar *name 132 | , gchar *key 133 | , gpointer value); 134 | 135 | /** 136 | * Get user's config directory. 137 | * 138 | * 139 | * @return 140 | */ 141 | gchar *gqq_config_get_cfgdir(); 142 | #define QQ_CFGDIR gqq_config_get_cfgdir() 143 | 144 | /** 145 | * Get user' face directory. 146 | * 147 | * 148 | * @return 149 | */ 150 | gchar *gqq_config_get_facedir(); 151 | #define QQ_FACEDIR gqq_config_get_facedir() 152 | 153 | /** 154 | * Whether mute. 155 | * 156 | * @param cfg 157 | * 158 | * @return TRUE if mute, else FALSE. 159 | */ 160 | gint gqq_config_is_mute(GQQConfig *cfg); 161 | 162 | /** 163 | * Set the mute status. 164 | * 165 | * @param cfg 166 | * @param mute 167 | */ 168 | void gqq_config_set_mute(GQQConfig *cfg, gint mute); 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /src/gui/groupchatwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_GROUP_CHATWINDOW_H 2 | #define __GTKQQ_GROUP_CHATWINDOW_H 3 | #include 4 | #include 5 | 6 | #define QQ_TYPE_GROUP_CHATWINDOW qq_group_chatwindow_get_type() 7 | #define QQ_GROUP_CHATWINDOW(obj) G_TYPE_CHECK_INSTANCE_CAST(obj\ 8 | , QQ_TYPE_GROUP_CHATWINDOW\ 9 | , QQGroupChatWindow) 10 | #define QQ_GROUP_CHATWINDOWCLASS(c) G_TYPE_CHECK_CLASS_CAST(c\ 11 | , QQ_TYPE_GROUP_CHATWINDOW()\ 12 | , QQGroupChatWindowClass) 13 | #define QQ_IS_GROUP_CHATWINDOW(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj\ 14 | , QQ_TYPE_GROUP_CHATWINDOW()) 15 | 16 | typedef struct __QQGroupChatWindow QQGroupChatWindow; 17 | typedef struct __QQGroupChatWindowClass QQGroupChatWindowClass; 18 | 19 | struct __QQGroupChatWindow{ 20 | GtkWindow parent; 21 | 22 | }; 23 | 24 | struct __QQGroupChatWindowClass{ 25 | GtkWindowClass parent; 26 | }; 27 | 28 | GtkWidget* qq_group_chatwindow_new(const gchar *code); 29 | GType qq_group_chatwindow_get_type(); 30 | 31 | // 32 | // Add messages 33 | // 34 | void qq_group_chatwindow_add_recv_message(GtkWidget *widget, QQRecvMsg *msg); 35 | void qq_group_chatwindow_add_send_message(GtkWidget *widget, QQSendMsg *msg); 36 | #endif 37 | -------------------------------------------------------------------------------- /src/gui/loginpanel.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_LOGINWIN_H 2 | #define __GTKQQ_LOGINWIN_H 3 | #include 4 | 5 | #define QQ_LOGINPANEL(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, qq_loginpanel_get_type()\ 6 | , QQLoginPanel) 7 | #define QQ_LOGINPANEL_CLASS(c) G_TYPE_CHECK_CLASS_CAST(c\ 8 | , qq_loginpanel_get_type()\ 9 | , QQLoginPanelClass) 10 | #define QQ_IS_LOGINPANEL(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, qq_loginpanel_get_type()) 11 | 12 | typedef struct _QQLoginPanel QQLoginPanel; 13 | typedef struct _QQLoginPanelClass QQLoginPanelClass; 14 | typedef enum _QQLoginPanelLoginState QQLoginPanelLoginState; 15 | 16 | //the login status 17 | enum _QQLoginPanelLoginState{ 18 | LS_CHECK_VC, //check verify code 19 | LS_LOGIN, //login, get psessionid 20 | LS_GET_MY_INFO, //get information of myself 21 | LS_GET_FRIENDS, //get my friends list. 22 | LS_GET_GROUP_LIST, //get group list. 23 | LS_ONLINE, //get online buddies 24 | LS_RECENT, //get recent connected buddies 25 | LS_SLNICK, //get single long nick 26 | LS_GET_FACEIMG, //get face image 27 | LS_DONE, //finish the login. 28 | LS_ERROR, //error 29 | LS_UNKNOWN //unknown status 30 | }; 31 | 32 | struct _QQLoginPanel{ 33 | GtkVBox parent; 34 | 35 | /*< private >*/ 36 | GtkWidget *uin_label, *uin_entry; 37 | GtkWidget *passwd_label, *passwd_entry; 38 | GtkWidget *rempwcb; //rember password check button 39 | GtkWidget *err_label; //show error infomation. 40 | GtkWidget *login_btn, *status_comb; 41 | #ifdef USE_PROXY 42 | GtkWidget *set_proxy_btn; 43 | #endif /* USE_PROXY */ 44 | 45 | const gchar *uin, *passwd, *status; 46 | gint rempw; 47 | 48 | GtkWidget *container; 49 | 50 | //used to mark the login state. 51 | QQLoginPanelLoginState login_state; 52 | }; 53 | 54 | struct _QQLoginPanelClass{ 55 | GtkVBoxClass parent; 56 | }; 57 | 58 | /* 59 | * Create a new instance of QQLoginPanel. 60 | * 61 | * @param container the container which contains this instance. Can be 62 | * set to NULL. 63 | */ 64 | GtkWidget* qq_loginpanel_new(GtkWidget *container); 65 | GType qq_loginpanel_get_type(); 66 | 67 | /* 68 | * Get the inputs 69 | */ 70 | const gchar* qq_loginpanel_get_uin(QQLoginPanel *loginpanel); 71 | const gchar* qq_loginpanel_get_passwd(QQLoginPanel *loginpanel); 72 | const gchar* qq_loginpanel_get_status(QQLoginPanel *loginpanel); 73 | gint qq_loginpanel_get_rempw(QQLoginPanel *loginpanel); 74 | #endif 75 | -------------------------------------------------------------------------------- /src/gui/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef USE_GSTREAMER 15 | #include 16 | #endif //USE_GSTREAMER 17 | 18 | /* 19 | * Global 20 | */ 21 | QQInfo *info = NULL; 22 | GQQConfig *cfg = NULL; 23 | QQTray *tray = NULL; 24 | GtkWidget *main_win = NULL; 25 | 26 | // 27 | // The main loop used to get information from the server. 28 | // Such as face images, buddy information. 29 | // 30 | GQQMessageLoop *get_info_loop = NULL; 31 | // 32 | // The main loop used to get qq number and face images from the server. 33 | // Such as face images, buddy information. 34 | // 35 | GQQMessageLoop *get_number_faceimg_loop = NULL; 36 | // 37 | // The main loop used to send messages. 38 | // Such as group messages and buddy messages. 39 | // 40 | GQQMessageLoop *send_loop = NULL; 41 | 42 | int main(int argc, char **argv) 43 | { 44 | #ifdef USE_GSTREAMER 45 | gst_init(&argc , &argv); 46 | #endif 47 | gtk_init(&argc, &argv); 48 | 49 | log_init(); 50 | info = qq_init(NULL); 51 | if(info == NULL){ 52 | return -1; 53 | } 54 | cfg = gqq_config_new(info); 55 | 56 | send_loop = gqq_msgloop_start("Send"); 57 | if(send_loop == NULL){ 58 | return -1; 59 | } 60 | get_info_loop = gqq_msgloop_start("Get informain"); 61 | if(get_info_loop == NULL){ 62 | return -1; 63 | } 64 | get_number_faceimg_loop = gqq_msgloop_start("Get Number and face images"); 65 | if(get_number_faceimg_loop == NULL){ 66 | return -1; 67 | } 68 | 69 | /* GtkWidget *win = qq_mainwindow_new(); */ 70 | main_win = qq_mainwindow_new(); 71 | tray = qq_tray_new(); 72 | gtk_widget_show_all(main_win); 73 | 74 | gtk_main(); 75 | 76 | g_object_unref(G_OBJECT(tray)); 77 | 78 | qq_logout(info, NULL); 79 | gqq_msgloop_stop(get_info_loop); 80 | gqq_msgloop_stop(send_loop); 81 | 82 | //Save config 83 | gqq_config_save(cfg); 84 | qq_finalize(info, NULL); 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /src/gui/mainpanel.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_MAINPANEL_H 2 | #define __GTKQQ_MAINPANEL_H 3 | #include 4 | 5 | #define QQ_MAINPANEL(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, qq_mainpanel_get_type()\ 6 | , QQMainPanel) 7 | #define QQ_MAINPANELCLASS(c) G_TYPE_CHECK_CLASS_CAST(c\ 8 | , qq_mainpanel_get_type()\ 9 | , QQMainPanelClass) 10 | #define QQ_IS_MAINPANEL(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, qq_mainpanel_get_type()) 11 | 12 | typedef struct _QQMainPanel QQMainPanel; 13 | typedef struct _QQMainPanelClass QQMainPanelClass; 14 | 15 | struct _QQMainPanel{ 16 | GtkVBox parent; 17 | 18 | /*< private >*/ 19 | GtkWidget *faceimgframe; //a frame contains gtk image 20 | GtkWidget *faceeventbox; 21 | GdkPixbuf *facepixbuf; 22 | 23 | GtkWidget *status_btn; 24 | GtkWidget *nick; 25 | 26 | GtkWidget *longnick, *longnick_entry; 27 | GtkWidget *longnick_box, *longnick_eventbox; 28 | 29 | GtkWidget *search_entry; 30 | 31 | GtkWidget *buddy_btn, *grp_btn, *recent_btn; 32 | 33 | GtkWidget *notebook; 34 | GtkWidget *buddy_tree; 35 | GtkWidget *group_list; 36 | GtkWidget *recent_list; 37 | 38 | GtkWidget *menubar; 39 | 40 | GtkWidget *container; 41 | }; 42 | 43 | struct _QQMainPanelClass{ 44 | GtkVBoxClass parent; 45 | 46 | /*< private >*/ 47 | GtkWidget *buddy_img[2]; 48 | GtkWidget *grp_img[2]; 49 | GtkWidget *recent_img[2]; 50 | 51 | GdkCursor *hand; 52 | }; 53 | 54 | GType qq_mainpanel_get_type(); 55 | GtkWidget* qq_mainpanel_new(GtkWidget *container); 56 | 57 | // 58 | //Update the information of the panel. 59 | //NOTE: 60 | // This function will create a new model for the tree. 61 | // 62 | void qq_mainpanel_update(QQMainPanel *panel); 63 | // 64 | // Update my information 65 | // 66 | void qq_mainpanel_update_my_info(QQMainPanel *panel); 67 | // 68 | // Update the buddy info 69 | // 70 | void qq_mainpanel_update_buddy_info(QQMainPanel *panel); 71 | void qq_mainpanel_update_buddy_faceimg(QQMainPanel *panel); 72 | void qq_mainpanel_update_online_buddies(QQMainPanel *panel); 73 | 74 | void qq_mainpanel_update_group_info(QQMainPanel *panel); 75 | #endif 76 | -------------------------------------------------------------------------------- /src/gui/mainwindow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* 10 | * The main event loop context of Gtk. 11 | */ 12 | extern QQInfo *info; 13 | extern GQQConfig *cfg; 14 | extern GtkWidget *main_win; 15 | 16 | static void qq_mainwindow_init(QQMainWindow *win); 17 | static void qq_mainwindowclass_init(QQMainWindowClass *wc); 18 | 19 | /* 20 | * The handler of "destroy" singal 21 | */ 22 | #if 0 23 | static void destroy_handler(GtkWidget *widget, gpointer data) 24 | { 25 | gtk_main_quit(); 26 | g_debug("Destroy window.(%s, %d)", __FILE__, __LINE__); 27 | return; 28 | } 29 | #endif 30 | 31 | gboolean 32 | qq_mainwindow_close(GtkWidget *widget) 33 | { 34 | qq_mainwindow_hide(widget); 35 | 36 | return TRUE; 37 | } 38 | 39 | GType qq_mainwindow_get_type() 40 | { 41 | static GType t = 0; 42 | if(!t){ 43 | const GTypeInfo info = 44 | { 45 | sizeof(QQMainWindowClass), 46 | NULL, /* base_init */ 47 | NULL, /* base_finalize */ 48 | (GClassInitFunc)qq_mainwindowclass_init, 49 | NULL, /* class finalize*/ 50 | NULL, /* class data */ 51 | sizeof(QQMainWindow), 52 | 0, /* n pre allocs */ 53 | (GInstanceInitFunc)qq_mainwindow_init, 54 | 0 55 | }; 56 | 57 | t = g_type_register_static(GTK_TYPE_WINDOW, "QQMainWindow" 58 | , &info, 0); 59 | } 60 | return t; 61 | } 62 | 63 | /* Show the main window. */ 64 | void qq_mainwindow_show(GtkWidget *win) 65 | { 66 | QQMainWindow *mainwin = (QQMainWindow *)win; 67 | 68 | mainwin->showed = TRUE; 69 | gtk_widget_show(win); 70 | } 71 | 72 | /* Hide the main window */ 73 | void qq_mainwindow_hide(GtkWidget *win) 74 | { 75 | QQMainWindow *mainwin = (QQMainWindow *)win; 76 | 77 | mainwin->showed = FALSE; 78 | gtk_widget_hide(win); 79 | } 80 | 81 | /* If the window now is shown, hide it, 82 | else show it. */ 83 | void qq_mainwindow_show_hide(GtkWidget *win) 84 | { 85 | QQMainWindow *mainwin = (QQMainWindow *)win; 86 | 87 | if (TRUE == mainwin->showed) { 88 | qq_mainwindow_hide(win); 89 | } else { 90 | qq_mainwindow_show(win); 91 | } 92 | } 93 | 94 | GtkWidget* qq_mainwindow_new() 95 | { 96 | return GTK_WIDGET(g_object_new(qq_mainwindow_get_type() 97 | , "type", GTK_WINDOW_TOPLEVEL, NULL)); 98 | } 99 | 100 | 101 | static void qq_mainwindow_init(QQMainWindow *win) 102 | { 103 | GtkWidget *w = GTK_WIDGET(win); 104 | gtk_widget_set_size_request(w, 200, 500); 105 | gtk_window_resize(GTK_WINDOW(w), 250, 550); 106 | 107 | // gtk_window_set_resizable(GTK_WINDOW(w), FALSE); 108 | g_signal_connect(w, "delete-event", 109 | G_CALLBACK(qq_mainwindow_close), NULL); 110 | win -> login_panel = qq_loginpanel_new(w); 111 | win -> splash_panel = qq_splashpanel_new(); 112 | win -> main_panel = qq_mainpanel_new(w); 113 | win -> showed = FALSE; 114 | 115 | win -> notebook = gtk_notebook_new(); 116 | gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win -> notebook), FALSE); 117 | gtk_notebook_set_show_border(GTK_NOTEBOOK(win -> notebook), FALSE); 118 | 119 | gtk_widget_show_all(win -> login_panel); 120 | gtk_widget_show_all(win -> splash_panel); 121 | gtk_widget_show_all(win -> main_panel); 122 | 123 | gtk_notebook_append_page(GTK_NOTEBOOK(win -> notebook) 124 | , win -> login_panel, NULL); 125 | gtk_notebook_append_page(GTK_NOTEBOOK(win -> notebook) 126 | , win -> splash_panel, NULL); 127 | gtk_notebook_append_page(GTK_NOTEBOOK(win -> notebook) 128 | , win -> main_panel, NULL); 129 | 130 | gtk_container_add(GTK_CONTAINER(win), win -> notebook); 131 | 132 | GdkPixbuf *pb = gdk_pixbuf_new_from_file(IMGDIR"webqq_icon.png", NULL); 133 | gtk_window_set_icon(GTK_WINDOW(win), pb); 134 | g_object_unref(pb); 135 | gtk_window_set_title(GTK_WINDOW(win), "GtkQQ"); 136 | 137 | /* 138 | * Test 139 | */ 140 | // gtk_notebook_set_current_page(GTK_NOTEBOOK(win -> notebook), 2); 141 | // qq_mainpanel_update(QQ_MAINPANEL(win -> main_panel)); 142 | 143 | } 144 | static void qq_mainwindowclass_init(QQMainWindowClass *wc) 145 | { 146 | } 147 | 148 | void qq_mainwindow_show_loginpanel(GtkWidget *win) 149 | { 150 | if(!QQ_IS_MAINWINDOW(win)){ 151 | g_warning("Not a mainwindow!!(%s, %d)", __FILE__, __LINE__); 152 | return; 153 | } 154 | gtk_notebook_set_current_page(GTK_NOTEBOOK( 155 | QQ_MAINWINDOW(win) -> notebook), 0); 156 | } 157 | void qq_mainwindow_show_splashpanel(GtkWidget *win) 158 | { 159 | if(!QQ_IS_MAINWINDOW(win)){ 160 | g_warning("Not a mainwindow!!(%s, %d)", __FILE__, __LINE__); 161 | return; 162 | } 163 | gtk_notebook_set_current_page(GTK_NOTEBOOK( 164 | QQ_MAINWINDOW(win) -> notebook), 1); 165 | } 166 | void qq_mainwindow_show_mainpanel(GtkWidget *win) 167 | { 168 | if(!QQ_IS_MAINWINDOW(win)){ 169 | g_warning("Not a mainwindow!!(%s, %d)", __FILE__, __LINE__); 170 | return; 171 | } 172 | gtk_notebook_set_current_page(GTK_NOTEBOOK( 173 | QQ_MAINWINDOW(win) -> notebook), 2); 174 | } 175 | 176 | GtkWidget *qq_mainwindow_get_mainpanel(GtkWidget *win) 177 | { 178 | if (!win) 179 | return NULL; 180 | 181 | QQMainWindow *mainwin = (QQMainWindow *)win; 182 | 183 | return mainwin->main_panel; 184 | } 185 | -------------------------------------------------------------------------------- /src/gui/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_MAINWINDOW_H 2 | #define __GTKQQ_MAINWINDOW_H 3 | #include 4 | 5 | #define QQ_MAINWINDOW(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, qq_mainwindow_get_type()\ 6 | , QQMainWindow) 7 | #define QQ_MAINWINDOWCLASS(c) G_TYPE_CHECK_CLASS_CAST(c\ 8 | , qq_mainwindow_get_type()\ 9 | , QQMainWindowClass) 10 | #define QQ_IS_MAINWINDOW(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, qq_mainwindow_get_type()) 11 | 12 | typedef struct __QQMainWindow QQMainWindow; 13 | typedef struct __QQMainWindowClass QQMainWindowClass; 14 | 15 | struct __QQMainWindow{ 16 | GtkWindow parent; 17 | 18 | GtkWidget *notebook; 19 | 20 | GtkWidget *login_panel; 21 | GtkWidget *main_panel; 22 | GtkWidget *splash_panel; 23 | 24 | gboolean showed; 25 | }; 26 | 27 | struct __QQMainWindowClass{ 28 | GtkWindowClass parent; 29 | }; 30 | 31 | GtkWidget* qq_mainwindow_new(); 32 | GType qq_mainwindow_get_type(); 33 | 34 | /* Main window show or hide */ 35 | void qq_mainwindow_show(GtkWidget *win); 36 | void qq_mainwindow_hide(GtkWidget *win); 37 | 38 | /* If the window now is shown, hide it, 39 | else show it. */ 40 | void qq_mainwindow_show_hide(GtkWidget *win); 41 | /* 42 | * Show different panels 43 | */ 44 | void qq_mainwindow_show_loginpanel(GtkWidget *win); 45 | void qq_mainwindow_show_splashpanel(GtkWidget *win); 46 | void qq_mainwindow_show_mainpanel(GtkWidget *win); 47 | 48 | /** 49 | * Get the main panel accoss main window. 50 | * 51 | * @param win The main window. 52 | * 53 | * @return 54 | */ 55 | GtkWidget *qq_mainwindow_get_mainpanel(GtkWidget *win); 56 | #endif 57 | -------------------------------------------------------------------------------- /src/gui/msgdispacher.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // 14 | // Global 15 | // 16 | extern QQTray *tray; 17 | extern QQInfo *info; 18 | extern GQQConfig *cfg; 19 | extern GtkWidget *main_win; 20 | 21 | #ifdef USE_GSTREAMER 22 | static void qq_sound_notify(QQRecvMsg *msg) 23 | { 24 | char filename[512] = {0}; 25 | 26 | if (!msg) 27 | return ; 28 | 29 | switch (msg->msg_type) { 30 | case MSG_BUDDY_T: 31 | case MSG_GROUP_T: 32 | /* When new message is coming, play a msg audio. */ 33 | g_snprintf(filename, sizeof(filename), SOUNDDIR"/Classic/msg.wav"); 34 | break; 35 | case MSG_STATUS_CHANGED_T: 36 | if (!g_strcmp0(msg->status->str, "online")) { 37 | g_snprintf(filename, sizeof(filename), SOUNDDIR"/Classic/Global.wav"); 38 | break; 39 | } else { 40 | return; 41 | } 42 | case MSG_KICK_T: 43 | /* No implement now */ 44 | return; 45 | default: 46 | g_warning("Unknonw poll message type! %d (%s, %d)", msg->msg_type 47 | , __FILE__, __LINE__); 48 | return; 49 | } 50 | 51 | qq_play_wavfile(filename); 52 | } 53 | #endif //USE_GSTREAMER 54 | 55 | static void qq_poll_dispatch_buddy_msg(QQRecvMsg *msg) 56 | { 57 | GtkWidget *cw = gqq_config_lookup_ht(cfg, "chat_window_map" 58 | , msg -> from_uin -> str); 59 | 60 | if(cw == NULL){ 61 | cw = qq_chatwindow_new(msg -> from_uin -> str); 62 | // not show it 63 | gtk_widget_hide(cw); 64 | gqq_config_insert_ht(cfg, "chat_window_map" 65 | , msg -> from_uin -> str, cw); 66 | } 67 | qq_chatwindow_add_recv_message(cw, msg); 68 | qq_tray_blinking_for(tray, msg -> from_uin -> str); 69 | qq_recvmsg_free(msg); 70 | } 71 | 72 | static void qq_poll_dispatch_group_msg(QQRecvMsg *msg) 73 | { 74 | GtkWidget *cw = gqq_config_lookup_ht(cfg, "chat_window_map" 75 | , msg -> group_code -> str); 76 | if(cw == NULL){ 77 | cw = qq_group_chatwindow_new(msg -> group_code -> str); 78 | // not show it 79 | gtk_widget_hide(cw); 80 | gqq_config_insert_ht(cfg, "chat_window_map" 81 | , msg -> group_code -> str, cw); 82 | } 83 | qq_group_chatwindow_add_recv_message(cw, msg); 84 | qq_tray_blinking_for(tray, msg -> group_code -> str); 85 | qq_recvmsg_free(msg); 86 | 87 | } 88 | 89 | static void qq_poll_dispatch_status_changed_msg(QQRecvMsg *msg) 90 | { 91 | GtkWidget *mainpanel = NULL; 92 | const gchar *number = NULL; 93 | const gchar *status = NULL; 94 | const gchar *client_type = NULL; 95 | QQBuddy *bdy = NULL; 96 | 97 | /* Get the mainpanel object. */ 98 | mainpanel = qq_mainwindow_get_mainpanel(main_win); 99 | if (!mainpanel) 100 | return ; 101 | 102 | /* Get number whose status has changed. */ 103 | bdy = qq_info_lookup_buddy_by_uin(info, msg->uin->str); 104 | if (bdy->qqnumber->len <= 0) 105 | return ; 106 | number = bdy->qqnumber->str; 107 | 108 | status = msg->status->str; 109 | client_type = msg->client_type->str; 110 | g_debug("Buddy %s is %s (%s, %d)\n", number, status, __FILE__, __LINE__); 111 | 112 | /* Find the buddy from the buddy list to update status. */ 113 | int i = 0; 114 | for(i = 0; i < info -> buddies -> len; ++i){ 115 | bdy = (QQBuddy *)info -> buddies -> pdata[i]; 116 | if (bdy->qqnumber->len >0 && !g_strcmp0(bdy->qqnumber->str, number)) { 117 | qq_buddy_set(bdy, "status", status); 118 | qq_buddy_set(bdy, "client_type", atoi(client_type)); 119 | qq_mainpanel_update_online_buddies(QQ_MAINPANEL(mainpanel)); 120 | break; 121 | } else { 122 | continue; 123 | } 124 | } 125 | } 126 | 127 | static void qq_poll_dispatch_kick_msg(QQRecvMsg *msg) 128 | { 129 | 130 | } 131 | 132 | gint qq_poll_message_callback(QQRecvMsg *msg, gpointer data) 133 | { 134 | if(msg == NULL || data == NULL){ 135 | return 0; 136 | } 137 | 138 | GQQMessageLoop *loop = data; 139 | 140 | #ifdef USE_GSTREAMER 141 | /* Play a audio to notify that a new msg is coming if 142 | user dont set mute. */ 143 | if (!gqq_config_is_mute(cfg)) 144 | qq_sound_notify(msg); 145 | #endif // USE_GSTREAMER 146 | 147 | switch(msg -> msg_type) 148 | { 149 | case MSG_BUDDY_T: 150 | gqq_mainloop_attach(loop, qq_poll_dispatch_buddy_msg, 1, msg); 151 | break; 152 | case MSG_GROUP_T: 153 | gqq_mainloop_attach(loop, qq_poll_dispatch_group_msg, 1, msg); 154 | break; 155 | case MSG_STATUS_CHANGED_T: 156 | gqq_mainloop_attach(loop, qq_poll_dispatch_status_changed_msg, 1, msg); 157 | break; 158 | case MSG_KICK_T: 159 | gqq_mainloop_attach(loop, qq_poll_dispatch_kick_msg, 1, msg); 160 | break; 161 | default: 162 | g_warning("Unknonw poll message type! %d (%s, %d)", msg -> msg_type 163 | , __FILE__, __LINE__); 164 | break; 165 | } 166 | return 0; 167 | } 168 | -------------------------------------------------------------------------------- /src/gui/msgdispacher.h: -------------------------------------------------------------------------------- 1 | #ifndef _GTKQQ_MSG_DISPACHER_H_ 2 | #define _GTKQQ_MSG_DISPACHER_H_ 3 | #include 4 | #include 5 | 6 | // 7 | // The callback of the message poll 8 | // For every received message, this function will be called. 9 | // This function will be called out the gtk main event loop. 10 | // 11 | gint qq_poll_message_callback(QQRecvMsg *msg, gpointer data); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/gui/msgloop.c: -------------------------------------------------------------------------------- 1 | #include 2 | //The Invoker type 3 | typedef void (*Invoker)(gpointer method, gpointer *pars); 4 | 5 | // 6 | // GQQClosure 7 | // Contain all the information to invoke a method whoes 8 | // parameters are all gpointer type. 9 | // 10 | typedef struct{ 11 | Invoker invoker; 12 | gpointer method; 13 | gpointer pars[10]; // I think that no method's parameters' 14 | // number will greater ten... 15 | }GQQClosure; 16 | 17 | static gpointer thread_main(gpointer data) 18 | { 19 | gchar *name; 20 | GQQMessageLoop *ml= (GQQMessageLoop*)data; 21 | 22 | ml -> ctx = g_main_context_new(); 23 | if(ml -> ctx == NULL){ 24 | g_error("Create context for %s loop failed... (%s, %d)",ml -> name 25 | , __FILE__, __LINE__); 26 | return NULL; 27 | } 28 | GMainLoop *loop = g_main_loop_new(ml -> ctx, TRUE); 29 | if(loop == NULL){ 30 | g_error("Create %s main loop failed...(%s, %d)", ml -> name 31 | , __FILE__, __LINE__); 32 | return NULL; 33 | } 34 | ml -> loop = loop; 35 | 36 | g_debug("Start %s main loop...(%s, %d)", ml -> name, __FILE__, __LINE__); 37 | name = g_strdup(ml -> name); 38 | g_main_loop_run(ml -> loop); 39 | g_debug("%s main loop quit.(%s, %d)", name, __FILE__, __LINE__); 40 | g_free(name); 41 | return NULL; 42 | } 43 | 44 | GQQMessageLoop* gqq_msgloop_start(const gchar *name) 45 | { 46 | if(name == NULL){ 47 | name = ""; 48 | } 49 | 50 | GQQMessageLoop *ml = g_slice_new0(GQQMessageLoop); 51 | ml -> name = g_strdup(name); 52 | 53 | GError *err = NULL; 54 | if(g_thread_create(thread_main, ml, FALSE, &err) == NULL){ 55 | g_warning("Create main loop thread failed... %s (%s, %d)" 56 | , err -> message, __FILE__, __LINE__); 57 | g_error_free(err); 58 | g_free(ml -> name); 59 | g_slice_free(GQQMessageLoop, ml); 60 | return NULL; 61 | } 62 | return ml; 63 | } 64 | void gqq_msgloop_stop(GQQMessageLoop *loop) 65 | { 66 | if(loop == NULL){ 67 | return; 68 | } 69 | g_main_context_unref(loop -> ctx); 70 | g_main_loop_quit(loop -> loop); 71 | g_free(loop -> name); 72 | g_slice_free(GQQMessageLoop, loop); 73 | return; 74 | } 75 | 76 | void gqq_method_invoker_1(gpointer method, gpointer *pars) 77 | { 78 | typedef void(*MethodType1)(gpointer); 79 | MethodType1 m = (MethodType1)method; 80 | m(pars[0]); 81 | } 82 | void gqq_method_invoker_2(gpointer method, gpointer *pars) 83 | { 84 | typedef void(*MethodType1)(gpointer, gpointer); 85 | MethodType1 m = (MethodType1)method; 86 | m(pars[0], pars[1]); 87 | } 88 | void gqq_method_invoker_3(gpointer method, gpointer *pars) 89 | { 90 | typedef void(*MethodType1)(gpointer, gpointer, gpointer); 91 | MethodType1 m = (MethodType1)method; 92 | m(pars[0], pars[1], pars[2]); 93 | } 94 | void gqq_method_invoker_4(gpointer method, gpointer *pars) 95 | { 96 | typedef void(*MethodType1)(gpointer, gpointer, gpointer, gpointer); 97 | MethodType1 m = (MethodType1)method; 98 | m(pars[0], pars[1], pars[2], pars[3]); 99 | } 100 | void gqq_method_invoker_5(gpointer method, gpointer *pars) 101 | { 102 | typedef void(*MethodType1)(gpointer, gpointer, gpointer 103 | , gpointer, gpointer); 104 | MethodType1 m = (MethodType1)method; 105 | m(pars[0], pars[1], pars[2], pars[3], pars[4]); 106 | } 107 | 108 | // The table of the addresses of the invokers 109 | static Invoker invokers[] = { 110 | NULL, 111 | gqq_method_invoker_1, 112 | gqq_method_invoker_2, 113 | gqq_method_invoker_3, 114 | gqq_method_invoker_4, 115 | gqq_method_invoker_5, 116 | NULL 117 | }; 118 | 119 | // 120 | // The callback called in the main loop. 121 | // 122 | static gboolean gqq_ctx_callback(gpointer data) 123 | { 124 | GQQClosure *c = (GQQClosure*)data; 125 | // invoke the method. 126 | c -> invoker(c -> method, c -> pars); 127 | // free the GQQClosure. 128 | g_slice_free(GQQClosure, c); 129 | return FALSE; 130 | } 131 | 132 | gint gqq_mainloop_attach(GQQMessageLoop *loop, gpointer method, gint par_num, ...) 133 | { 134 | va_list par; 135 | va_start(par, par_num); 136 | GQQClosure *c = g_slice_new0(GQQClosure); 137 | c -> method = method; 138 | c -> invoker = invokers[par_num]; 139 | gpointer p; 140 | gint i; 141 | for(i = 0; i < par_num; ++i){ 142 | p = va_arg(par, gpointer); 143 | c -> pars[i] = p; 144 | } 145 | va_end(par); 146 | 147 | GSource *src = g_idle_source_new(); 148 | g_source_set_callback(src, gqq_ctx_callback, c, NULL); 149 | g_source_attach(src, loop -> ctx); 150 | g_source_unref(src); 151 | return 0; 152 | } 153 | -------------------------------------------------------------------------------- /src/gui/msgloop.h: -------------------------------------------------------------------------------- 1 | #ifndef __GQQ_MSGLOOP_H_ 2 | #define __GQQ_MSGLOOP_H_ 3 | #include 4 | #include 5 | // 6 | // The wrapper of the main loop. 7 | // 8 | typedef struct __GQQMessageLoop{ 9 | GMainLoop *loop; 10 | GMainContext *ctx; 11 | gchar *name; 12 | }GQQMessageLoop; 13 | 14 | // 15 | // Start a new main loop. 16 | // The new main loop will run in a new thread. 17 | // 18 | GQQMessageLoop* gqq_msgloop_start(const gchar *name); 19 | void gqq_msgloop_stop(GQQMessageLoop *loop); 20 | 21 | // 22 | // Invoke the method in the main loop `loop` 23 | // 24 | // @param method : the address of the method which will be called in the 25 | // message loop. 26 | // @param par_num: the number of the parameter of the method. 27 | // <= 5. 28 | // NOTE: 29 | // The types of the parameters of the method must be pointer. 30 | // 31 | gint gqq_mainloop_attach(GQQMessageLoop* loop, gpointer method, gint par_num, ...); 32 | #endif 33 | -------------------------------------------------------------------------------- /src/gui/proxypanel.h: -------------------------------------------------------------------------------- 1 | #ifndef __PROXY_SETTING_H__ 2 | #define __PROXY_SETTING_H__ 3 | 4 | #include 5 | 6 | void set_proxy_btn_cb(GtkButton *btn, gpointer data); 7 | 8 | void on_click_detect_cb(GtkButton *btn, gpointer data); 9 | 10 | void on_click_save_cb(GtkButton * btn , gpointer data); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/gui/settingdialog.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/gui/settingdialog.c -------------------------------------------------------------------------------- /src/gui/settingdialog.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/gui/settingdialog.h -------------------------------------------------------------------------------- /src/gui/sound.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sound.c 3 | * @author mathslinux 4 | * @date Thu Dec 1 14:31:03 2011 5 | * 6 | * @brief Gtkqq sound implementation 7 | * 8 | * 9 | */ 10 | 11 | #include 12 | 13 | #ifdef USE_GSTREAMER 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #define MAX_SOUND_LEN 1 /**< Max audio length.*/ 20 | 21 | #if 0 22 | static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data) 23 | { 24 | GstElement *play = (GstElement *)data; 25 | gboolean res = gst_pipeline_get_auto_flush_bus((GstPipeline *)play); 26 | GError *err = NULL; 27 | 28 | switch (GST_MESSAGE_TYPE (msg)) { 29 | case GST_MESSAGE_ERROR: 30 | gst_message_parse_error(msg, &err, NULL); 31 | g_warning("Play sound error!! (%s, %d)", __FILE__, __LINE__); 32 | g_error_free(err); 33 | 34 | case GST_MESSAGE_EOS: 35 | gst_element_set_state(play, GST_STATE_NULL); 36 | gst_object_unref(GST_OBJECT(play)); 37 | break; 38 | 39 | case GST_MESSAGE_WARNING: 40 | gst_message_parse_warning(msg, &err, NULL); 41 | g_warning("Play sound error!! (%s, %d)", __FILE__, __LINE__); 42 | g_error_free(err); 43 | break; 44 | 45 | default: 46 | break; 47 | } 48 | 49 | return TRUE; 50 | } 51 | #endif 52 | 53 | /** 54 | * Play a audio of wav format when qq client get message. e.g get new chat message. 55 | * 56 | * @param filename The wavfile name. 57 | */ 58 | void qq_play_wavfile(const gchar *filename) 59 | { 60 | char *uri; 61 | GstElement *sink = NULL, *play = NULL; 62 | #if 0 63 | GstBus *bus = NULL; 64 | #endif 65 | 66 | if (!filename) { 67 | g_warning("Null point access!! (%s, %d)", __FILE__, __LINE__); 68 | goto error; 69 | } 70 | 71 | if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { 72 | g_warning("Sound file is not exist!! (%s, %d)", __FILE__, __LINE__); 73 | goto error; 74 | } 75 | 76 | /* Create elements for wav file */ 77 | sink = gst_element_factory_make("alsasink", "sink"); 78 | play = gst_element_factory_make("playbin2", "play"); 79 | uri = g_strdup_printf("file://%s", filename); 80 | 81 | /* Connect elements. */ 82 | g_object_set(G_OBJECT(play), "uri", uri, "audio-sink", sink, NULL); 83 | 84 | if (!sink || !play || !uri) { 85 | g_warning("One element could not be created!! (%s, %d)", __FILE__, __LINE__); 86 | goto error; 87 | } 88 | 89 | if (!sink || !play || !uri) { 90 | g_warning("One element could not be created!! (%s, %d)", __FILE__, __LINE__); 91 | goto error; 92 | } 93 | 94 | #if 0 95 | bus = gst_pipeline_get_bus(GST_PIPELINE(play)); 96 | gst_bus_add_watch(bus, bus_call, play); 97 | gst_object_unref(bus); 98 | #endif 99 | 100 | /* Start play. The code is some ugly now. */ 101 | gst_element_set_state(play,GST_STATE_PLAYING); 102 | sleep(MAX_SOUND_LEN); 103 | gst_element_set_state(play,GST_STATE_NULL); 104 | 105 | error: 106 | if (play) { 107 | g_free(uri); 108 | gst_object_unref(GST_OBJECT(play)); 109 | } 110 | } 111 | 112 | #endif // USE_GSTREAMER 113 | -------------------------------------------------------------------------------- /src/gui/sound.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sound.c 3 | * @author mathslinux 4 | * @date Thu Dec 1 14:31:03 2011 5 | * 6 | * @brief Gtkqq sound implementation 7 | * 8 | * 9 | */ 10 | 11 | #ifndef SOUND_H 12 | #define SOUND_H 13 | 14 | #ifdef USE_GSTREAMER 15 | 16 | /** 17 | * Play a audio of wav format when qq client get message. e.g get new chat message. 18 | * 19 | * @param filename The wavfile name. 20 | */ 21 | void qq_play_wavfile(const gchar *filename); 22 | #endif // USE_GSTREAMER 23 | #endif 24 | -------------------------------------------------------------------------------- /src/gui/splashpanel.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void qq_splashpanelclass_init(QQSplashPanelClass *c); 4 | static void qq_splashpanel_init(QQSplashPanel *obj); 5 | static void qq_splashpanel_destroy(GtkObject *obj); 6 | 7 | GtkWidget *qq_splashpanel_new() 8 | { 9 | QQSplashPanel *panel = g_object_new(qq_splashpanel_get_type(), NULL); 10 | return GTK_WIDGET(panel); 11 | } 12 | 13 | GType qq_splashpanel_get_type() 14 | { 15 | static GType t = 0; 16 | if(!t){ 17 | static const GTypeInfo info = 18 | { 19 | sizeof(QQSplashPanelClass), 20 | NULL, 21 | NULL, 22 | (GClassInitFunc)qq_splashpanelclass_init, 23 | NULL, 24 | NULL, 25 | sizeof(QQSplashPanel), 26 | 0, 27 | (GInstanceInitFunc)qq_splashpanel_init, 28 | NULL 29 | }; 30 | t = g_type_register_static(GTK_TYPE_VBOX, "QQSplashPanel" 31 | , &info, 0); 32 | } 33 | return t; 34 | 35 | } 36 | 37 | static void qq_splashpanelclass_init(QQSplashPanelClass *c) 38 | { 39 | GtkObjectClass *cl = GTK_OBJECT_CLASS(c); 40 | cl -> destroy = qq_splashpanel_destroy; 41 | } 42 | 43 | /* 44 | * Let the progress bar shake. 45 | */ 46 | static gboolean progress_bar_timeout_func(gpointer data) 47 | { 48 | gtk_progress_bar_pulse(GTK_PROGRESS_BAR(data)); 49 | return TRUE; 50 | } 51 | 52 | static void qq_splashpanel_init(QQSplashPanel *obj) 53 | { 54 | GtkWidget *logo = gtk_image_new_from_file(IMGDIR"webqq_icon.png"); 55 | gtk_widget_set_size_request(logo, -1, 250); 56 | gtk_box_pack_start(GTK_BOX(obj), logo, FALSE, FALSE, 0); 57 | 58 | GtkWidget *probar = gtk_progress_bar_new(); 59 | gtk_widget_set_size_request(probar, 200, 50); 60 | gtk_progress_bar_set_text(GTK_PROGRESS_BAR(probar), "登录中..."); 61 | g_timeout_add(100, progress_bar_timeout_func, probar); 62 | 63 | GtkWidget *box = NULL; 64 | box = gtk_hbox_new(FALSE, 0); 65 | gtk_box_pack_start(GTK_BOX(box), probar, TRUE, FALSE, 0); 66 | gtk_box_pack_start(GTK_BOX(obj), box, FALSE, FALSE, 50); 67 | } 68 | static void qq_splashpanel_destroy(GtkObject *obj) 69 | { 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/gui/splashpanel.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_SPLASHPANEL_H 2 | #define __GTKQQ_SPLASHPANEL_H 3 | #include 4 | 5 | #define QQ_SPLASHPANEL(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, qq_splashpanel_get_type(),\ 6 | QQSplashPanel) 7 | #define QQ_SPLASHPANEL_CLASS(c) G_TYPE_CHECK_CLASS_CAST(c,\ 8 | qq_splashpanel_get_type(),\ 9 | QQSplashPanelClass) 10 | #define QQ_IS_SPLASHPANEL(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, qq_splashPanel_get_type()) 11 | 12 | typedef struct _QQSplashPanel QQSplashPanel; 13 | typedef struct _QQSplashPanelClass QQSplashPanelClass; 14 | 15 | struct _QQSplashPanel{ 16 | GtkVBox parent; 17 | }; 18 | 19 | struct _QQSplashPanelClass{ 20 | GtkVBoxClass parent; 21 | }; 22 | 23 | GtkWidget *qq_splashpanel_new(); 24 | GType qq_splashpanel_get_type(); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/gui/statusbutton.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_STATUS_BUTTON 2 | #define __GTKQQ_STATUS_BUTTON 3 | #include 4 | #include 5 | 6 | /* 7 | * QQ status button. 8 | * Show and change the status. 9 | */ 10 | #define QQ_STATUSBUTTON(obj) G_TYPE_CHECK_INSTANCE_CAST(obj\ 11 | , qq_statusbutton_get_type()\ 12 | , QQStatusButton) 13 | #define QQ_STATUSBUTTONCLASS(c) G_TYPE_CHECK_CLASS_CAST(c\ 14 | , qq_statusbutton_get_type()\ 15 | , QQStatusButtonClass) 16 | #define QQ_IS_STATUSBUTTON(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj\ 17 | , qq_statusbutton_get_type()) 18 | #define QQ_TYPE_STATUSBUTTON qq_statusbutton_get_type() 19 | 20 | typedef struct _QQStatusButton QQStatusButton; 21 | typedef struct _QQStatusButtonClass QQStatusButtonClass; 22 | 23 | typedef enum _QQStatusButtonStatus QQStatusButtonStatus; 24 | 25 | enum _QQStatusButtonStatus{ 26 | STATUS_ONLINE = 0, 27 | STATUS_HIDDEN, 28 | STATUS_AWAY, 29 | STATUS_OFFLINE, 30 | STATUS_CALLME, 31 | STATUS_BUSY, 32 | STATUS_SILENT, 33 | STATUS_NUM 34 | }; 35 | 36 | struct _QQStatusButton{ 37 | GtkComboBox parent; 38 | QQStatusButtonStatus status; 39 | 40 | /*< private >*/ 41 | GtkWidget *popmenu; 42 | }; 43 | 44 | struct _QQStatusButtonClass{ 45 | GtkComboBoxClass parent; 46 | 47 | /*< private >*/ 48 | GdkPixbuf *pb[STATUS_NUM]; 49 | GdkPixbuf *arrow; 50 | GdkCursor *hand_cursor; 51 | }; 52 | 53 | GType qq_statusbutton_get_type(); 54 | GtkWidget* qq_statusbutton_new(); 55 | 56 | // 57 | // Get the status 58 | // string or int 59 | // 60 | const gchar* qq_statusbutton_get_status_string(GtkWidget *btn); 61 | QQStatusButtonStatus qq_statusbutton_get_status(GtkWidget *btn); 62 | 63 | // 64 | // Set the status 65 | // 66 | void qq_statusbutton_set_status_string(GtkWidget *btn 67 | , const gchar *status); 68 | void qq_statusbutton_set_status(GtkWidget *btn 69 | , QQStatusButtonStatus status); 70 | #endif 71 | -------------------------------------------------------------------------------- /src/gui/tencent/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS=qq 2 | qq_CPPFLAGS= -I$(srcdir)/. $(GTK_CFLAGS)\ 3 | -DIMGDIR=\"$(pkgdatadir)/misc/\" 4 | qq_LDADD = $(GTK_LIBS) 5 | qq_SOURCES= qqwindow.h qqwindow.c\ 6 | qqbutton.h qqbutton.c\ 7 | qq.c constval.h 8 | -------------------------------------------------------------------------------- /src/gui/tencent/constval.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_CONSTVAL_H 2 | #define __GTKQQ_CONSTVAL_H 3 | /* 4 | * const values used in the program 5 | */ 6 | 7 | #define CLOSEBTN_NOR_IMG "Button_colse_normal.bmp" 8 | #define CLOSEBTN_HL_IMG "Button_close_highlightBackground.bmp" 9 | #define CLOSEBTN_PUSH_IMG "Button_close_pushedBackground.bmp" 10 | 11 | #define MINBTN_NOR_IMG "Button_min_normalBackground.bmp" 12 | #define MINBTN_HL_IMG "Button_min_highlightBackground.bmp" 13 | #define MINBTN_PUSH_IMG "Button_min_pushedBackground.bmp" 14 | 15 | #define MAXBTN_NOR_IMG "Button_max_normalBackground.bmp" 16 | #define MAXBTN_HL_IMG "Button_max_highlightBackground.bmp" 17 | #define MAXBTN_PUSH_IMG "Button_max_pushedBackground.bmp" 18 | 19 | #define RESTOREBTN_NOR_IMG "Button_restore_normal.bmp" 20 | #define RESTOREBTN_HL_IMG "Button_restore_highlightBackground.bmp" 21 | #define RESTOREBTN_PUSH_IMG "Button_restore_pushedBackground.bmp" 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/gui/tencent/qq.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | gtk_init(&argc, &argv); 8 | 9 | GtkWidget *qwin = qq_window_new(); 10 | 11 | QQButton *btn1 = qq_button_new(QQ_BUTTON_CLOSE); 12 | QQButton *btn2 = qq_button_new(QQ_BUTTON_MIN); 13 | QQButton *btn3 = qq_button_new(QQ_BUTTON_MAX); 14 | QQButton *btn4 = qq_button_new(QQ_BUTTON_RESTORE); 15 | gtk_widget_show(GTK_WIDGET(btn1)); 16 | gtk_widget_show(GTK_WIDGET(btn2)); 17 | gtk_widget_show(GTK_WIDGET(btn3)); 18 | gtk_widget_show(GTK_WIDGET(btn4)); 19 | 20 | GtkWidget *hbox = gtk_hbox_new(FALSE, 0); 21 | GtkWidget *vbox = gtk_vbox_new(FALSE, 0); 22 | 23 | gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(btn4), FALSE, FALSE, 0); 24 | gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(btn2), FALSE, FALSE, 0); 25 | gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(btn3), FALSE, FALSE, 0); 26 | gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(btn1), FALSE, FALSE, 0); 27 | gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 0); 28 | 29 | gtk_container_add(GTK_CONTAINER(qwin), vbox); 30 | gtk_widget_show_all(qwin); 31 | gtk_main(); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/gui/tencent/qqbutton.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static void qq_button_init (QQButton *btn, gpointer data); 5 | static void qq_button_class_init (QQButtonClass *bclass, gpointer data); 6 | static void qq_button_set_type (QQButton *btn, QQButtonType type); 7 | 8 | static gboolean enter_notify_event_cb (GtkWidget *widget 9 | , GdkEventCrossing *event 10 | , gpointer data); 11 | static gboolean leave_notify_event_cb (GtkWidget *widget 12 | , GdkEventCrossing *event 13 | , gpointer data); 14 | 15 | static gboolean expose_event_cb (GtkWidget *widget 16 | , GdkEventExpose *event 17 | , gpointer data); 18 | 19 | static gboolean button_press_event_cb (GtkWidget *widget, GdkEventButton *event 20 | , gpointer data); 21 | static gboolean button_release_event_cb (GtkWidget *widget, GdkEventButton *event 22 | , gpointer data); 23 | 24 | QQButton* qq_button_new(QQButtonType type) 25 | { 26 | QQButton *btn; 27 | btn = g_object_new(qq_button_get_type(), NULL); 28 | 29 | /* 30 | * Set the type. 31 | * Maybe this should be done in the ini function. 32 | * But I don't want to use the property. 33 | */ 34 | qq_button_set_type(btn, type); 35 | 36 | return btn; 37 | } 38 | 39 | GType qq_button_get_type() 40 | { 41 | static GType type = 0; 42 | if(type == 0){ 43 | static const GTypeInfo type_info = 44 | { 45 | sizeof(QQButtonClass), 46 | NULL, 47 | NULL, 48 | (GClassInitFunc)qq_button_class_init, 49 | NULL, 50 | NULL, 51 | sizeof(QQButton), 52 | 0, 53 | (GInstanceInitFunc)qq_button_init 54 | }; 55 | 56 | type = g_type_register_static(GTK_TYPE_BUTTON 57 | , "QQButton" 58 | , &type_info 59 | , (GTypeFlags)0); 60 | } 61 | return type; 62 | } 63 | 64 | void qq_button_set_type(QQButton *btn, QQButtonType type) 65 | { 66 | QQButtonClass *c = QQ_BUTTON_GET_CLASS(btn); 67 | switch(type) 68 | { 69 | case QQ_BUTTON_NORMAL: 70 | /* normal button, do nothing */ 71 | break; 72 | case QQ_BUTTON_CLOSE: 73 | btn -> nor_img = c -> closebtn_nor_img; 74 | btn -> hl_img = c -> closebtn_hl_img; 75 | btn -> push_img = c -> closebtn_push_img; 76 | 77 | btn -> curr_img = btn -> nor_img; 78 | btn -> type = type; 79 | break; 80 | case QQ_BUTTON_MIN: 81 | btn -> nor_img = c -> minbtn_nor_img; 82 | btn -> hl_img = c -> minbtn_hl_img; 83 | btn -> push_img = c -> minbtn_push_img; 84 | 85 | btn -> curr_img = btn -> nor_img; 86 | btn -> type = type; 87 | break; 88 | case QQ_BUTTON_MAX: 89 | btn -> nor_img = c -> maxbtn_nor_img; 90 | btn -> hl_img = c -> maxbtn_hl_img; 91 | btn -> push_img = c -> maxbtn_push_img; 92 | 93 | btn -> curr_img = btn -> nor_img; 94 | btn -> type = type; 95 | break; 96 | case QQ_BUTTON_RESTORE: 97 | btn -> nor_img = c -> restorebtn_nor_img; 98 | btn -> hl_img = c -> restorebtn_hl_img; 99 | btn -> push_img = c -> restorebtn_push_img; 100 | btn -> curr_img = btn -> nor_img; 101 | btn -> type = type; 102 | break; 103 | case QQ_BUTTON_UNKNOWN: 104 | default: 105 | break; 106 | } 107 | GtkImage *img = GTK_IMAGE(btn -> curr_img); 108 | GdkPixbuf *pb = gtk_image_get_pixbuf(img); 109 | 110 | gint w,h; 111 | w = gdk_pixbuf_get_width(pb); 112 | h = gdk_pixbuf_get_height(pb); 113 | gtk_widget_set_size_request(GTK_WIDGET(btn), w, h); 114 | } 115 | void qq_button_init(QQButton *btn, gpointer data) 116 | { 117 | g_signal_connect(GTK_WIDGET(btn), "enter-notify-event" 118 | , G_CALLBACK(enter_notify_event_cb), NULL); 119 | g_signal_connect(GTK_WIDGET(btn), "leave-notify-event" 120 | , G_CALLBACK(leave_notify_event_cb), NULL); 121 | g_signal_connect(GTK_WIDGET(btn), "button-press-event" 122 | , G_CALLBACK(button_press_event_cb), NULL); 123 | g_signal_connect(GTK_WIDGET(btn), "button-release-event" 124 | , G_CALLBACK(button_release_event_cb), NULL); 125 | 126 | g_signal_connect(GTK_WIDGET(btn), "expose-event" 127 | , G_CALLBACK(expose_event_cb), NULL); 128 | 129 | btn -> curr_img = NULL; 130 | btn -> nor_img = NULL; 131 | btn -> hl_img = NULL; 132 | btn -> push_img = NULL; 133 | 134 | btn -> alloc = g_slice_new(GtkAllocation); 135 | 136 | return; 137 | } 138 | 139 | void qq_button_class_init(QQButtonClass *bclass, gpointer data) 140 | { 141 | bclass -> closebtn_nor_img = gtk_image_new_from_file( 142 | IMGDIR""CLOSEBTN_NOR_IMG); 143 | bclass -> closebtn_hl_img = gtk_image_new_from_file( 144 | IMGDIR""CLOSEBTN_HL_IMG); 145 | bclass -> closebtn_push_img = gtk_image_new_from_file( 146 | IMGDIR""CLOSEBTN_PUSH_IMG); 147 | bclass -> minbtn_nor_img = gtk_image_new_from_file( 148 | IMGDIR""MINBTN_NOR_IMG); 149 | bclass -> minbtn_hl_img = gtk_image_new_from_file( 150 | IMGDIR""MINBTN_HL_IMG); 151 | bclass -> minbtn_push_img = gtk_image_new_from_file( 152 | IMGDIR""MINBTN_PUSH_IMG); 153 | bclass -> maxbtn_nor_img = gtk_image_new_from_file( 154 | IMGDIR""MAXBTN_NOR_IMG); 155 | bclass -> maxbtn_hl_img = gtk_image_new_from_file( 156 | IMGDIR""MAXBTN_HL_IMG); 157 | bclass -> maxbtn_push_img = gtk_image_new_from_file( 158 | IMGDIR""MAXBTN_PUSH_IMG); 159 | bclass -> restorebtn_nor_img = gtk_image_new_from_file( 160 | IMGDIR""RESTOREBTN_NOR_IMG); 161 | bclass -> restorebtn_hl_img = gtk_image_new_from_file( 162 | IMGDIR""RESTOREBTN_HL_IMG); 163 | bclass -> restorebtn_push_img = gtk_image_new_from_file( 164 | IMGDIR""RESTOREBTN_PUSH_IMG); 165 | } 166 | 167 | 168 | gboolean enter_notify_event_cb(GtkWidget *widget 169 | , GdkEventCrossing *event, gpointer data) 170 | { 171 | QQButton *btn = QQ_BUTTON(widget); 172 | if(btn -> curr_img == btn -> hl_img){ 173 | return FALSE; 174 | } 175 | 176 | btn -> curr_img = btn -> hl_img; 177 | expose_event_cb(widget, NULL, NULL); 178 | return FALSE; 179 | } 180 | 181 | gboolean leave_notify_event_cb(GtkWidget *widget 182 | , GdkEventCrossing *event, gpointer data) 183 | { 184 | QQButton *btn = QQ_BUTTON(widget); 185 | if(btn -> curr_img == btn -> nor_img){ 186 | return FALSE; 187 | } 188 | 189 | btn -> curr_img = btn -> nor_img; 190 | expose_event_cb(widget, NULL, NULL); 191 | return FALSE; 192 | } 193 | 194 | gboolean button_press_event_cb(GtkWidget *widget, GdkEventButton *event 195 | , gpointer data) 196 | { 197 | if(event -> button != 1){ 198 | return FALSE; 199 | } 200 | 201 | QQButton *btn = QQ_BUTTON(widget); 202 | btn -> curr_img = btn -> push_img; 203 | expose_event_cb(widget, NULL, NULL); 204 | return FALSE; 205 | } 206 | gboolean button_release_event_cb(GtkWidget *widget, GdkEventButton *event 207 | , gpointer data) 208 | { 209 | if(event -> button != 1){ 210 | return FALSE; 211 | } 212 | 213 | QQButton *btn = QQ_BUTTON(widget); 214 | btn -> curr_img = btn -> hl_img; 215 | expose_event_cb(widget, NULL, NULL); 216 | return FALSE; 217 | } 218 | 219 | /* 220 | * Render the button. 221 | */ 222 | gboolean expose_event_cb(GtkWidget *widget 223 | , GdkEventExpose *event, gpointer data) 224 | { 225 | QQButton *btn = QQ_BUTTON(widget); 226 | GtkImage *img = (GtkImage*)btn -> curr_img; 227 | cairo_t *ct = gdk_cairo_create(widget -> window); 228 | GdkPixbuf *pb = gtk_image_get_pixbuf(img); 229 | 230 | gtk_widget_get_allocation(widget, btn -> alloc); 231 | gdk_cairo_set_source_pixbuf(ct, pb, btn -> alloc -> x 232 | , btn -> alloc -> y); 233 | cairo_paint(ct); 234 | cairo_destroy(ct); 235 | 236 | /* 237 | * Stop the signal transferring. 238 | * Or not, the normal UI will cover the image. 239 | */ 240 | return TRUE; 241 | } 242 | 243 | -------------------------------------------------------------------------------- /src/gui/tencent/qqbutton.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_QQ_BUTTON_H 2 | #define __GTKQQ_QQ_BUTTON_H 3 | #include 4 | 5 | typedef enum{ 6 | QQ_BUTTON_NORMAL, //the normal button 7 | QQ_BUTTON_CLOSE, //close button 8 | QQ_BUTTON_MIN, //minimize button 9 | QQ_BUTTON_MAX, //maximize button 10 | QQ_BUTTON_RESTORE, //resotre button 11 | QQ_BUTTON_UNKNOWN //unknown button, an error occurs. 12 | }QQButtonType; 13 | 14 | #define QQ_BUTTON_TYPE (qq_button_get_type()) 15 | #define QQ_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj)\ 16 | , QQ_BUTTON_TYPE\ 17 | , QQButton)) 18 | #define QQ_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass)\ 19 | , QQ_BUTTON_TYPE\ 20 | , QQButtonClass)) 21 | #define QQ_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj)\ 22 | , QQ_BUTTON_TYPE)) 23 | #define QQ_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass)\ 24 | , QQ_BUTTON_TYPE)) 25 | #define QQ_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj)\ 26 | , QQ_BUTTON_TYPE\ 27 | , QQButtonClass)) 28 | typedef struct _QQButton QQButton; 29 | typedef struct _QQButtonClass QQButtonClass; 30 | 31 | 32 | struct _QQButton{ 33 | GtkButton parent; 34 | 35 | /* private */ 36 | gint width, height; 37 | 38 | /* 39 | * The images 40 | */ 41 | GtkWidget *nor_img; //the normal image 42 | GtkWidget *hl_img; //when highlight 43 | GtkWidget *push_img; //when push 44 | GtkWidget *curr_img; //current image 45 | 46 | QQButtonType type; 47 | GtkAllocation *alloc; 48 | }; 49 | 50 | struct _QQButtonClass{ 51 | GtkButtonClass parentclass; 52 | /* 53 | * store the images of all the button 54 | */ 55 | GtkWidget *closebtn_nor_img; 56 | GtkWidget *closebtn_hl_img; 57 | GtkWidget *closebtn_push_img; 58 | 59 | GtkWidget *minbtn_nor_img; 60 | GtkWidget *minbtn_hl_img; 61 | GtkWidget *minbtn_push_img; 62 | 63 | GtkWidget *maxbtn_nor_img; 64 | GtkWidget *maxbtn_hl_img; 65 | GtkWidget *maxbtn_push_img; 66 | 67 | GtkWidget *restorebtn_nor_img; 68 | GtkWidget *restorebtn_hl_img; 69 | GtkWidget *restorebtn_push_img; 70 | }; 71 | 72 | QQButton* qq_button_new(QQButtonType type); 73 | GType qq_button_get_type(); 74 | #endif 75 | -------------------------------------------------------------------------------- /src/gui/tencent/qqwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_QQWINDOW_H 2 | #define __GTKQQ_QQWINDOW_H 3 | #include 4 | #include 5 | #include 6 | 7 | #define QQ_WINDOW_TYPE (qq_window_get_type()) 8 | #define QQ_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj)\ 9 | , QQ_WINDOW_TYPE\ 10 | , QQWindow)) 11 | #define QQ_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass)\ 12 | , QQ_WINDOW_TYPE\ 13 | , QQWindowClass)) 14 | #define QQ_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj)\ 15 | , QQ_WINDOW_TYPE)) 16 | #define QQ_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass)\ 17 | , QQ_WINDOW_TYPE)) 18 | #define QQ_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj)\ 19 | , QQ_WINDOW_TYPE\ 20 | , QQWindowClass)) 21 | typedef struct _QQWindow QQWindow; 22 | typedef struct _QQWindowClass QQWindowClass; 23 | 24 | 25 | struct _QQWindow{ 26 | GtkWindow parent; 27 | 28 | /* private */ 29 | gboolean is_maxsize; 30 | gint pre_w, pre_h; //the pre width and height 31 | }; 32 | 33 | struct _QQWindowClass{ 34 | GtkWindowClass parentclass; 35 | 36 | /* private */ 37 | /* 38 | * the cursor used when resize the window 39 | */ 40 | GdkCursor *ls, *rs, *bs, *ts; 41 | GdkCursor *tlc, *trc, *blc, *brc; 42 | GdkCursor *nc; //the normal cursor 43 | 44 | /* 45 | * The width of the border which is used to resize the 46 | * window 47 | */ 48 | gint resize_border; 49 | 50 | /* 51 | * Use to get a rounded rectangle 52 | */ 53 | GdkColormap *cm; 54 | GdkColor fg, bg; 55 | }; 56 | 57 | GtkWidget* qq_window_new(); 58 | GType qq_window_get_type(); 59 | 60 | /* 61 | * Maximizes the windows 62 | * If the window is already maximized, then this function 63 | * does nothing. 64 | */ 65 | void qq_window_maximize(QQWindow *qwin); 66 | /* 67 | * Unmaximizes the windows 68 | * If the window is already unmaximized, then this function 69 | * does nothing. 70 | */ 71 | void qq_window_unmaximize(QQWindow *qwin); 72 | 73 | #endif 74 | 75 | -------------------------------------------------------------------------------- /src/gui/test/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS=winmove 2 | winmove_CPPFLAGS= -I$(srcdir)/. $(GTK_CFLAGS) -g -Wall -O2 3 | winmove_LDADD = $(GTK_LIBS) 4 | 5 | winmove_SOURCES= winmove.c 6 | -------------------------------------------------------------------------------- /src/gui/test/winmove.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static gboolean delete_event_cb(GtkWidget *w, GdkEvent *event, gpointer data) 4 | { 5 | gtk_main_quit(); 6 | return FALSE; 7 | } 8 | 9 | static gboolean button_press_cb(GtkWidget *w, GdkEventButton *event 10 | , gpointer data){ 11 | 12 | g_print("button press.\n"); 13 | gint width,height; 14 | gtk_window_get_size(GTK_WINDOW(w), &width, &height); 15 | gint x,y; 16 | x = (gint)event -> x; 17 | y = (gint)event -> y; 18 | if(x > width - 10 && y > height - 10){ 19 | gtk_window_begin_resize_drag(GTK_WINDOW(w), GDK_WINDOW_EDGE_SOUTH_EAST 20 | , 1, (gint)event -> x_root, (gint)event -> y_root 21 | , 0); 22 | }else{ 23 | gtk_window_begin_move_drag(GTK_WINDOW(w), 1, (gint)event -> x_root 24 | , (gint)event -> y_root 25 | , 0); 26 | 27 | } 28 | return FALSE; 29 | } 30 | 31 | int main(int argc, char **argv) 32 | { 33 | 34 | gtk_init(&argc, &argv); 35 | 36 | GtkWidget *window; 37 | 38 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 39 | gtk_window_set_title(GTK_WINDOW(window), "test"); 40 | gtk_window_set_default_size(GTK_WINDOW(window), 500, 600); 41 | 42 | g_signal_connect(window, "delete-event", G_CALLBACK(delete_event_cb) 43 | , NULL); 44 | g_signal_connect(window, "button-press-event", G_CALLBACK(button_press_cb) 45 | , NULL); 46 | 47 | gtk_window_set_decorated(GTK_WINDOW(window), FALSE); 48 | gtk_widget_show(window); 49 | 50 | //Must be called _after_ the widget is realized 51 | gdk_window_set_events(window -> window, GDK_ALL_EVENTS_MASK); 52 | gtk_main(); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/gui/tray.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_TRAY_H 2 | #define __GTKQQ_TRAY_H 3 | #include 4 | #include 5 | 6 | #define QQ_TRAY(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, qq_tray_get_type(), QQTray) 7 | #define QQ_TRAYCLASS(c) G_TYPE_CHECK_CLASS_CAST(c, qq_tray_get_type()\ 8 | , QQTrayClass) 9 | #define QQ_IS_TRAY(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, qq_tray_get_type()) 10 | 11 | typedef struct __QQTray QQTray; 12 | typedef struct __QQTrayClass QQTrayClass; 13 | 14 | struct __QQTray{ 15 | GtkStatusIcon parent; 16 | }; 17 | 18 | struct __QQTrayClass{ 19 | GtkStatusIconClass parent; 20 | }; 21 | 22 | QQTray* qq_tray_new(); 23 | GType qq_tray_get_type(); 24 | 25 | 26 | // 27 | // Blink the tray icon for the uin 28 | // If the tray icon is blinking, add the uin to the queue. 29 | // 30 | void qq_tray_blinking_for(QQTray *tray, const gchar *uin); 31 | // 32 | // Stop blinking for the uin. 33 | // If some uin is waiting for blinking, blink it. 34 | // 35 | void qq_tray_stop_blinking_for(QQTray *tray, const gchar *uin); 36 | 37 | /** 38 | * Set mute item status, it usually called when user login. 39 | * 40 | * @param tray 41 | * @param mute 42 | */ 43 | void qq_tray_set_mute_item(QQTray *tray, gboolean mute); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/libqq/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES=libwebqq.la 2 | libwebqq_la_CPPFLAGS= $(GTHREAD_CFLAGS) $(GLIB_CFLAGS) $(ZLIB_CFLAGS) 3 | libwebqq_la_LIBADD= $(GTHREAD_LIBS) $(GLIB_LIBS) $(ZLIB_LIBS) 4 | libwebqq_la_SOURCES=http.h http.c json.h json.c url.h qqhosts.h\ 5 | url.c qq.h qqlogin.c qqtypes.h qqtypes.c qqmanageinfo.c\ 6 | unicode.c unicode.h qqinit.c qqpoll.c qqsendmsg.c\ 7 | qqutils.c qqimg.c qqproxy.h qqproxy.c 8 | AM_CFLAGS = -Wall -Werror 9 | -------------------------------------------------------------------------------- /src/libqq/http.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBQQ_HTTP_H 2 | #define __LIBQQ_HTTP_H 3 | /* 4 | * http.h 5 | * 6 | * Describe the http protocol 7 | */ 8 | #include 9 | 10 | /* 11 | * Request 12 | * 13 | * Request = Request-Line 14 | * *(( general-header | request-header | entity-header ) CRLF) 15 | * CRLF 16 | * [ message-body ] 17 | * Request-Line = Method SP Request-URI SP HTTP-Version CRLF 18 | */ 19 | typedef struct 20 | { 21 | GString *method; 22 | GString *uri; 23 | GString *version; 24 | 25 | GTree *headers; //the headers and values. 26 | GString *msg; //message 27 | }Request; 28 | 29 | 30 | /* 31 | * Response 32 | * 33 | * Response = Status-Line ; Section 6.1 34 | * *(( general-header ; Section 4.5 35 | * | response-header ; Section 6.2 36 | * | entity-header ) CRLF) ; Section 7.1 37 | * CRLF 38 | * [ message-body ] ; Section 7.2 39 | * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF 40 | */ 41 | typedef struct 42 | { 43 | GString* version; 44 | GString* status; 45 | GString* reason; 46 | 47 | GTree *headers; //the headers and values. 48 | GString *msg; //message 49 | }Response; 50 | 51 | /* 52 | * create and destroy a request 53 | */ 54 | Request* request_new(); 55 | void request_del(Request *r); 56 | 57 | /* 58 | * convert request to the string format 59 | */ 60 | GString* request_tostring(Request* r); 61 | 62 | void request_set_method(Request* r, const gchar* m); 63 | void request_set_uri(Request* r, const gchar* uri); 64 | void request_set_version(Request* r, const gchar* v); 65 | void request_add_header(Request* r, const gchar* name 66 | , const gchar* value); 67 | 68 | /* 69 | * Set the some headers to simulate the explorer 70 | * we mask as chrome. 71 | */ 72 | void request_set_default_headers(Request *r); 73 | /* 74 | * get the value of header name 75 | */ 76 | GString* request_get_header(Request* r, const GString* name); 77 | 78 | /* 79 | * Append message body to the request. 80 | */ 81 | void request_append_msg(Request* r, const gchar* msg 82 | , gsize len); 83 | 84 | 85 | /*******************************************/ 86 | /* 87 | * create and destroy a response 88 | */ 89 | Response* response_new(); 90 | void response_del(Response *r); 91 | 92 | /* 93 | * parse s and create a response 94 | */ 95 | Response* response_new_parse(GString* s); 96 | /* 97 | * get the value of header 98 | */ 99 | GString* response_get_header(Response *rp, const GString *header); 100 | gchar* response_get_header_chars(Response *rp, const gchar *header); 101 | /* 102 | * convert response to the string format 103 | */ 104 | GString* response_tostring(Response* r); 105 | /* 106 | * only convert the headers and status line to the string format 107 | */ 108 | GString* response_headers_tostring(Response* r); 109 | 110 | 111 | /* 112 | * print \r or \n just like \\r \\n 113 | */ 114 | void print_raw(GString* s); 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /src/libqq/qq.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_SENDMSG_H 2 | #define __GTKQQ_SENDMSG_H 3 | #include 4 | #include 5 | 6 | 7 | // 8 | // Initialize the libqq. 9 | // NOTE: 10 | // **This function MUST be called before any other function!** 11 | // return QQInfo instance if success or NULL if failed 12 | // 13 | QQInfo* qq_init(GError **err); 14 | // 15 | // Finalze the event loops. 16 | // Called before the program exits. 17 | // 18 | void qq_finalize(QQInfo *info, GError **err); 19 | 20 | // 21 | // Check if we need the verify code. 22 | // We need call this function before qq_login. 23 | // If we need the verify code, after this function, the verify code image 24 | // is stored in info -> vc_image_data. 25 | // 26 | gint qq_check_verifycode(QQInfo *info, const gchar *uin, GError **err); 27 | 28 | // 29 | // Login 30 | // @param info store the information used by this program 31 | // @param uin the QQ number 32 | // @param passwd the QQ password 33 | // @param status the status of the user. If NULL, this func 34 | // will not change the status. 35 | // 36 | // If success, return 0. or error code and set *err. 37 | // 38 | gint qq_login(QQInfo *info, const gchar *uin, const gchar *passwd 39 | , const gchar *status, GError **err); 40 | 41 | // 42 | // Logout 43 | // If success, return 0. or error code and set *err. 44 | // 45 | gint qq_logout(QQInfo *info, GError **err); 46 | 47 | // 48 | // Send message 49 | // If success, return 0. or error code and set *err. 50 | // 51 | gint qq_sendmsg(QQSendMsg *msg, GError **err); 52 | GString* get_pwvc_md5(const gchar *pwd, const gchar *vc, GError **err); 53 | 54 | // 55 | // Get all the buddies and categories 56 | // If success, return 0. or error code and set *err. 57 | // 58 | gint qq_get_buddies_and_categories(QQInfo *info, GError **err); 59 | // 60 | // Get all groups. 61 | // If success, return 0. or error code and set *err. 62 | // 63 | gint qq_get_groups(QQInfo *info, GError **err); 64 | // 65 | // Update the details of buddies and groups. 66 | // Buddies, groups etc 67 | // 68 | gint qq_update_details(QQInfo *info, GError **err); 69 | 70 | // 71 | // Get buddy information 72 | // If success, return 0. or error code and set *err. 73 | // 74 | gint qq_get_buddy_info(QQInfo *info, QQBuddy *bdy, GError **err); 75 | // 76 | // Get the group information 77 | // If success, return 0. or error code and set *err. 78 | // 79 | gint qq_get_group_info(QQInfo *info, QQGroup *grp, GError **err); 80 | 81 | // 82 | // Get the online buddies 83 | // If success, return 0. or error code and set *err. 84 | // 85 | gint qq_get_online_buddies(QQInfo *info, GError **err); 86 | // 87 | // Get the recent contact. 88 | // If success, the callback's redata is "GET_RECENT_CONTACT" 89 | // 90 | gint qq_get_recent_contact(QQInfo *info, GError **err); 91 | // 92 | // Get the long nick of bdy. 93 | // If success, return 0. or error code and set *err. 94 | // 95 | gint qq_get_single_long_nick(QQInfo *info, QQBuddy *bdy, GError **err); 96 | // 97 | // Get the qq (group) number of uin 98 | // 99 | gint qq_get_qq_number(QQInfo *info, const gchar *uin 100 | , gchar *num, GError **err); 101 | // 102 | // The callback of the poll fuction. 103 | // @param msg : the message received 104 | // @param data : the user data 105 | // 106 | typedef gint (*QQPollCallBack)(QQRecvMsg *msg, gpointer data); 107 | // 108 | // Start the poll thread to poll the message form the server. 109 | // When a new message received, the QQPollCallBack is called. 110 | // data is passed to cb. 111 | // 112 | // NOTE: 113 | // This function will create a new thread to poll message. 114 | // This function will return immeditally. 115 | // The callback function will called in the new created thread. 116 | // 117 | gint qq_start_poll(QQInfo *info, QQPollCallBack cb, gpointer data 118 | , GError **err); 119 | // 120 | // Stop poll message. 121 | // 122 | void qq_stop_poll(QQInfo *info); 123 | 124 | // 125 | // Send message to friends and group 126 | // 127 | gint qq_send_message(QQInfo *info, QQSendMsg *msg, GError **err); 128 | 129 | // 130 | // Get the face image of uin 131 | // The redata of the cb function is QQFaceImg struct which contains 132 | // the information of the face image. 133 | // 134 | gint qq_get_face_img(QQInfo *info, QQFaceImg *img, GError **err); 135 | // 136 | // Save face image to file path 137 | // 138 | gint qq_save_face_img(QQFaceImg *img, const gchar *path, GError **err); 139 | #endif 140 | -------------------------------------------------------------------------------- /src/libqq/qqhosts.h: -------------------------------------------------------------------------------- 1 | #ifndef __GTKQQ_QQ_HOSTS_H 2 | #define __GTKQQ_QQ_HOSTS_H 3 | 4 | /* 5 | * The hosts and paths used by webqq 6 | */ 7 | 8 | #define WEBQQHOST "web2.qq.com" 9 | 10 | #define LOGINPAGEHOST "ui.ptlogin2.qq.com" 11 | #define LOGINPAGEPATH "/cgi-bin/login" 12 | #define LOGINPROXY "web2.qq.com/loginproxy.html" 13 | #define LOGIN_S_URL "http%3A%2F%2Fweb.qq.com%2Floginproxy.html%3F"\ 14 | "login2qq%3D1%26webqq_type%3D10" 15 | 16 | #define VERPATH "/cgi-bin/ver" 17 | 18 | #define LOGINHOST "ptlogin2.qq.com" 19 | #define VCCHECKPATH "/check" 20 | #define LOGINPATH "/login" 21 | 22 | #define APPID "1003903" 23 | 24 | #define IMAGEHOST "captcha.qq.com" 25 | #define IMAGEPATH "/getimage" 26 | 27 | #define PSIDHOST "d.web2.qq.com" 28 | #define PSIDPATH "/channel/login2" 29 | 30 | #define LOGOUTPATH "/channel/logout2" 31 | #define LOGOUTHOST PSIDHOST 32 | 33 | #define REFERER "http://"LOGOUTHOST"/proxy.html?v=2010102002" 34 | 35 | #define SWQQHOST "s.web2.qq.com" 36 | #define GETINFO "/api/get_friend_info2" 37 | #define GETQQNUM "/api/get_friend_uin2" 38 | #define LNICKPATH "/api/get_single_long_nick2" 39 | #define FRIENDSPATH "/api/get_user_friends2" 40 | #define GNAMEPATH "/api/get_group_name_list_mask2" 41 | #define GETGRPINFO "/api/get_group_info_ext2" 42 | 43 | #define ONLINEHOST PSIDHOST 44 | #define ONLINEPATH "/channel/get_online_buddies2" 45 | 46 | #define RECENTHOST SWQQHOST 47 | #define RECENTPATH "/api/get_recent_contact2" 48 | 49 | #define MSGHOST PSIDHOST 50 | #define MSGFRIPATH "/channel/send_buddy_msg2" 51 | #define MSGGRPPATH "/channel/send_qun_msg2" 52 | 53 | #define POLLHOST PSIDHOST 54 | #define POLLPATH "/channel/poll2" 55 | 56 | #define FIMGHOST "face2.qun.qq.com" 57 | #define FIMGPATH "/cgi/svr/face/getface" 58 | #endif 59 | -------------------------------------------------------------------------------- /src/libqq/qqimg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | /* 8 | * Get the image type from the content type. 9 | */ 10 | static GString* get_image_type(const gchar *ct) 11 | { 12 | if(ct == NULL){ 13 | return NULL; 14 | } 15 | 16 | if(g_strstr_len(ct, -1, "bmp") != NULL){ 17 | return g_string_new("bmp"); 18 | } 19 | if(g_strstr_len(ct, -1, "jpeg") != NULL){ 20 | return g_string_new("jpeg"); 21 | } 22 | if(g_strstr_len(ct, -1, "png") != NULL){ 23 | return g_string_new("png"); 24 | } 25 | if(g_strstr_len(ct, -1, "gif") != NULL){ 26 | return g_string_new("gif"); 27 | } 28 | 29 | g_warning("Unknown image type: %s (%s, %d)", ct, __FILE__, __LINE__); 30 | return NULL; 31 | } 32 | 33 | /* 34 | * get the face image from the server. 35 | */ 36 | gint qq_get_face_img(QQInfo *info, QQFaceImg *img, GError **err) 37 | { 38 | if(info == NULL || img == NULL){ 39 | return PARAMETER_ERR; 40 | } 41 | gint ret_code = NO_ERR; 42 | gchar params[300]; 43 | gint res = 0; 44 | g_debug("Get face image of %s!(%s, %d)", img -> uin -> str 45 | , __FILE__, __LINE__); 46 | 47 | Request *req = request_new(); 48 | Response *rps = NULL; 49 | request_set_method(req, "GET"); 50 | request_set_version(req, "HTTP/1.1"); 51 | g_snprintf(params, 300, FIMGPATH"?cache=0&type=1&fid=0&uin=%s&" 52 | "vfwebqq=%s", img -> uin -> str 53 | , info -> vfwebqq -> str); 54 | request_set_uri(req, params); 55 | request_set_default_headers(req); 56 | request_add_header(req, "Host", FIMGHOST); 57 | request_add_header(req, "Cookie", info -> cookie -> str); 58 | request_add_header(req, "Referer", "http://web2.qq.com/"); 59 | 60 | Connection *con = connect_to_host(FIMGHOST, 80); 61 | if(con == NULL){ 62 | g_warning("Can NOT connect to server!(%s, %d)" 63 | , __FILE__, __LINE__); 64 | request_del(req); 65 | return NETWORK_ERR; 66 | } 67 | 68 | send_request(con, req); 69 | res = rcv_response(con, &rps); 70 | close_con(con); 71 | connection_free(con); 72 | 73 | if (-1 == res || !rps) { 74 | g_warning("Null point access (%s, %d)\n", __FILE__, __LINE__); 75 | ret_code = -1; 76 | goto error; 77 | } 78 | 79 | const gchar *retstatus = rps -> status -> str; 80 | if(g_strstr_len(retstatus, -1, "200") == NULL){ 81 | /* 82 | * Maybe some error occured. 83 | */ 84 | g_warning("Resoponse status is NOT 200, but %s (%s, %d)" 85 | , retstatus, __FILE__, __LINE__); 86 | ret_code = NETWORK_ERR; 87 | goto error; 88 | } 89 | 90 | qq_faceimg_set(img, "data", rps -> msg); 91 | qq_faceimg_set(img, "type", get_image_type( 92 | response_get_header_chars(rps 93 | , "Content-Type"))); 94 | error: 95 | request_del(req); 96 | response_del(rps); 97 | return ret_code; 98 | } 99 | 100 | 101 | /* 102 | * in qqutils.c 103 | */ 104 | extern gint save_img_to_file(const gchar *data, gint len, const gchar *path); 105 | // 106 | //save the face image to file 107 | //the file name is uin 108 | // 109 | gint qq_save_face_img(QQFaceImg *img, const gchar *path, GError **err) 110 | { 111 | if(img == NULL || path == NULL){ 112 | g_warning("img == NULL || path == NULL (%s, %d)" 113 | , __FILE__, __LINE__); 114 | return PARAMETER_ERR; 115 | } 116 | return save_img_to_file(img -> data -> str, img -> data -> len, path); 117 | } 118 | 119 | -------------------------------------------------------------------------------- /src/libqq/qqinit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Do the initail. 3 | */ 4 | #include 5 | #include 6 | 7 | QQInfo* qq_init(GError **err) 8 | { 9 | if(!g_thread_supported()){ 10 | g_thread_init(NULL); 11 | g_message("Init the gthread system. (%s, %d)", __FILE__, __LINE__); 12 | } 13 | QQInfo *info = qq_info_new(); 14 | return info; 15 | } 16 | 17 | void qq_finalize(QQInfo *info, GError **err) 18 | { 19 | if(info == NULL){ 20 | return; 21 | } 22 | 23 | qq_info_free(info); 24 | } 25 | -------------------------------------------------------------------------------- /src/libqq/qqproxy.h: -------------------------------------------------------------------------------- 1 | #ifndef __QQ_PROXY_H__ 2 | #define __QQ_PROXY_H__ 3 | #include 4 | #include 5 | typedef struct { 6 | int num; 7 | const char *str; 8 | } LOOKUP_ITEM; 9 | 10 | #define SOCKET int 11 | 12 | #define METHOD_UNDECIDED 0 13 | #define METHOD_DIRECT 1 14 | #define METHOD_SOCKS 2 15 | #define METHOD_HTTP 3 16 | #define METHOD_TELNET 4 17 | 18 | 19 | #define RESOLVE_UNKNOWN 0 20 | #define RESOLVE_LOCAL 1 21 | #define RESOLVE_REMOTE 2 22 | #define RESOLVE_BOTH 3 23 | 24 | #define LOCAL_STDIO 0 25 | #define LOCAL_SOCKET 1 26 | 27 | #define WITH_RESOLVER 1 28 | 29 | #define ENV_SOCKS_SERVER "SOCKS_SERVER" /* SOCKS server */ 30 | #define ENV_SOCKS5_SERVER "SOCKS5_SERVER" 31 | #define ENV_SOCKS4_SERVER "SOCKS4_SERVER" 32 | 33 | #define ENV_SOCKS_RESOLVE "SOCKS_RESOLVE" /* resolve method */ 34 | #define ENV_SOCKS5_RESOLVE "SOCKS5_RESOLVE" 35 | #define ENV_SOCKS4_RESOLVE "SOCKS4_RESOLVE" 36 | 37 | #define ENV_SOCKS5_USER "SOCKS5_USER" /* auth user for SOCKS5 */ 38 | #define ENV_SOCKS4_USER "SOCKS4_USER" /* auth user for SOCKS4 */ 39 | #define ENV_SOCKS_USER "SOCKS_USER" /* auth user for SOCKS */ 40 | #define ENV_SOCKS5_PASSWD "SOCKS5_PASSWD" /* auth password for SOCKS5 */ 41 | #define ENV_SOCKS5_PASSWORD "SOCKS5_PASSWORD" /* old style */ 42 | 43 | #define ENV_HTTP_PROXY "HTTP_PROXY" /* common env var */ 44 | #define ENV_HTTP_PROXY_USER "HTTP_PROXY_USER" /* auth user */ 45 | #define ENV_HTTP_PROXY_PASSWORD "HTTP_PROXY_PASSWORD" /* auth password */ 46 | 47 | #define ENV_TELNET_PROXY "TELNET_PROXY" /* common env var */ 48 | 49 | #define ENV_CONNECT_USER "CONNECT_USER" /* default auth user name */ 50 | #define ENV_CONNECT_PASSWORD "CONNECT_PASSWORD" /* default auth password */ 51 | 52 | #define ENV_SOCKS_DIRECT "SOCKS_DIRECT" /* addr-list for non-proxy */ 53 | #define ENV_SOCKS5_DIRECT "SOCKS5_DIRECT" 54 | #define ENV_SOCKS4_DIRECT "SOCKS4_DIRECT" 55 | #define ENV_HTTP_DIRECT "HTTP_DIRECT" 56 | #define ENV_CONNECT_DIRECT "CONNECT_DIRECT" 57 | 58 | #define ENV_SOCKS5_AUTH "SOCKS5_AUTH" 59 | #define ENV_SSH_ASKPASS "SSH_ASKPASS" /* askpass program */ 60 | 61 | /* Prefix string of HTTP_PROXY */ 62 | #define HTTP_PROXY_PREFIX "http://" 63 | #define PROXY_AUTH_NONE 0 64 | #define PROXY_AUTH_BASIC 1 65 | #define PROXY_AUTH_DIGEST 2 66 | 67 | #define REASON_UNK -2 68 | #define REASON_ERROR -1 69 | #define REASON_CLOSED_BY_LOCAL 0 70 | #define REASON_CLOSED_BY_REMOTE 1 71 | 72 | /* return value of relay start function. */ 73 | #define START_ERROR -1 74 | #define START_OK 0 75 | #define START_RETRY 1 76 | 77 | #ifndef SOCKET_ERROR 78 | #define SOCKET_ERROR -1 79 | #endif 80 | 81 | #define MAX_DIRECT_ADDR_LIST 256 82 | 83 | void fatal( const char *fmt, ... ); 84 | void *xmalloc (size_t size); 85 | char * downcase( char *str ); 86 | 87 | char * expand_host_and_port (const char *fmt, const char *host, int port); 88 | int lookup_resolve( const char *str ); 89 | 90 | char *getusername(void); 91 | int expect( char *str, char *substr); 92 | 93 | #define PARAMETER_FILE "/etc/connectrc" 94 | #define PARAMETER_DOTFILE ".connectrc" 95 | typedef struct { 96 | char* name; 97 | char* value; 98 | } PARAMETER_ITEM; 99 | 100 | struct ADDRPAIR { 101 | struct in_addr addr; 102 | struct in_addr mask; 103 | char *name; 104 | int negative; 105 | }; 106 | #define socket_errno() (errno) 107 | 108 | PARAMETER_ITEM* find_parameter_item(const char* name); 109 | void set_timeout(int timeout); 110 | void sig_timeout(void); 111 | 112 | void mask_addr (void *addr, void *mask, int addrlen); 113 | 114 | int cmp_addr (void *addr1, void *addr2, int addrlen); 115 | int domain_match(const char *s1, const char *s2); 116 | void mask_addr (void *addr, void *mask, int addrlen); 117 | 118 | int is_direct_name (const char *name); 119 | 120 | int is_direct_address (const struct in_addr addr); 121 | 122 | int check_direct(const char *host); 123 | 124 | int local_resolve (const char *host, struct sockaddr_in *addr); 125 | int open_connection( const char *host, short port ); 126 | 127 | int atomic_out( SOCKET s, char *buf, int size ); 128 | int atomic_in( SOCKET s, char *buf, int size ); 129 | int line_input( SOCKET s, char *buf, int size ); 130 | char * cut_token( char *str, char *delim); 131 | 132 | char *make_base64_string(const char *str); 133 | int basic_auth (SOCKET s); 134 | 135 | 136 | int begin_http_relay( SOCKET s ); 137 | 138 | void set_relay(int method, const char * server, int port, const char * usr, const char * pass); 139 | 140 | int get_authenticated_socket(const char * host, int port); 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /src/libqq/qqsendmsg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static gint do_send_buddy_msg(QQInfo *info, QQSendMsg *msg, GError **err) 11 | { 12 | GString *uin = msg -> to_uin; 13 | 14 | gint ret_code = 0; 15 | gint res = 0; 16 | gchar params[3000]; 17 | g_debug("Send msg to %s!(%s, %d)", uin -> str, __FILE__, __LINE__); 18 | 19 | Request *req = request_new(); 20 | Response *rps = NULL; 21 | request_set_method(req, "POST"); 22 | request_set_version(req, "HTTP/1.1"); 23 | request_set_uri(req, MSGFRIPATH); 24 | request_set_default_headers(req); 25 | request_add_header(req, "Host", MSGHOST); 26 | request_add_header(req, "Cookie", info -> cookie -> str); 27 | request_add_header(req, "Origin", "http://d.web2.qq.com"); 28 | request_add_header(req, "Content-Type", 29 | "application/x-www-form-urlencoded"); 30 | request_add_header(req, "Referer" 31 | , "http://"MSGHOST"/proxy.html?v=20110331002&callback=2"); 32 | GString *content; 33 | content = qq_sendmsg_contents_tostring(msg); 34 | g_snprintf(params, 3000, "r={\"to\":%s,\"face\":%s," 35 | "%s,\"msg_id\":%s," 36 | "\"clientid\":\"%s\",\"psessionid\":\"%s\"}" 37 | , uin -> str, msg -> face -> str 38 | , content -> str 39 | , msg -> msg_id -> str 40 | , info -> clientid -> str 41 | , info -> psessionid -> str); 42 | g_string_free(content, TRUE); 43 | gchar *euri = g_uri_escape_string(params, "=", FALSE); 44 | request_append_msg(req, euri, strlen(euri)); 45 | g_free(euri); 46 | 47 | g_snprintf(params, 3000, "%u", (unsigned int)strlen(req -> msg -> str)); 48 | request_add_header(req, "Content-Length", params); 49 | 50 | Connection *con = connect_to_host(MSGHOST, 80); 51 | if(con == NULL){ 52 | g_warning("Can NOT connect to server!(%s, %d)" 53 | , __FILE__, __LINE__); 54 | request_del(req); 55 | return -1; 56 | } 57 | 58 | send_request(con, req); 59 | res = rcv_response(con, &rps); 60 | close_con(con); 61 | connection_free(con); 62 | 63 | if (-1 == res || !rps) { 64 | g_warning("Null point access (%s, %d)\n", __FILE__, __LINE__); 65 | ret_code = -1; 66 | goto error; 67 | } 68 | const gchar *retstatus = rps -> status -> str; 69 | json_t *json = NULL; 70 | if(g_strstr_len(retstatus, -1, "200") == NULL){ 71 | /* 72 | * Maybe some error occured. 73 | */ 74 | g_warning("Resoponse status is NOT 200, but %s (%s, %d)" 75 | , retstatus, __FILE__, __LINE__); 76 | ret_code = -1; 77 | goto error; 78 | } 79 | 80 | switch(json_parse_document(&json, rps -> msg -> str)) 81 | { 82 | case JSON_OK: 83 | break; 84 | default: 85 | g_warning("json_parser_document: syntax error. (%s, %d)" 86 | , __FILE__, __LINE__); 87 | } 88 | 89 | json_t *val = json_find_first_label_all(json, "result"); 90 | if(val != NULL){ 91 | val = val -> child; 92 | if(g_strstr_len(val -> text, -1, "ok") == NULL){ 93 | g_warning("Server return error. %s (%s, %d)" 94 | , val -> text, __FILE__, __LINE__); 95 | } 96 | }else{ 97 | g_warning("Server return: (%s, %d)%s", __FILE__, __LINE__ 98 | , rps -> msg -> str); 99 | } 100 | json_free_value(&json); 101 | error: 102 | request_del(req); 103 | response_del(rps); 104 | return ret_code; 105 | } 106 | 107 | static gint do_send_group_msg(QQInfo *info, QQSendMsg *msg, GError **err) 108 | { 109 | GString *uin = msg -> to_uin; 110 | 111 | gint ret_code = 0; 112 | gint res = 0; 113 | gchar params[3000]; 114 | g_debug("Send msg to %s!(%s, %d)", uin -> str, __FILE__, __LINE__); 115 | 116 | Request *req = request_new(); 117 | Response *rps = NULL; 118 | request_set_method(req, "POST"); 119 | request_set_version(req, "HTTP/1.1"); 120 | request_set_uri(req, MSGGRPPATH); 121 | request_set_default_headers(req); 122 | request_add_header(req, "Host", MSGHOST); 123 | request_add_header(req, "Cookie", info -> cookie -> str); 124 | request_add_header(req, "Origin", "http://d.web2.qq.com"); 125 | request_add_header(req, "Content-Type", 126 | "application/x-www-form-urlencoded"); 127 | request_add_header(req, "Referer" 128 | , "http://"MSGHOST"/proxy.html?v=20101025002&callback=2"); 129 | GString *content; 130 | content = qq_sendmsg_contents_tostring(msg); 131 | g_snprintf(params, 3000, "r={\"group_uin\":\"%s\"," 132 | "%s,\"msg_id\":%s," 133 | "\"clientid\":\"%s\",\"psessionid\":\"%s\"}" 134 | "&clientid=%s&psessionid=%s" 135 | , uin -> str, content -> str 136 | , msg -> msg_id -> str 137 | , info -> clientid -> str 138 | , info -> psessionid -> str 139 | , info -> clientid -> str 140 | , info -> psessionid -> str); 141 | g_string_free(content, TRUE); 142 | 143 | gchar *euri = g_uri_escape_string(params, "=", FALSE); 144 | request_append_msg(req, euri, strlen(euri)); 145 | g_free(euri); 146 | 147 | g_snprintf(params, 3000, "%u", (unsigned int)strlen(req -> msg -> str)); 148 | request_add_header(req, "Content-Length", params); 149 | 150 | Connection *con = connect_to_host(MSGHOST, 80); 151 | if(con == NULL){ 152 | g_warning("Can NOT connect to server!(%s, %d)" 153 | , __FILE__, __LINE__); 154 | request_del(req); 155 | return -1; 156 | } 157 | 158 | send_request(con, req); 159 | res = rcv_response(con, &rps); 160 | close_con(con); 161 | connection_free(con); 162 | 163 | if (-1 == res || !rps) { 164 | g_warning("Null point access (%s, %d)\n", __FILE__, __LINE__); 165 | ret_code = -1; 166 | goto error; 167 | } 168 | const gchar *retstatus = rps -> status -> str; 169 | json_t *json = NULL; 170 | if(g_strstr_len(retstatus, -1, "200") == NULL){ 171 | /* 172 | * Maybe some error occured. 173 | */ 174 | g_warning("Resoponse status is NOT 200, but %s (%s, %d)" 175 | , retstatus, __FILE__, __LINE__); 176 | ret_code = -1; 177 | goto error; 178 | } 179 | 180 | switch(json_parse_document(&json, rps -> msg -> str)) 181 | { 182 | case JSON_OK: 183 | break; 184 | default: 185 | g_warning("json_parser_document: syntax error. (%s, %d)" 186 | , __FILE__, __LINE__); 187 | } 188 | 189 | json_t *val = json_find_first_label_all(json, "result"); 190 | if(val != NULL){ 191 | val = val -> child; 192 | if(g_strstr_len(val -> text, -1, "ok") == NULL){ 193 | g_warning("Server return error. %s (%s, %d)" 194 | , val -> text, __FILE__, __LINE__); 195 | } 196 | }else{ 197 | g_warning("Server return: (%s, %d)%s", __FILE__, __LINE__ 198 | , rps -> msg -> str); 199 | } 200 | json_free_value(&json); 201 | error: 202 | request_del(req); 203 | response_del(rps); 204 | return ret_code; 205 | } 206 | 207 | gint qq_send_message(QQInfo *info, QQSendMsg *msg, GError **err) 208 | { 209 | if(info == NULL || msg == NULL){ 210 | g_warning("info or msg == NULL. (%s, %d)", __FILE__ 211 | , __LINE__); 212 | return -1; 213 | } 214 | 215 | switch(msg -> type) 216 | { 217 | case MSG_BUDDY_T: 218 | return do_send_buddy_msg(info, msg, err); 219 | case MSG_GROUP_T: 220 | return do_send_group_msg(info, msg, err); 221 | default: 222 | g_warning("Unknown message type: %d (%s, %d)" 223 | , msg -> type, __FILE__, __LINE__); 224 | return -1; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /src/libqq/qqutils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | * Get the milliseconds of now 12 | */ 13 | glong get_now_millisecond() 14 | { 15 | glong re; 16 | GTimeVal now; 17 | g_get_current_time(&now); 18 | re = now.tv_usec / 1000; 19 | re += now.tv_sec; 20 | return re; 21 | } 22 | 23 | /* 24 | * Save the image data to file. 25 | * The file is path/fname.ext. 26 | */ 27 | gint save_img_to_file(const gchar *data, gint len, const gchar *path ) 28 | { 29 | if(data == NULL){ 30 | return -1; 31 | } 32 | 33 | g_debug("Create image file : %s (%s, %d)", path, __FILE__, __LINE__); 34 | gint fd = creat(path, S_IRUSR | S_IWUSR); 35 | if(fd == -1){ 36 | g_warning("Create image data to file error! %s (%s, %d)" 37 | , strerror(errno), __FILE__, __LINE__); 38 | return -1; 39 | } 40 | 41 | GError *err = NULL; 42 | GIOChannel *ioc = g_io_channel_unix_new(fd); 43 | if(ioc == NULL){ 44 | g_warning("Create io channle error!! %d %s " 45 | "(%s, %d)", err -> code , err -> message 46 | , __FILE__, __LINE__); 47 | g_error_free(err); 48 | return -1; 49 | } 50 | err = NULL; 51 | g_io_channel_set_encoding(ioc, NULL, &err); 52 | err = NULL; 53 | GIOStatus status; 54 | gsize bytes_w; 55 | status = g_io_channel_write_chars(ioc, data, len, &bytes_w, &err); 56 | switch(status) 57 | { 58 | case G_IO_STATUS_NORMAL: 59 | if(bytes_w < len){ 60 | g_warning("Not write all verify code image data " 61 | "to file!(%s, %d)", __FILE__ 62 | , __LINE__); 63 | } 64 | break; 65 | case G_IO_STATUS_ERROR: 66 | g_warning("Write verify code image file error! %d %s " 67 | "(%s, %d)", err -> code , err -> message 68 | , __FILE__, __LINE__); 69 | goto error; 70 | case G_IO_STATUS_EOF: 71 | case G_IO_STATUS_AGAIN: 72 | default: 73 | break; 74 | } 75 | 76 | error: 77 | g_io_channel_close(ioc); 78 | g_io_channel_unref(ioc); 79 | return 0; 80 | } 81 | 82 | void create_error_msg(GError **err, gint code, const gchar *fmt, ...) 83 | { 84 | va_list ap; 85 | va_start(ap, fmt); 86 | 87 | if(err != NULL){ 88 | *err = g_error_new_valist(g_quark_from_string("GtkQQ") 89 | , code, fmt, ap); 90 | } 91 | va_end(ap); 92 | } 93 | -------------------------------------------------------------------------------- /src/libqq/unicode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #if 0 3 | static gboolean is_space(gchar c) 4 | { 5 | if(c == ' ' || c == '\t' || c == '\n' || c == '\r'){ 6 | return TRUE; 7 | } 8 | return FALSE; 9 | } 10 | #endif 11 | 12 | static guint hex2char(gchar c) 13 | { 14 | if(c >= '0' && c <= '9'){ 15 | return c - '0'; 16 | } 17 | 18 | if(c >= 'a' && c <= 'f'){ 19 | return c - 'a' + 10; 20 | } 21 | 22 | if(c >= 'A' && c <= 'F'){ 23 | return c - 'A' + 10; 24 | } 25 | return 0; 26 | } 27 | 28 | /* 29 | * decode UCS-4 to utf8 30 | * UCS-4 code UTF-8 31 | * U+00000000–U+0000007F 0xxxxxxx 32 | * U+00000080–U+000007FF 110xxxxx 10xxxxxx 33 | * U+00000800–U+0000FFFF 1110xxxx 10xxxxxx 10xxxxxx 34 | * U+00010000–U+001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 35 | * U+00200000–U+03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 36 | * U+04000000–U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 37 | * 38 | * Chinese are all in U+00000800–U+0000FFFF. 39 | * So only decode to the second and third format. 40 | */ 41 | 42 | static void do_ucs4toutf8(GString *to, const gchar *from) 43 | { 44 | static guint E = 0xe0; 45 | static guint T = 0x02; 46 | static guint sep1 = 0x80; 47 | static guint sep2 = 0x800; 48 | static guint sep3 = 0x10000; 49 | static guint sep4 = 0x200000; 50 | static guint sep5 = 0x4000000; 51 | 52 | guint tmp[4]; 53 | gchar re[6]; 54 | guint ivalue = 0; 55 | 56 | gint i; 57 | for(i = 0; i < 4; ++i){ 58 | tmp[i] = 0xf & hex2char(from[ i + 2]); 59 | ivalue *= 16; 60 | ivalue += tmp[i]; 61 | } 62 | 63 | //decode 64 | if(ivalue < sep1){ 65 | //0xxxxxxx 66 | re[0] = 0x7f & tmp[3]; 67 | g_string_append_c(to, re[0]); 68 | }else if(ivalue < sep2){ 69 | //110xxxxx 10xxxxxx 70 | re[0] = (0x3 << 6) | ((tmp[1] & 7) << 2) | (tmp[2] >> 2); 71 | re[1] = (0x1 << 7) | ((tmp[2] & 3) << 4) | tmp[3]; 72 | g_string_append_c(to, re[0]); 73 | g_string_append_c(to, re[1]); 74 | }else if(ivalue < sep3){ 75 | //1110xxxx 10xxxxxx 10xxxxxx 76 | re[0] = E | (tmp[0] & 0xf); 77 | re[1] = (T << 6) | (tmp[1] << 2) | ((tmp[2] >> 2) & 0x3); 78 | re[2] = (T << 6) | (tmp[2] & 0x3) << 4 | tmp[3]; 79 | //copy to @to. 80 | for(i = 0; i < 3; ++i){ 81 | g_string_append_c(to, re[i]); 82 | } 83 | }else if(ivalue < sep4){ 84 | //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 85 | re[0] = 0xf0 | ((tmp[1] >> 2) & 0x7); 86 | re[1] = 0x2 << 6 | ((tmp[1] & 0x3) << 4) | ((tmp[2] >> 4) & 0xf); 87 | re[2] = 0x2 << 6 | ((tmp[2] & 0xf) << 4) | ((tmp[3] >> 6) & 0x3); 88 | re[3] = 0x2 << 6 | (tmp[2] & 0x3f); 89 | //copy to @to. 90 | for(i = 0; i < 4; ++i){ 91 | g_string_append_c(to, re[i]); 92 | } 93 | }else if(ivalue < sep5){ 94 | //111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 95 | g_warning("Not implement Unicoe convert!! U+00200000–U+03FFFFFF " 96 | "(%s, %d)", __FILE__, __LINE__); 97 | }else{ 98 | //1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 99 | g_warning("Not implement Unicoe convert!! U+04000000–U+7FFFFFFF " 100 | "(%s, %d)", __FILE__, __LINE__); 101 | } 102 | } 103 | 104 | void ucs4toutf8(GString *to, const gchar *from) 105 | { 106 | if(to == NULL || from == NULL){ 107 | return; 108 | } 109 | const gchar *c; 110 | for(c = from; *c != '\0'; ++c){ 111 | if(*c == '\\' && *(c + 1) == 'u'){ 112 | do_ucs4toutf8(to, c); 113 | c+= 5; 114 | }else{ 115 | g_string_append_c(to, *c); 116 | continue; 117 | } 118 | } 119 | } 120 | 121 | 122 | -------------------------------------------------------------------------------- /src/libqq/unicode.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBQQ_UNICODE_H 2 | #define __LIBQQ_UNICODE_H 3 | #include 4 | /* 5 | * Convert UCS-4 to UTF8. 6 | * 7 | * The result will be stored in to. 8 | */ 9 | void ucs4toutf8(GString *to, const gchar *from); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/libqq/url.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBWEBQQ_URL_H 2 | #define __LIBWEBQQ_URL_H 3 | #include 4 | 5 | /* 6 | * send and recive the http protocol 7 | */ 8 | 9 | /* 10 | * define a connection to any host 11 | */ 12 | typedef struct{ 13 | int fd; //socket fd 14 | GIOChannel *channel; //the GIOChannel of the fd. 15 | 16 | gchar *buf; //use to read data. 17 | gsize bufsize; //buffer size 18 | }Connection; 19 | 20 | /* 21 | * create and free a connection. 22 | * Just allocate and free the memory. 23 | */ 24 | Connection* connection_new(); 25 | void connection_free(Connection *con); 26 | 27 | /* 28 | * Connect to the url:port 29 | * return the socket file descriptor, or -1 for error. 30 | */ 31 | Connection* connect_to_host(const char *hostname, int port); 32 | /* 33 | * close the connection 34 | */ 35 | void close_con(Connection* con); 36 | /* 37 | * sent the request to fd. 38 | */ 39 | gint send_request(Connection* con, Request *r); 40 | 41 | /* 42 | * read the response from fd. 43 | * the response will store in **r. 44 | */ 45 | gint rcv_response(Connection* con, Response **rp); 46 | #endif 47 | -------------------------------------------------------------------------------- /src/misc/Button_close_highlightBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_close_highlightBackground.bmp -------------------------------------------------------------------------------- /src/misc/Button_close_pushedBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_close_pushedBackground.bmp -------------------------------------------------------------------------------- /src/misc/Button_colse_normal.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_colse_normal.bmp -------------------------------------------------------------------------------- /src/misc/Button_max_highlightBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_max_highlightBackground.bmp -------------------------------------------------------------------------------- /src/misc/Button_max_normalBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_max_normalBackground.bmp -------------------------------------------------------------------------------- /src/misc/Button_max_pushedBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_max_pushedBackground.bmp -------------------------------------------------------------------------------- /src/misc/Button_min_highlightBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_min_highlightBackground.bmp -------------------------------------------------------------------------------- /src/misc/Button_min_normalBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_min_normalBackground.bmp -------------------------------------------------------------------------------- /src/misc/Button_min_pushedBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_min_pushedBackground.bmp -------------------------------------------------------------------------------- /src/misc/Button_restore_highlightBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_restore_highlightBackground.bmp -------------------------------------------------------------------------------- /src/misc/Button_restore_normal.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_restore_normal.bmp -------------------------------------------------------------------------------- /src/misc/Button_restore_pushedBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/Button_restore_pushedBackground.bmp -------------------------------------------------------------------------------- /src/misc/ContactMainTabButton1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/ContactMainTabButton1.png -------------------------------------------------------------------------------- /src/misc/ContactMainTabButton2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/ContactMainTabButton2.png -------------------------------------------------------------------------------- /src/misc/GroupMainTabButton1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/GroupMainTabButton1.png -------------------------------------------------------------------------------- /src/misc/GroupMainTabButton2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/GroupMainTabButton2.png -------------------------------------------------------------------------------- /src/misc/MainPanel_Support_DownBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/MainPanel_Support_DownBackground.bmp -------------------------------------------------------------------------------- /src/misc/MainPanel_Support_NormalBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/MainPanel_Support_NormalBackground.bmp -------------------------------------------------------------------------------- /src/misc/MainPanel_Support_highlightBackground.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/MainPanel_Support_highlightBackground.bmp -------------------------------------------------------------------------------- /src/misc/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS=qqfaces status sound 2 | 3 | imgdir= ${pkgdatadir}/misc 4 | img_DATA=\ 5 | Button_close_highlightBackground.bmp\ 6 | Button_close_pushedBackground.bmp\ 7 | Button_colse_normal.bmp\ 8 | Button_max_highlightBackground.bmp\ 9 | Button_max_normalBackground.bmp\ 10 | Button_max_pushedBackground.bmp\ 11 | Button_min_highlightBackground.bmp\ 12 | Button_min_normalBackground.bmp\ 13 | Button_min_pushedBackground.bmp\ 14 | Button_restore_highlightBackground.bmp\ 15 | Button_restore_normal.bmp\ 16 | Button_restore_pushedBackground.bmp\ 17 | MainPanel_Support_DownBackground.bmp\ 18 | MainPanel_Support_highlightBackground.bmp\ 19 | MainPanel_Support_NormalBackground.bmp\ 20 | webqq_icon.png\ 21 | avatar.gif\ 22 | phone.png\ 23 | group.png\ 24 | webqq.png\ 25 | sendfile.png selectfont.png selectface.png sendpic.png\ 26 | showhistory.png clearscreen.png\ 27 | avatar.png\ 28 | ContactMainTabButton1.png ContactMainTabButton2.png\ 29 | GroupMainTabButton1.png GroupMainTabButton2.png\ 30 | RecentMainTabButton1.png RecentMainTabButton2.png 31 | # dist_img_DATA = $(img_DATA) 32 | # EXTRA_DIST = $(imgdir) 33 | EXTRA_DIST = $(img_DATA) 34 | -------------------------------------------------------------------------------- /src/misc/RecentMainTabButton1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/RecentMainTabButton1.png -------------------------------------------------------------------------------- /src/misc/RecentMainTabButton2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/RecentMainTabButton2.png -------------------------------------------------------------------------------- /src/misc/avatar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/avatar.gif -------------------------------------------------------------------------------- /src/misc/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/avatar.png -------------------------------------------------------------------------------- /src/misc/clearscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/clearscreen.png -------------------------------------------------------------------------------- /src/misc/group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/group.png -------------------------------------------------------------------------------- /src/misc/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/phone.png -------------------------------------------------------------------------------- /src/misc/qqfaces/0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/0.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/1.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/10.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/100.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/100.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/101.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/101.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/102.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/102.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/103.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/103.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/104.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/104.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/105.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/105.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/106.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/106.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/107.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/107.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/108.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/108.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/109.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/109.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/11.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/110.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/110.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/111.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/111.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/112.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/112.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/113.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/113.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/114.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/115.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/115.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/116.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/116.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/117.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/117.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/118.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/118.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/119.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/119.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/12.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/120.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/120.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/121.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/121.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/122.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/122.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/123.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/123.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/124.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/124.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/125.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/125.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/126.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/126.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/127.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/127.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/128.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/128.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/129.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/129.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/13.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/130.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/130.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/131.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/131.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/132.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/132.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/133.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/133.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/134.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/134.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/14.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/15.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/16.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/17.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/18.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/19.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/2.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/20.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/21.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/22.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/23.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/24.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/25.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/26.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/27.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/27.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/28.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/29.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/3.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/30.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/31.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/31.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/32.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/33.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/34.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/34.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/35.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/35.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/36.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/36.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/37.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/37.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/38.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/38.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/39.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/39.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/4.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/40.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/40.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/41.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/41.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/42.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/42.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/43.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/43.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/44.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/44.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/45.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/45.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/46.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/46.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/47.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/47.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/48.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/48.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/49.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/49.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/5.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/50.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/51.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/51.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/52.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/52.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/53.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/53.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/54.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/54.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/55.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/55.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/56.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/56.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/57.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/57.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/58.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/58.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/59.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/59.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/6.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/60.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/60.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/61.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/61.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/62.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/62.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/63.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/63.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/64.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/64.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/65.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/65.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/66.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/66.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/67.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/67.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/68.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/68.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/69.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/69.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/7.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/70.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/70.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/71.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/71.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/72.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/72.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/73.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/73.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/74.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/74.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/75.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/75.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/76.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/76.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/77.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/77.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/78.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/78.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/79.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/79.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/8.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/80.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/80.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/81.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/81.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/82.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/82.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/83.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/83.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/84.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/84.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/85.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/85.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/86.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/86.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/87.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/87.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/88.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/88.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/89.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/89.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/9.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/90.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/90.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/91.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/91.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/92.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/92.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/93.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/93.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/94.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/94.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/95.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/95.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/96.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/96.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/97.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/97.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/98.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/98.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/99.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/qqfaces/99.gif -------------------------------------------------------------------------------- /src/misc/qqfaces/Makefile.am: -------------------------------------------------------------------------------- 1 | faceimgdir= ${pkgdatadir}/misc/qqfaces 2 | faceimg_DATA=\ 3 | 0.gif 109.gif 118.gif 127.gif 14.gif 23.gif 32.gif\ 4 | 41.gif 50.gif 5.gif 69.gif 78.gif 87.gif 96.gif\ 5 | 100.gif 10.gif 119.gif 128.gif 15.gif 24.gif 33.gif\ 6 | 42.gif 51.gif 60.gif 6.gif 79.gif 88.gif 97.gif\ 7 | 101.gif 110.gif 11.gif 129.gif 16.gif 25.gif 34.gif\ 8 | 43.gif 52.gif 61.gif 70.gif 7.gif 89.gif 98.gif\ 9 | 102.gif 111.gif 120.gif 12.gif 17.gif 26.gif 35.gif\ 10 | 44.gif 53.gif 62.gif 71.gif 80.gif 8.gif 99.gif\ 11 | 103.gif 112.gif 121.gif 130.gif 18.gif 27.gif 36.gif\ 12 | 45.gif 54.gif 63.gif 72.gif 81.gif 90.gif 9.gif\ 13 | 104.gif 113.gif 122.gif 131.gif 19.gif 28.gif 37.gif\ 14 | 46.gif 55.gif 64.gif 73.gif 82.gif 91.gif\ 15 | 105.gif 114.gif 123.gif 132.gif 1.gif 29.gif 38.gif\ 16 | 47.gif 56.gif 65.gif 74.gif 83.gif 92.gif\ 17 | 106.gif 115.gif 124.gif 133.gif 20.gif 2.gif 39.gif\ 18 | 48.gif 57.gif 66.gif 75.gif 84.gif 93.gif\ 19 | 107.gif 116.gif 125.gif 134.gif 21.gif 30.gif 3.gif\ 20 | 49.gif 58.gif 67.gif 76.gif 85.gif 94.gif\ 21 | 108.gif 117.gif 126.gif 13.gif 22.gif 31.gif 40.gif\ 22 | 4.gif 59.gif 68.gif 77.gif 86.gif 95.gif 23 | 24 | # EXTRA_DIST = $(faceimgdir) 25 | EXTRA_DIST = $(faceimg_DATA) 26 | -------------------------------------------------------------------------------- /src/misc/selectface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/selectface.png -------------------------------------------------------------------------------- /src/misc/selectfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/selectfont.png -------------------------------------------------------------------------------- /src/misc/sendfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sendfile.png -------------------------------------------------------------------------------- /src/misc/sendpic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sendpic.png -------------------------------------------------------------------------------- /src/misc/showhistory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/showhistory.png -------------------------------------------------------------------------------- /src/misc/sound/Classic/Audio.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Classic/Audio.wav -------------------------------------------------------------------------------- /src/misc/sound/Classic/Global.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Classic/Global.wav -------------------------------------------------------------------------------- /src/misc/sound/Classic/msg.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Classic/msg.wav -------------------------------------------------------------------------------- /src/misc/sound/Classic/shake.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Classic/shake.wav -------------------------------------------------------------------------------- /src/misc/sound/Classic/system.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Classic/system.wav -------------------------------------------------------------------------------- /src/misc/sound/Makefile.am: -------------------------------------------------------------------------------- 1 | classicsounddir=${pkgdatadir}/misc/sound/Classic 2 | officesounddir=${pkgdatadir}/misc/sound/Office 3 | 4 | classicsound_DATA=\ 5 | Classic/Audio.wav\ 6 | Classic/Global.wav\ 7 | Classic/msg.wav\ 8 | Classic/shake.wav\ 9 | Classic/system.wav 10 | 11 | officesound_DATA=\ 12 | Office/Audio.wav\ 13 | Office/Global.wav\ 14 | Office/msg.wav\ 15 | Office/shake.wav\ 16 | Office/system.wav 17 | 18 | EXTRA_DIST= $(classicsound_DATA) $(officesound_DATA) 19 | -------------------------------------------------------------------------------- /src/misc/sound/Office/Audio.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Office/Audio.wav -------------------------------------------------------------------------------- /src/misc/sound/Office/Global.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Office/Global.wav -------------------------------------------------------------------------------- /src/misc/sound/Office/msg.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Office/msg.wav -------------------------------------------------------------------------------- /src/misc/sound/Office/shake.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Office/shake.wav -------------------------------------------------------------------------------- /src/misc/sound/Office/system.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/sound/Office/system.wav -------------------------------------------------------------------------------- /src/misc/status/Makefile.am: -------------------------------------------------------------------------------- 1 | statusimgdir= ${pkgdatadir}/misc/status 2 | statusimg_DATA=online.png hidden.png offline.png away.png downarrow.png\ 3 | callme.png busy.png silent.png 4 | EXTRA_DIST = $(statusimg_DATA) 5 | -------------------------------------------------------------------------------- /src/misc/status/away.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/status/away.png -------------------------------------------------------------------------------- /src/misc/status/busy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/status/busy.png -------------------------------------------------------------------------------- /src/misc/status/callme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/status/callme.png -------------------------------------------------------------------------------- /src/misc/status/downarrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/status/downarrow.png -------------------------------------------------------------------------------- /src/misc/status/hidden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/status/hidden.png -------------------------------------------------------------------------------- /src/misc/status/offline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/status/offline.png -------------------------------------------------------------------------------- /src/misc/status/online.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/status/online.png -------------------------------------------------------------------------------- /src/misc/status/silent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/status/silent.png -------------------------------------------------------------------------------- /src/misc/webqq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/webqq.png -------------------------------------------------------------------------------- /src/misc/webqq_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kernelhcy/gtkqq/74f8acfacb0d17e1129efadb73f8adcf2160c993/src/misc/webqq_icon.png -------------------------------------------------------------------------------- /src/test/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS=-I${srcdir}/../libqq/ 2 | AM_CFLAGS+=-I${srcdir}/../comm/ 3 | AM_CFLAGS+=-I${srcdir}/../gui/ 4 | AM_CFLAGS+=${GLIB_CFLAGS} -DGTKQQ_DEBUG -Wall -Werror 5 | 6 | bin_PROGRAMS=testhttp testjson testcprint testlog testurl testpro testproxy 7 | 8 | testhttp_SOURCES= testhttp.c 9 | testhttp_LDADD=${srcdir}/../libqq/libwebqq.la $(GLIB_LIBS) 10 | 11 | testjson_SOURCES= testjson.c ${srcdir}/../libqq/json.c ${srcdir}/../libqq/json.h 12 | testjson_LDADD=$(GLIB_LIBS) 13 | 14 | testcprint_SOURCES= ${srcdir}/../comm/cprint.c testcprint.c 15 | testcprint_LDADD=${srcdir}/../libqq/libwebqq.la $(GLIB_LIBS) 16 | 17 | testlog_SOURCES= ${srcdir}/../comm/cprint.c ${srcdir}/../comm/log.c testlog.c 18 | testlog_LDADD=${srcdir}/../libqq/libwebqq.la $(GLIB_LIBS) 19 | 20 | testurl_SOURCES= ${srcdir}/../comm/log.c testurl.c ${srcdir}/../comm/cprint.c 21 | testurl_LDADD=${srcdir}/../libqq/libwebqq.la $(GLIB_LIBS) 22 | 23 | testpro_SOURCES= ${srcdir}/../comm/cprint.c testpro.c ${srcdir}/../comm/log.c 24 | testpro_LDADD=${srcdir}/../libqq/libwebqq.la $(GLIB_LIBS) 25 | 26 | testproxy_SOURCES=testproxy.c 27 | testproxy_LDADD=${srcdir}/../libqq/libwebqq.la $(GLIB_LIBS) 28 | -------------------------------------------------------------------------------- /src/test/test.json: -------------------------------------------------------------------------------- 1 | {"retcode":0,"result":{"uin":1421032531,"stat":"offline","vip_info":0,"nick":"\u963F\u51E1\u8FBE","country":"\u4E2D\u56FD","province":"\u9655\u897F","city":"\u897F\u5B89","gender":"male","face":519,"birthday":{"year":1988,"month":9,"day":26},"blood":1,"shengxiao":5,"constel":9,"phone":"","mobile":"-","email":"","occupation":"","college":"","homepage":"","personal":"nothing","allow":1}} 2 | -------------------------------------------------------------------------------- /src/test/testcprint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char **argv) 5 | { 6 | printf("Test cprint:\n"); 7 | cprintf(GREEN_F, BLUE_B, HIGHLIGHT, "green blue hithlight %s %d\n" 8 | , "hello", 234); 9 | cprintf(BLUE_F, UNSET_B, HIGHLIGHT, "blue unset hightlight %s %d\n" 10 | , "hello", 234); 11 | cprintf(YELLOW_F, UNSET_B, HIGHLIGHT, "yellow unset hightlight %s %d\n" 12 | , "hello", 234); 13 | cprintf(PURPLE_F, UNSET_B, HIGHLIGHT, "purple unset hightlight %s %d\n" 14 | , "hello", 234); 15 | cprintf(GREEN_F, UNSET_B, UNDERLINE, "green unset underline%s %d\n" 16 | , "hello", 234); 17 | cprintf(BLUE_F, UNSET_B, BLINKING, "blue unset blinking %s %d\n" 18 | , "hello", 234); 19 | cprintf(YELLOW_F, UNSET_B, REVERSE, "yellow unset reverse %s %d\n" 20 | , "hello", 234); 21 | cprintf(PURPLE_F, UNSET_B, HIDE, "purple unset hide %s %d\n" 22 | , "hello", 234); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/test/testhttp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char** argv) 6 | { 7 | Request* r = request_new(); 8 | request_set_method(r, "GET"); 9 | request_set_uri(r, "http://web.qq.com/hello.html?key=234"); 10 | request_set_version(r, "HTTP/1.1"); 11 | 12 | request_add_header(r, "Content-Lenght", "12345"); 13 | request_add_header(r, "Host", "web.qq.com"); 14 | 15 | gchar* s = "asdjfaslkdjfoqwiuertjakfdja;sldf"; 16 | request_append_msg(r, s, strlen(s)); 17 | request_append_msg(r, s, strlen(s)); 18 | request_append_msg(r, s, strlen(s)); 19 | request_append_msg(r, s, strlen(s)); 20 | request_append_msg(r, s, strlen(s)); 21 | request_append_msg(r, s, strlen(s)); 22 | 23 | print_raw(request_tostring(r)); 24 | g_printf("\n\n"); 25 | 26 | s = "HTTP/1.1 200 OK\r\n" 27 | "Date: Sun, 02 Jan 2011 19 19:09:55 GMT\r\n" 28 | "Server: Tencent Login Server/2.0.0\r\n" 29 | "Set-Cookie: pt2gguin=o0494498045; EXPIRES=Fri, 02-Jan-2020 00:00:00 GMT; PATH=/;DOMAIN=qq.com;\r\n" 30 | "Set-Cookie: uin=o0494498045; PATH=/; DOMAIN=qq.com;\r\n" 31 | "Set-Cookie: skey=@EK66ZxUe8; PATH=/; DOMAIN=qq.com;\r\n" 32 | "Set-Cookie: clientuin=; EXPIRES=Fri, 02-Jan-1970 00:00:00 GMT; PATH=/; DOMAIN=qq.com;\r\n" 33 | "Set-Cookie: clientkey=; EXPIRES=Fri, 02-Jan-1970 00:00:00 GMT; PATH=/; DOMAIN=qq.com;\r\n" 34 | "Set-Cookie: zzpaneluin=; EXPIRES=Fri, 02-Jan-1970 00:00:00 GMT; PATH=/; DOMAIN=qq.com;\r\n" 35 | "Set-Cookie: zzpanelkey=; EXPIRES=Fri, 02-Jan-1970 00:00:00 GMT; PATH=/; DOMAIN=qq.com;\r\n" 36 | "Set-Cookie: ptisp=edu;PATH=/; DOMAIN=qq.com;\r\n" 37 | "Set-Cookie:ptuserinfo=4b65726e656c;PATH=/;DOMAIN=ptlogin2.qq.com;\r\n" 38 | "Set-Cookie: ptwebqq=b16f2ca37c56d8a2ce064a9494cc85044e78ac6c480041c3f5be450206ab6728;" "PATH=/; DOMAIN=qq.com;\r\n" 39 | "Pragma: no-cache\r\n" 40 | "Cache-Control: no-cache; must-revalidate\r\n" 41 | "Connection: Close\r\n" 42 | "Content-Type: application/x-javascript; charset=utf-8\r\n"; 43 | Response* rps = response_new_parse(g_string_new(s)); 44 | g_printf("%s\n",response_tostring(rps) -> str); 45 | g_printf("\n\n"); 46 | print_raw(rps -> reason); 47 | print_raw(rps -> msg); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/test/testjson.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char ** argv) 8 | { 9 | gchar d[2000]; 10 | gchar *file; 11 | 12 | file = argv[1]; 13 | GString * input = g_string_new(NULL); 14 | FILE *fd = fopen(file, "r"); 15 | gsize len; 16 | while((len = fread(d, sizeof(gchar), 2000, fd)) > 0){ 17 | g_string_append_len(input, d, len); 18 | } 19 | 20 | fclose(fd); 21 | 22 | enum json_error error; 23 | json_t *json = NULL; 24 | error = json_parse_document(&json, input -> str); 25 | switch(error) 26 | { 27 | case JSON_OK: 28 | break; 29 | default: 30 | g_warning("json_parse_docuemt error."); 31 | break; 32 | } 33 | json_t *val; 34 | val = json_find_first_label_all(json, "year"); 35 | if(val != NULL){ 36 | g_debug("year: %s", val -> child -> text); 37 | } 38 | json_free_value(&json); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/test/testlog.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char ** argv) 6 | { 7 | log_init(); 8 | g_debug("debug %s %d\n", __FILE__, __LINE__); 9 | g_message("message %s %d\n", __FILE__, __LINE__); 10 | g_warning("warning %s %d\n", __FILE__, __LINE__); 11 | g_error("error %s %d\n", __FILE__, __LINE__); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /src/test/testpro.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | extern gint save_img_to_file(const gchar *data, gint len, const gchar *ext, 9 | const gchar *path, const gchar *fname); 10 | 11 | int main(int argc, char **argv) 12 | { 13 | const gchar *qquin = "1421032531"; 14 | const gchar *qqpwd = "1234567890"; 15 | gchar vc[20]; 16 | 17 | log_init(); 18 | g_message("Log initial done."); 19 | QQInfo *info = qq_init(NULL); 20 | qq_check_verifycode(info, qquin ,NULL); 21 | if(info -> need_vcimage){ 22 | save_img_to_file(info -> vc_image_data -> str, info -> vc_image_size 23 | , info -> vc_image_type -> str 24 | , "/home/hcy/tmp/gtkqq/" 25 | , "vc"); 26 | printf("Input verify code : "); 27 | int ret = scanf("%s", vc); 28 | assert( ret > 0 ); 29 | info -> verify_code = g_string_new(vc); 30 | } 31 | 32 | qq_login(info, qquin, qqpwd, "online", NULL); 33 | 34 | g_debug("poll..."); 35 | qq_start_poll(info, NULL, NULL, NULL); 36 | 37 | g_message("get my information..."); 38 | qq_get_buddy_info(info, info -> me, NULL); 39 | g_message("get my friends..."); 40 | qq_get_buddies_and_categories(info, NULL); 41 | g_message("get group name list mask..."); 42 | qq_get_groups(info, NULL); 43 | g_message("get group info..."); 44 | qq_get_group_info(info, (QQGroup*)g_ptr_array_index(info -> groups, 0), NULL); 45 | g_message("get online buddies..."); 46 | qq_get_online_buddies(info, NULL); 47 | g_message("get recent contact..."); 48 | qq_get_recent_contact(info, NULL); 49 | 50 | gchar buf[500]; 51 | while(1){ 52 | printf("MSG:"); 53 | int ret = scanf("%s", buf); 54 | assert( ret > 0 ); 55 | if(g_strcmp0("quit", buf) == 0){ 56 | break; 57 | } 58 | QQSendMsg *msg = qq_sendmsg_new(info, 0 //buddy message 59 | , ((QQBuddy*)(g_ptr_array_index(info -> buddies, 0))) -> uin -> str); 60 | QQMsgContent *ctent = qq_msgcontent_new(1, 62); 61 | qq_sendmsg_add_content(msg, ctent); 62 | ctent = qq_msgcontent_new(1, 51); 63 | qq_sendmsg_add_content(msg, ctent); 64 | ctent = qq_msgcontent_new(2, buf); 65 | qq_sendmsg_add_content(msg, ctent); 66 | ctent = qq_msgcontent_new(3, "宋体", 20, "0000FF", 1, 0, 1); 67 | qq_sendmsg_add_content(msg, ctent); 68 | qq_send_message(info, msg, NULL); 69 | qq_sendmsg_free(msg); 70 | } 71 | 72 | g_message("Will logout..."); 73 | qq_logout(info, NULL); 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /src/test/testproxy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | int main(int argc , char* argv[]) 10 | { 11 | if ( argc != 5 && argc != 3 && argc !=7 ) 12 | { 13 | printf("Usage : \n $ proxyip proxyport destip destport\n"); 14 | exit(1); 15 | } 16 | int sock = 0; 17 | if (argc == 5) 18 | { 19 | sock = get_authenticated_socket( argv[3],atoi(argv[4])); 20 | } 21 | else if (argc == 3) 22 | { 23 | set_relay(METHOD_DIRECT,NULL, 0, NULL,NULL); 24 | } 25 | else 26 | { 27 | set_relay(METHOD_HTTP, argv[1], atoi(argv[2]), argv[3], argv[4]); 28 | } 29 | sock = get_authenticated_socket(argv[1], atoi(argv[2])); 30 | 31 | if( sock == SOCKET_ERROR ) 32 | g_debug("Can not connect to server bypass proxy."); 33 | else{ 34 | g_debug("Succed to connect to server bypass proxy."); 35 | } 36 | close(sock); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/test/testurl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | int main(int argc, char ** argv) 5 | { 6 | log_init(); 7 | Connection *con = connect_to_host("web2.qq.com", 80); 8 | if(con == NULL){ 9 | return 0; 10 | } 11 | Request *r = request_new(); 12 | request_set_method(r, "GET"); 13 | request_set_uri(r, "/"); 14 | request_set_version(r, "HTTP/1.1"); 15 | request_set_default_headers(r); 16 | // request_add_header(r, "Proxy-Authorization", "Basic " 17 | // "YWNtOjEyMzQ1Njc4OTBhIQ=="); 18 | // request_add_header(r, "Proxy-Connection", "keep-alive"); 19 | request_add_header(r, "host", "web2.qq.com"); 20 | 21 | if(send_request(con, r) < 0){ 22 | close_con(con); 23 | return 0; 24 | } 25 | Response *rps = NULL; 26 | if(rcv_response(con, &rps) < 0){ 27 | close_con(con); 28 | return 0; 29 | } 30 | g_debug("read the response"); 31 | g_debug("%s", response_tostring(rps) -> str); 32 | printf("MESSAGE: %s", rps -> msg -> str); 33 | close_con(con); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/tool/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS=unidecode 2 | unidecode_CPPFLAGS= $(GTK_CFLAGS) 3 | unidecode_LDADD= $(GTK_LIBS) 4 | unidecode_SOURCES=unidecode.c 5 | -------------------------------------------------------------------------------- /src/tool/unidecode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static guint hex2char(gchar c) 6 | { 7 | if(c >= '0' && c <= '9'){ 8 | return c - '0'; 9 | } 10 | 11 | if(c >= 'a' && c <= 'f'){ 12 | return c - 'a' + 10; 13 | } 14 | 15 | if(c >= 'A' && c <= 'F'){ 16 | return c - 'A' + 10; 17 | } 18 | return 0; 19 | } 20 | 21 | static void decodeunicode(GString *to, const gchar *from) 22 | { 23 | if(to == NULL || from == NULL){ 24 | return; 25 | } 26 | if(from[0] != '\\' || from[1] != 'u'){ 27 | return; 28 | } 29 | 30 | static guint E = 0xe0; 31 | static guint T = 0x2;; 32 | 33 | guint tmp[4]; 34 | gchar re[3]; 35 | 36 | gint i; 37 | for(i = 0; i < 4; ++i){ 38 | tmp[i] = 0xf & hex2char(from[ i + 2]); 39 | } 40 | 41 | //decode 42 | re[0] = E | (tmp[0] & 0xf); 43 | re[1] = (T << 6) | (tmp[1] << 2) | ((tmp[2] >> 2) & 0x3); 44 | re[2] = (T << 6) | (tmp[2] & 0x3) << 4 | tmp[3]; 45 | 46 | //copy to @to. 47 | for(i = 0; i < 3; ++i){ 48 | g_string_append_c(to, re[i]); 49 | } 50 | } 51 | 52 | #define BUFSIZE 100 53 | int main(int argc, char **argv) 54 | { 55 | gchar buf[BUFSIZE]; 56 | gchar *file; 57 | 58 | file = argv[1]; 59 | 60 | GString * input = g_string_new(NULL); 61 | 62 | FILE *fd = fopen(file, "r"); 63 | gsize len; 64 | while((len = fread(buf, sizeof(gchar), BUFSIZE, fd)) > 0){ 65 | g_string_append_len(input, buf, len); 66 | } 67 | 68 | fclose(fd); 69 | GString *out = g_string_new(NULL); 70 | 71 | gint i; 72 | for(i = 0; input -> str[i] != '\0'; ++i){ 73 | if(input -> str[i] == '\\' && input -> str[i + 1] == 'u'){ 74 | decodeunicode(out, input -> str + i); 75 | i += 5; 76 | }else{ 77 | g_string_append_c(out, input -> str[i]); 78 | } 79 | } 80 | 81 | g_printf("%s\n", out -> str); 82 | g_string_free(out, TRUE); 83 | 84 | return 0; 85 | } 86 | 87 | 88 | -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | 1.登录,登出。 2 | 2.读取好友的信息和分组信息。 3 | 3.接收和发送好友消息,消息中包括表情和字体设置。 4 | 4.读取群信息和群成员信息。 5 | 5.接收和发送群消息,消息中包括表情和字体设置。 6 | 6. notification sound 7 | 8 | done 9 | -------- 10 | todo 11 | 12 | 1.获取等级 13 | 2.修改个人信息,好友备注等。 14 | 3.接收和发送图片。 15 | 4.接收和发送文件。 16 | 5. Login and message transmittion with proxy. 17 | --------------------------------------------------------------------------------