libofetion-2.2.2/0000755000175000017500000000000011700115547012330 5ustar aronaronlibofetion-2.2.2/fetion_types.h0000644000175000017500000003675411700115314015220 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_TYPES_H #define FETION_TYPES_H /* inline function to trace program track */ #ifdef UNUSED #elif defined(__GNUC__) # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) #else # define UNUSED(x) x #endif #define FETION_NAME "OpenFetion" #define FETION_VERSION "" #define PROTO_VERSION "4.3.0980" #define NAVIGATION_URI "nav.fetion.com.cn" #define PGGROUP_SPACE_URI "http://group.feixin.10086.cn/space/Index/" #define LOGIN_TYPE_FETIONNO 1 #define LOGIN_TYPE_MOBILENO 0 #define BOUND_MOBILE_ENABLE 1 #define BOUND_MOBILE_DISABLE 0 #define BASIC_SERVICE_NORMAL 1 #define BASIC_SERVICE_ABNORMAL 0 #define CARRIER_STATUS_OFFLINE -1 #define CARRIER_STATUS_NORMAL 0 #define CARRIER_STATUS_DOWN 1 #define CARRIER_STATUS_CLOSED 2 #define RELATION_STATUS_AUTHENTICATED 1 #define RELATION_STATUS_UNAUTHENTICATED 0 #define SERVICE_DOWN_MESSAGE "您目前无法使用此功能\n\n您的手机已停机,无法使\n用手机相关功能,请缴费\n后重试" /** * some other buddylists */ typedef enum { BUDDY_LIST_NOT_GROUPED = 0 , BUDDY_LIST_STRANGER = -1 , BUDDY_LIST_PGGROUP = -2 } BuddyListType; /** * Presence states */ typedef enum { P_ONLINE = 400 , P_RIGHTBACK = 300 , P_AWAY = 100 , P_BUSY = 600 , P_OUTFORLUNCH = 500 , P_ONTHEPHONE = 150 , P_MEETING = 850 , P_DONOTDISTURB = 800 , P_HIDDEN = 0 , P_OFFLINE = -1 } StateType; /** * Type used to indicate whether user`s portrait has been changed */ typedef enum { IMAGE_NOT_INITIALIZED = -1 , /* portrait has not been initialized */ IMAGE_NOT_CHANGED , /* portrait does not change */ IMAGE_CHANGED , /* portrait has been changed */ IMAGE_ALLREADY_SET } ImageChangedType; /** * Type to indicate user`s service status */ typedef enum { STATUS_NORMAL = 1 , /* normal status */ STATUS_OFFLINE , /* user offline , deleted you from his list or out of service*/ STATUS_NOT_AUTHENTICATED , /* user has not accept your add buddy request */ STATUS_SMS_ONLINE , /* user has not start fetion service */ STATUS_REJECTED , /* user rejected your add buddy request,wait for deleting */ STATUS_SERVICE_CLOSED , /* user has closed his fetion service */ STATUS_NOT_BOUND /* user doesn`t bound fetion number to a mobile number */ } StatusType; /** * Two-way linked list that can contans any types */ typedef struct fxlist { struct fxlist *pre; void *data; struct fxlist *next; } FxList; /** * Fetion Connection */ typedef struct { int socketfd; /* socket file descriptor*/ char local_ipaddress[16]; /* local ip address */ int local_port; /* local port */ char remote_ipaddress[16]; /* remote ip address */ int remote_port; /* remote port */ SSL* ssl; /* SSL handle */ SSL_CTX* ssl_ctx; /* SSL ctx struct */ } FetionConnection; /** * Sip header that in form of "name: value" such as "AK: ak-value" */ typedef struct sipheader { char name[8]; /* sip header namne*/ char *value; /* sip header value*/ struct sipheader *next; /* next sip header */ } SipHeader; /** * Sip type include some common attributes */ typedef struct { int type; /* sip message type */ char from[20]; /* sender`s fetion no ,in sip it`s "F: " */ int callid; int sequence; /* sequence number , in sip it`s "Q: " */ int threadCount; /* listening threads count using this sip */ char sipuri[48]; /* outer sipuri used when listening */ SipHeader* header; /* some othre header list */ FetionConnection* tcp; /* fetion connection used to send message */ } FetionSip; /** * Sip message list that parsed from received chunk */ typedef struct sipmsg { char *message; struct sipmsg *next; } SipMsg; /** * Contact lists information (Two-way linked list) */ typedef struct contact { char userId[16]; /* userid used since v4 protocal */ char sId[16]; /* fetion no */ char sipuri[48]; /* sipuri like 'sip:100@fetion.com.cn' */ char localname[256]; /* name set by yourself */ char nickname[256]; /* user`s nickname */ char impression[2048]; /* user`s mood phrase */ char mobileno[12]; /* mobile phone number */ char devicetype[10]; /* user`s client type , like PC and J2ME,etc */ char portraitCrc[12]; /* a number generated by crc algorithm */ char birthday[16]; /* user`s bitrhday */ char country[6]; /* user`s country`s simplified form,like CN */ char province[6]; /* user`s province`s simplified form,like bj */ char city[6]; /* user`s city`s code ,like 10 for beijing */ int identity; /* whethere to show mobileno to this user */ int scoreLevel; /* user`s score level,unused now */ int serviceStatus; /* basic service status */ int carrierStatus; int relationStatus; char carrier[16]; StateType state; /* state type like online,busy,etc */ char groupids[48]; int groupid; /* buddylist id */ int gender; /* gender 1 for male 2 for female,0 for private */ int imageChanged; /* whether user`s portrait has changed */ int dirty; /* whether the contact just read from the server is newer than that int the local disk */ struct contact* next; struct contact* pre; } Contact; /** * Buddy lists information (Two-way linked list) */ typedef struct group { char groupname[32]; /* current buddy list name */ int groupid; /* current buddy list Id */ int dirty; struct group *next; struct group *pre; } Group; typedef struct pggroupmember { char sipuri[64]; char nickname[256]; char clientType[64]; char userId[16]; int state; int identity; int getContactInfoCallId; Contact *contact; struct pggroupmember *next; struct pggroupmember *pre; } PGGroupMember; typedef struct pggroup { char pguri[64]; char name[256]; int statusCode; int category; int currentMemberCount; int limitMemberCount; int groupRank; int maxRank; int identity; int hasAcked; int hasDetails; int hasImage; int inviteCallId; int getMembersCallId; char createTime[48]; char bulletin[1024]; char summary[1024]; char getProtraitUri[1024]; PGGroupMember *member; struct pggroup *next; struct pggroup *pre; } PGGroup; /** * Verification information used for picture code confirm */ typedef struct { char *algorithm; char *type; char *text; char *tips; char *code; char *guid; } Verification; /** * User list store in local data file (One-way linked list) */ struct userlist { char no[24]; /* fetion no or mobile no */ char password[48]; /* password */ char userid[48]; char sid[48]; int laststate; /* last state when logining */ int islastuser; /* is the last logined user */ struct userlist *pre; struct userlist *next; /* next User node */ }; /** * structure used to describe global proxy information */ typedef struct { int proxyEnabled; /* whether http proxy is enable */ char proxyHost[48]; /* proxy host name or ip address */ int proxyPort; /* port number of proxy server */ char proxyUser[48]; /* username for proxy authentication */ char proxyPass[48]; /* password for proxy authentication */ } Proxy; /* for close action */ #define CLOSE_ALERT_ENABLE 0 #define CLOSE_ALERT_DISABLE 1 /* for nitification action */ #define MSG_ALERT_ENABLE 0 #define MSG_ALERT_DISABLE 1 /** * Configuration information */ typedef struct { char globalPath[256]; /* global path,default $(HOME)/.openfetion */ char userPath[256]; /* user path , directory name by user`s sid in globalPath */ char iconPath[256]; /* path stores user`s friend portraits in user`s path */ char sipcProxyIP[20]; /* sipc proxy server`s ip ,read from configuration.xml */ int sipcProxyPort; /* sipc proxy server`s port , read from configuration.xml */ char portraitServerName[48]; /* portrait server`s hostname ,read from configuration.xml*/ char portraitServerPath[32]; /* portrait server`s path , such as /HD_POOL8 */ int iconSize; /* portrait`s display size default 25px */ int closeAlert; /* whether popup an alert when quiting */ int autoReply; /* whether auto reply enabled */ int isMute; char autoReplyMessage[180]; /* auto reply message content */ int msgAlert; int autoPopup; /* whether auto pupup chat dialog enabled */ int sendMode; /* press enter to send message or ctrl + enter */ int closeMode; /* close button clicked to close window or iconize it */ int canIconify; int allHighlight; int autoAway; int autoAwayTimeout; int onlineNotify; int closeSysMsg; int closeFetionShow; int useStatusIcon; int window_width; int window_height; int window_pos_x; int window_pos_y; char configServersVersion[16]; /* the version of some related servers such as sipc server */ char configParametersVersion[16]; char configHintsVersion[16]; /* the version of hints */ struct userlist* ul; /* user list stored in local data file */ Proxy *proxy; /* structure stores the global proxy information */ } Config; /** * User`s personal information and some related structs */ typedef struct { char sId[16]; /* fetion number */ char userId[16]; /* user id */ char mobileno[16]; /* mobile phone number */ char password[48]; /* raw password not hashed */ char sipuri[48]; /* sipuri like 'sip:100@fetion.com.cn' */ char publicIp[32]; /* public ip of current session */ char lastLoginIp[32]; /* public ip of last login */ char lastLoginTime[48]; /* last login time , got after sipc authentication */ char personalVersion[16]; /* the version of personal information */ char contactVersion[16]; /* the version of contact information */ char customConfigVersion[16]; /* the version of custom config string,unused now */ char nickname[48]; /* nickname of yourself */ char impression[256]; /* mood phrase of yourself */ char portraitCrc[16]; /* a number generated by crc algorithm */ char country[6]; /* the country which your number belongs to */ char province[6]; /* the province which your number belongs to */ char city[6]; /* the city which your number belongs to */ int gender; /* the gender of your self */ char smsOnLineStatus[32]; int smsDayLimit; int smsDayCount; int smsMonthLimit; int smsMonthCount; int pgGroupCallId; /* callid for get group list request */ int groupInfoCallId; /* callid for get group info request */ int state; /* presence state */ int loginType; /* using sid or mobileno */ int loginStatus; /* login status code */ int carrierStatus; int boundToMobile; /* whether this number is bound to a mobile number */ long loginTimes; int contactCount; int groupCount; char* ssic; /* cookie string read from reply message after ssi login */ char* customConfig; /* custom config string used to set personal information */ Verification* verification; /* a struct used to generate picture code */ Contact* contactList; /* friend list of current user */ Group* groupList; /* buddylist list of current user */ PGGroup* pggroup; /* group list */ Config* config; /* config information */ FetionSip* sip; /* sip object used to handle sip event */ } User; /** * structure used to describe onversation information */ typedef struct { Contact *currentContact; /* current friend who you a chating with */ User *currentUser; /* current user,ourselves */ FetionSip *currentSip; /* sip struct used to send message * NULL if did not start a chat channel for this conversation */ } Conversation; /** * structure used to describe message information */ typedef struct { char *message; /* message content */ char *sipuri; /* sender`s sip uri */ char *pguri; int callid; int sysback; struct tm sendtime; /* message sent time */ } Message; /** * structure used to describe chat history */ typedef struct { char name[48]; /* name of message sender */ char userid[16]; /* userid of message sender */ char sendtime[32]; /* message sent time */ char message[4096]; /* message content */ int issend; /* message is sent of received*/ } History; typedef struct { User* user; sqlite3 *db; } FetionHistory; #define FILE_RECEIVE 1 #define FILE_SEND 2 #define FILE_ACCEPTED 1 #define FILE_DECLINED 2 typedef struct { FetionSip *sip; int shareMode; int shareState; char guid[64]; char sessionid[64]; char absolutePath[1024]; char filename[64]; char sipuri[64]; char md5[64]; long long filesize; char preferType[8]; char innerIp[24]; int innerUdpPort; int innerTcpPort; char outerIp[24]; int outerUdpPort; int outerTcpPort; } Share; struct unacked_list { int timeout; Message *message; struct unacked_list *next; struct unacked_list *pre; }; #endif libofetion-2.2.2/CMakeLists.txt0000644000175000017500000000760011700115314015063 0ustar aronaronproject(libofetion) cmake_minimum_required(VERSION 2.6) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules) set(TARNAME libofetion) # program name, version etc set(LIBOFETION_API_VERSION "1.2.0") set(LIBOFETION_ABI_VERSION "1.1.0") set(LIBOFETION_ABI_MAJOR_VERSION "1") set(PACKAGE_VERSION "2.2.0") set(PACKAGE_NAME "${TARNAME}") set(PACKAGE_TARNAME "${TARNAME}") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "http://code.google.com/p/ofetion/issues/list") find_package(PkgConfig REQUIRED) if(NOT DEFINED BIN_INSTALL_DIR) set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin") endif(NOT DEFINED BIN_INSTALL_DIR) if(NOT DEFINED LIB_INSTALL_DIR) set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib") endif(NOT DEFINED LIB_INSTALL_DIR) if(NOT DEFINED DATA_INSTALL_DIR) set(DATA_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share") endif(NOT DEFINED DATA_INSTALL_DIR) if(NOT DEFINED INCLUDE_INSTALL_DIR) set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/${PACKAGE_TARNAME}") endif(NOT DEFINED INCLUDE_INSTALL_DIR) if(NOT DEFINED MAN_INSTALL_DIR) set(MAN_INSTALL_DIR "${DATA_INSTALL_DIR}/man") endif(NOT DEFINED MAN_INSTALL_DIR) if(NOT DEFINED RESOURCE_INSTALL_DIR) set(RESOURCE_INSTALL_DIR "${DATA_INSTALL_DIR}/libofetion${LIBOFETION_ABI_MAJOR_VERSION}/resource/") endif(NOT DEFINED RESOURCE_INSTALL_DIR) if(NOT DEFINED LOCALE_INSTALL_DIR) set(LOCALE_INSTALL_DIR "${DATA_INSTALL_DIR}/locale/") endif(NOT DEFINED LOCALE_INSTALL_DIR) add_definitions(-DRESOURCE_DIR="${RESOURCE_INSTALL_DIR}") install( FILES resource/city.xml resource/province.xml DESTINATION ${RESOURCE_INSTALL_DIR} ) pkg_check_modules(LIBXML2 REQUIRED libxml-2.0) pkg_check_modules(OPENSSL REQUIRED openssl) pkg_check_modules(SQLITE3 REQUIRED sqlite3) # gnu ld version script set(_link_flags " ") if(CMAKE_COMPILER_IS_GNUCXX) include(TestCXXAcceptsFlag) set(_version_script "${CMAKE_CURRENT_SOURCE_DIR}/./libofetion.map") check_cxx_accepts_flag("-Wl,--version-script,${_version_script}" LD_ACCEPTS_VERSION_SCRIPT) if(LD_ACCEPTS_VERSION_SCRIPT) set(_link_flags "${_link_flags} -Wl,--version-script,'${_version_script}'") endif(LD_ACCEPTS_VERSION_SCRIPT) endif(CMAKE_COMPILER_IS_GNUCXX) ########################################################################## add_definitions(-g -Wall -Wextra) ########################################################################## include_directories( ${LIBXML2_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS} ${SQLITE3_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) set(libofetion_SRC ./fetion_buddylist.c ./fetion_config.c ./fetion_connection.c ./fetion_contact.c ./fetion_conversation.c ./fetion_debug.c ./fetion_directsms.c ./fetion_group.c ./fetion_history.c ./fetion_list.c ./fetion_login.c ./fetion_message.c ./fetion_share.c ./fetion_sip.c ./fetion_user.c ) add_library(ofetion SHARED ${libofetion_SRC}) target_link_libraries(ofetion ${LIBXML2_LIBRARIES} ${OPENSSL_LIBRARIES} ${SQLITE3_LIBRARIES}) set_target_properties(ofetion PROPERTIES VERSION ${LIBOFETION_ABI_VERSION} SOVERSION ${LIBOFETION_ABI_MAJOR_VERSION} LINK_FLAGS ${_link_flags} ) add_library(ofetion-static STATIC ${libofetion_SRC}) SET_TARGET_PROPERTIES(ofetion-static PROPERTIES OUTPUT_NAME "ofetion") SET_TARGET_PROPERTIES(ofetion-static PROPERTIES PREFIX "lib") install(TARGETS ofetion ofetion-static LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR}) file(GLOB ofetion_INCLUDES "./*.h") install(FILES ${ofetion_INCLUDES} DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel) ########################################################################## configure_file(./ofetion.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/ofetion.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ofetion.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) libofetion-2.2.2/resource/0000755000175000017500000000000011700115314014147 5ustar aronaronlibofetion-2.2.2/resource/province.xml0000644000175000017500000000303211700115314016514 0ustar aronaron 北京市 上海市 天津市 重庆市 安徽省 福建省 广东省 甘肃省 广西自治区 贵州省 河北省 湖北省 黑龙江省 海南省 河南省 湖南省 吉林省 江苏省 江西省 辽宁省 内蒙古自治区 宁夏自治区 青海省 四川省 山东省 山西省 陕西省 新疆自治区 西藏自治区 云南省 浙江省 台湾 香港特别行政区 澳门特别行政区 香港特别行政区 libofetion-2.2.2/resource/city.xml0000644000175000017500000003126711700115314015652 0ustar aronaron 北京 其他 天津 其他 上海 其他 香港 其他 重庆 其他 其他 石家庄 保定 沧州 承德 邯郸 衡水 廊坊 秦皇岛 唐山 邢台 张家口 其他 太原 长治 大同 晋城 离石 临汾 朔州 忻州 阳泉 榆次 运城 其他 呼和浩特 阿拉善左旗 包头 赤峰 东胜 海拉尔 集宁 临河 乌兰浩特 通辽 乌海 锡林浩特 其他 沈阳 鞍山 本溪 朝阳 大连 丹东 抚顺 阜新 葫芦岛 锦州 辽阳 盘锦 铁岭 营口 其他 长春 白城 白山 吉林 辽源 梅河口 四平 松原 通化 延吉 其他 哈尔滨 大庆 大兴安岭 鹤岗 黑河 鸡西 佳木斯 牡丹江 七台河 齐齐哈尔 双鸭山 绥化 伊春 其他 南昌 抚州 赣州 吉安 景德镇 九江 萍乡 上饶 新余 宜春 鹰潭 其他 杭州 湖州 嘉兴 金华 丽水 宁波 衢州 绍兴 台州 温州 舟山 其他 南京 常州 淮安 连云港 南通 苏州 宿迁 泰州 无锡 徐州 盐城 扬州 张家港 镇江 其他 合肥 安庆 蚌埠 巢湖 池州 滁州 阜阳 淮北 黄山 六安 马鞍山 宿州 铜陵 芜湖 宣城 准南 其他 福州 龙岩 南平 宁德 莆田 泉州 三明 厦门 漳州 其他 济南 滨州 德州 东营 菏泽 济宁 莱芜 聊城 临沂 青岛 日照 泰安 威海 潍坊 烟台 枣庄 淄博 其他 郑州 安阳 鹤壁 潢川 焦作 开封 洛阳 漯河 南阳 平顶山 濮阳 三门峡 商丘 新乡 信阳 许昌 周口 驻马店 其他 武汉 鄂州 恩施 洪湖 黄冈 黄石 荆门 荆州 十堰 随州 咸宁 襄樊 孝感 宜昌 其他 长沙 常德 郴州 衡阳 怀化 吉首 娄底 邵阳 湘潭 益阳 永州 岳阳 张家界 株洲 其他 广州 潮阳 潮州 东莞 佛山 河源 惠州 江门 揭阳 茂名 梅州 清远 汕头 汕尾 韶关 深圳 顺德 阳江 云浮 湛江 肇庆 中山 珠海 其他 南宁 百色 北海 防城港 桂林 河池 柳州 钦州 梧州 玉林 其他 海口 儋州 三亚 其他 成都 巴中 达川 德阳 广安 广元 康定 乐山 泸州 马尔康 绵阳 内江 南充 攀枝花 遂宁 西昌 雅安 宜宾 自贡 其他 贵阳 安顺 毕节 都匀 凯里 六盘水 铜仁 兴义 遵义 其他 昆明 保山 楚雄 大理 德宏 迪庆 东川 个旧 丽江 临沧 六库 曲靖 思茅 文山 西双版纳 玉溪 昭通 其他 拉萨 阿里 昌都 林芝 那曲 日喀则 山南 其他 西安 安康 宝鸡 汉中 商州 铜川 渭南 咸阳 延安 榆林 其他 兰州 白银 定西 甘南州 酒泉 临夏 平凉 天水 武都 武威 西峰 张掖 其他 银川 固原 石嘴山 吴忠 其他 西宁 德令哈 格尔木 共和 海东 海晏 玛沁 门源 同仁 玉树 其他 乌鲁木齐 阿克苏 阿勒泰 阿图什 博乐 昌吉 哈密 和田 喀会 喀什 克拉玛依 库尔勒 奎屯 石河子 塔城 吐鲁番 伊宁 其他 其他 其他 libofetion-2.2.2/openfetion.h0000644000175000017500000000632411700115314014644 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef OPENFETION_H #define OPENFETION_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #define _XOPEN_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __cplusplus } #endif #endif libofetion-2.2.2/ofetion.pc.cmake0000644000175000017500000000045511700115314015372 0ustar aronaronprefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${BIN_INSTALL_DIR} libdir=${LIB_INSTALL_DIR} includedir=${INCLUDE_INSTALL_DIR} Name: ofetion Description: Fetion Protocol Library Requires: libxml-2.0 openssl Version: ${PACKAGE_VERSION} Libs: -L${LIB_INSTALL_DIR} -lofetion Cflags: -I${INCLUDE_INSTALL_DIR} libofetion-2.2.2/libofetion.map0000644000175000017500000000101711700115534015154 0ustar aronaronVERS_1.2.0 { global: fetion_*; generate_*; pg_group_*; fx_*; debug_*; sipc_*; parse_*; tcp_connection_*; unacked*; convert_date; get_currenttime; ssi_auth_action; contruct_message_sip; local: *; }; VERS_1.0.0 { global: fetion_*; generate_*; pg_group_*; fx_*; debug_*; sipc_*; parse_*; tcp_connection_*; unacked*; hash_password*; convert_date; get_currenttime; ssi_auth_action; contruct_message_sip; local: *; }; libofetion-2.2.2/fetion_user.h0000644000175000017500000001604711700115314015023 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_USER_H #define FETION_USER_H #define STATE_ONLINE 400 #define STATE_RIGHTBACK 300 #define STATE_AWAY 100 #define STATE_BUSY 600 #define STATE_OUTFORLUNCH 500 #define STATE_ONTHEPHONE 150 #define STATE_MEETING 850 #define STATE_DONOTDISTURB 800 #define STATE_HIDDEN 0 #define STATE_NOTAPRESENCE -1 #define USER_AUTH_NEED_CONFIRM(u) ((u)->loginStatus == 421 || (u)->loginStatus == 420) #define USER_AUTH_ERROR(u) ((u)->loginStatus == 401 || (u)->loginStatus == 400 || (u)->loginStatus == 404) /** * create a User object and initialize it with number and password * @no Phone number or Fetion number * @password Nothing special , just your fetion password * @return The user object created */ extern User* fetion_user_new(const char *no, const char *password); extern void fetion_user_set_userid(User *user, const char *userid); extern void fetion_user_set_sid(User *user, const char *sId); extern void fetion_user_set_mobileno(User *user, const char *mobileno); extern void fetion_user_set_password(User *user, const char *password); extern void fetion_user_set_sip(User *user, FetionSip *sip); extern void fetion_user_set_config(User *user, Config *config); extern void fetion_user_set_verification_code(User *user, const char *code); extern int fetion_user_init_config(User *user); extern void fetion_user_free(User *user); /** * upload portrait * @param user Global User object * @param filename The absolute filepath of the portrait file to be uploaded * @return 1 if success , or else -1 */ extern int fetion_user_upload_portrait(User *user, const char *filename); /** * download portrait of specified user * @param user Global User object * @param sipuri sip uri of the user whose portrait will be downloaded * @return 1 if success, or else -1 */ extern int fetion_user_download_portrait(User *user, const char *sipuri); /** * download portrait of specified sipuri with * the specified server name and server path of the portrait server * @param user Global User object * @param sipuri sip uri of the user(or Feiton Group) whose portrait will be downloaded * @param server The host name of the portrait server * @param portraitPath The uri path of the portrait server,like '/HD00S/getportrait.aspx' * @return 1 if success , or else -1 */ extern int fetion_user_download_portrait_with_uri(User *user, const char *sipuri, const char *server, const char *portraitPath); /** * modify the user`s online state such as 'Online' , 'Busy' , etc.. * @param user Global User object * @param state The online state type * @return 1 if success , or else -1 */ extern int fetion_user_set_state(User *user, StateType state); /** * modify the user`s personal signature * @param user Global User object * @param moodphrase The new personal signature string * @return 1 if success , or else -1 */ extern int fetion_user_set_moodphrase(User *user, const char *moodphrase); /** * reload the user`s detail information from the sipc server * @param user Global User object * @return 1 if success , or else -1 */ extern int fetion_user_update_info(User *user); /** * send a keep-alive message to the sipc server to tell that the client * is not offline.This function should be called periodically. * @param user Global User object * @return 1 if success , or else -1 */ extern int fetion_user_keep_alive(User *user); /** * traverse the two-way linked list of user group * @param head the list header * @param gl the list cursor */ #define foreach_grouplist(head , gl) \ for(gl = head ; (gl = gl->next) != head ;) /** * construct a double-linked list to store the group information */ extern Group* fetion_group_new(); /** * append a new group to the group list */ extern void fetion_group_list_append(Group *head, Group *group); /** * prepend a new group to the group list */ extern void fetion_group_list_prepend(Group *head, Group *group); /** * remove a specified group from the group list * @param group the group to be removed */ extern void fetion_group_list_remove(Group *group); /** * remove a group from the list with the specified group id */ extern void fetion_group_remove(Group *head, int groupid); /** * find a group from the list with the specified group id */ extern Group* fetion_group_list_find_by_id(Group *head, int id); extern Verification* fetion_verification_new(); extern void fetion_verification_free(Verification *ver); extern Contact* fetion_user_parse_presence_body(const char *body, User *user); extern Contact* fetion_user_parse_syncuserinfo_body(const char *body, User *user); extern int fetion_user_set_sms_status(User *user, int days); extern void fetion_user_save(User *user); extern void fetion_user_load(User *user); static inline void fetion_user_set_st(User *user, int state){ user->state = state; } #endif libofetion-2.2.2/fetion_user.c0000644000175000017500000007567211700115314015027 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include #include struct unacked_list *unackedlist; static int fetion_user_download_portrait_again(const char* filepath , const char* buf , Proxy *proxy); static char* generate_set_state_body(StateType state); static char* generate_set_moodphrase_body(const char* customConfigVersion , const char* customConfig , const char* personalVersion , const char* moodphrase); static char* generate_update_information_body(User* user); static char* generate_keep_alive_body(); static void parse_set_moodphrase_response(User* user , const char* sipmsg); static char* generate_set_sms_status_body(int days); static void parse_set_sms_status_response(User *user , const char *sipmsg); User* fetion_user_new(const char* no , const char* password) { User* user = (User*)malloc(sizeof(User)); struct sigaction sa; sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, 0 ); memset(user , 0 , sizeof(User)); if(strlen(no) == 11){ strcpy(user->mobileno , no); user->loginType = LOGIN_TYPE_MOBILENO; }else{ strcpy(user->sId , no); user->loginType = LOGIN_TYPE_FETIONNO; } strcpy(user->password , password); user->contactList = fetion_contact_new(); user->groupList = fetion_group_new(); user->pggroup = NULL; user->sip = NULL; user->verification = NULL; user->customConfig = NULL; user->ssic = NULL; user->config = NULL; unackedlist = unacked_list_new(NULL); return user; } void fetion_user_set_userid(User* user, const char* userid1) { strcpy(user->userId, userid1); } void fetion_user_set_sid(User* user, const char* sId1) { strcpy(user->sId, sId1); } void fetion_user_set_mobileno(User* user , const char* mobileno1) { strcpy(user->mobileno , mobileno1); } void fetion_user_set_password(User *user, const char *password) { strcpy(user->password, password); user->password[strlen(password)] = '\0'; } void fetion_user_set_sip(User* user , FetionSip* sip1) { debug_info("Set a initialized Sip Struct to User"); user->sip = sip1; } void fetion_user_set_config(User* user , Config* config1) { debug_info("Set a initialized Config Struct to User"); user->config = config1; } void fetion_user_set_verification_code(User* user , const char* code) { user->verification->code = (char*)malloc(strlen(code) + 1); memset(user->verification->code , 0 , strlen(code) + 1); strcpy(user->verification->code , code); } int fetion_user_init_config(User *user) { assert(user != NULL); assert(user->config != NULL); assert(*(user->userId) != '\0'); return fetion_config_initialize(user->config, user->userId); } void fetion_user_free(User* user) { if(user->ssic != NULL) free(user->ssic); if(user->customConfig != NULL) free(user->customConfig); if(user->verification != NULL) fetion_verification_free(user->verification); if(user->sip != NULL) fetion_sip_free(user->sip); if(user->config != NULL) fetion_config_free(user->config); free(user); } int fetion_user_set_state(User* user , StateType state) { SipHeader* eheader; FetionSip* sip = user->sip; char* body; char* res; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_SETPRESENCE); fetion_sip_add_header(sip , eheader); body = generate_set_state_body(state); res = fetion_sip_to_string(sip , body); tcp_connection_send(sip->tcp , res , strlen(res)); user->state = state; free(body); free(res); debug_info("User state changed to %d" , state); return 1; } int fetion_user_set_moodphrase(User* user , const char* moodphrase) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; int ret; fetion_sip_set_type(sip , SIP_SERVICE); debug_info("Start seting moodphrase"); eheader = fetion_sip_event_header_new(SIP_EVENT_SETUSERINFO); fetion_sip_add_header(sip , eheader); body = generate_set_moodphrase_body(user->customConfigVersion , user->customConfig , user->personalVersion , moodphrase); res = fetion_sip_to_string(sip , body); free(body); tcp_connection_send(sip->tcp , res , strlen(res)); free(res) ; res = fetion_sip_get_response(sip); ret = fetion_sip_get_code(res); if(ret == 200){ parse_set_moodphrase_response(user , res); free(res); debug_info("Set moodphrase success"); return 1; }else{ free(res); debug_error("Set moodphrase failed , errno :" , ret); return -1; } } int fetion_user_update_info(User* user) { FetionSip* sip = user->sip; SipHeader* eheader = NULL; char *res , *body; int ret; fetion_sip_set_type(sip , SIP_SERVICE); debug_info("Start Updating User Information"); eheader = fetion_sip_event_header_new(SIP_EVENT_SETUSERINFO); fetion_sip_add_header(sip , eheader); body = generate_update_information_body(user); res = fetion_sip_to_string(sip , body); free(body); tcp_connection_send(sip->tcp , res , strlen(res)); free(res) ; res = fetion_sip_get_response(sip); ret = fetion_sip_get_code(res); if(ret == 200){ free(res); debug_info("Update information success"); return 1; }else{ free(res); debug_error("Update information failed , errno :" , ret); return -1; } } int fetion_user_keep_alive(User* user) { FetionSip* sip = user->sip; SipHeader* eheader = NULL; int ret; char *res = NULL , *body = NULL; fetion_sip_set_type(sip , SIP_REGISTER); debug_info("send a keep alive request"); eheader = fetion_sip_event_header_new(SIP_EVENT_KEEPALIVE); fetion_sip_add_header(sip , eheader); body = generate_keep_alive_body(); res = fetion_sip_to_string(sip , body); free(body); ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return ret; } Group* fetion_group_new() { Group* list = (Group*)malloc(sizeof(Group)); memset(list , 0 , sizeof(Group)); list->pre = list; list->next = list; return list; } void fetion_group_list_append(Group* head , Group* group) { head->next->pre = group; group->next = head->next; group->pre = head; head->next = group; } void fetion_group_list_prepend(Group* head , Group* group) { head->pre->next = group; group->next = head; group->pre = head->pre; head->pre = group; } void fetion_group_list_remove(Group *group) { group->next->pre = group->pre; group->pre->next = group->next; } void fetion_group_remove(Group* head , int groupid) { Group *gl_cur; foreach_grouplist(head , gl_cur){ if(gl_cur->groupid == groupid){ gl_cur->pre->next = gl_cur->next; gl_cur->next->pre = gl_cur->pre; free(gl_cur); break; } } } Group* fetion_group_list_find_by_id(Group* head , int id) { Group *gl_cur; foreach_grouplist(head , gl_cur){ if(gl_cur->groupid == id){ return gl_cur; } } return NULL; } Verification* fetion_verification_new() { Verification* ver = (Verification*)malloc(sizeof(Verification)); memset(ver , 0 , sizeof(Verification)); ver->algorithm = NULL; ver->type = NULL; ver->text = NULL; ver->tips = NULL; return ver; } void fetion_verification_free(Verification* ver) { if(ver != NULL){ free(ver->algorithm); free(ver->type); free(ver->text); free(ver->tips); free(ver->guid); free(ver->code); } free(ver); } int fetion_user_upload_portrait(User* user , const char* filename) { char http[1024]; unsigned char buf[1024]; char res[1024]; char code[4]; char* ip = NULL; FILE* f = NULL; Config *config = user->config; char* server = config->portraitServerName; char* portraitPath = config->portraitServerPath; Proxy *proxy = config->proxy; long filelength; int n; FetionConnection* tcp; ip = get_ip_by_name(server); if(ip == NULL){ debug_error("Parse server ip address failed , %s" , server); return -1; } f = fopen(filename , "r"); fseek(f , 0 , SEEK_END); filelength = ftell(f); rewind(f); debug_info("uploading portrait...."); sprintf(http , "POST /%s/setportrait.aspx HTTP/1.1\r\n" "Cookie: ssic=%s\r\n" "Accept: */*\r\n" "Host: %s\r\n" "Content-Length: %ld\r\n" "Content-Type: image/jpeg\r\n" "User-Agent: IIC2.0/PC 4.0.0000\r\n" "Connection: Keep-Alive\r\n" "Cache-Control: no-cache\r\n\r\n" , portraitPath , user->ssic , server , filelength); tcp = tcp_connection_new(); if(proxy != NULL && proxy->proxyEnabled) tcp_connection_connect_with_proxy(tcp , ip , 80 , proxy); else tcp_connection_connect(tcp , ip , 80); tcp_connection_send(tcp , http , strlen(http)); memset(buf , 0 , sizeof(buf)); int ret; while((n = fread(buf , 1 , sizeof(buf) , f))){ ret = tcp_connection_send(tcp , buf , n) ; if(ret == -1){ fclose(f); return -1; } memset(buf , 0 , sizeof(buf)); } fclose(f); memset(res, 0, sizeof(res)); tcp_connection_recv(tcp , res , sizeof(res)); memset(code, 0, sizeof(code)); strncpy(code , res + 9 , 3); if(strcmp(code , "200") == 0){ debug_info("Upload portrait success"); return 1; }else{ debug_error("Upload portrait failed"); return -1; } } int fetion_user_set_sms_status(User *user , int days) { FetionSip *sip = user->sip; SipHeader *eheader; char buffer[2048]; char code[16]; char *body; char *res; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_SETUSERINFO); fetion_sip_add_header(sip , eheader); body = generate_set_sms_status_body(days); res = fetion_sip_to_string(sip , body); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); memset(buffer , 0 , sizeof(buffer)); tcp_connection_recv(sip->tcp , buffer , sizeof(buffer)); res = strstr(buffer , " ") + 1; memset(code , 0 , sizeof(code)); strncpy(code , res , 3); if(strcmp(code , "200") == 0){ parse_set_sms_status_response(user , buffer); debug_info("set sms online status to %d days[%s]" , days , user->smsOnLineStatus); return 1; }else{ debug_error("failed to set sms online status"); return -1; } return 1; } int fetion_user_download_portrait(User* user , const char* sipuri) { char uri[256]; char *server = user->config->portraitServerName; char *portraitPath = user->config->portraitServerPath; sprintf(uri , "/%s/getportrait.aspx" , portraitPath); return fetion_user_download_portrait_with_uri(user , sipuri , server , uri); } int fetion_user_download_portrait_with_uri(User *user , const char *sipuri , const char *server , const char *portraitpath) { char buf[2048] , *ip , *pos = NULL; FILE *f = NULL; char filename[256]; char *encodedSipuri , *encodedSsic , replyCode[4] = { 0 }; char *friendSid = NULL; Config *config = user->config; FetionConnection* tcp = NULL; int i = 0 , isFirstChunk = 0 , chunkLength = 0 , imageLength = 0 , receivedLength = 0; int ret; ip = get_ip_by_name(server); if(ip == NULL) { debug_error("Parse server ip address failed , %s" , server); return -1; } if(! sipuri || *sipuri == '\0') return -1; friendSid = fetion_sip_get_sid_by_sipuri(sipuri); if(friendSid == NULL) return -1; /* open a file to write ,if not exist then create one*/ sprintf(filename , "%s/%s.jpg" , config->iconPath , friendSid); free(friendSid); encodedSipuri = http_connection_encode_url(sipuri); encodedSsic = http_connection_encode_url(user->ssic); sprintf(buf , "GET %s?Uri=%s" "&Size=120&c=%s HTTP/1.1\r\n" "User-Agent: IIC2.0/PC "PROTO_VERSION"\r\n" "Accept: image/pjpeg;image/jpeg;image/bmp;" "image/x-windows-bmp;image/png;image/gif\r\n" "Host: %s\r\nConnection: Keep-Alive\r\n\r\n" , portraitpath , encodedSipuri , encodedSsic , server); tcp = tcp_connection_new(); if(config->proxy != NULL && config->proxy->proxyEnabled) ret = tcp_connection_connect_with_proxy(tcp , ip , 80 , config->proxy); else ret = tcp_connection_connect(tcp, ip, 80); if(ret < 0){ debug_error("connect to portrait server:%s", strerror(errno)); return -1; } free(ip); ret = tcp_connection_send(tcp , buf , strlen(buf)); if(ret < 0) return -1; //read reply /* 200 OK begin to download protrait , * 302 need to redirect ,404 not found */ for(;;){ memset(buf, 0, sizeof(buf)); chunkLength = tcp_connection_recv(tcp , buf , sizeof(buf) -1); if(chunkLength < 0) break; if(isFirstChunk == 0) { /* check the code num for the first segment*/ memcpy(replyCode , buf + 9 , 3); switch(atoi(replyCode)) { /* no protrait for current user found * ,just return a error */ case 404: goto end; break; /*write the image bytes of the first segment into file*/ case 200: f = fopen(filename , "wb+"); if( f == NULL ) { debug_error("Write user portrait to local disk failed"); return -1; } pos = (char*)buf; imageLength = http_connection_get_body_length(pos); receivedLength = chunkLength - http_connection_get_head_length(pos) -4; for(i = 0 ; i < chunkLength ; i++ ) if( buf[i] == '\r' && buf[i+1] == '\n' &&buf[i+2] == '\r' && buf[i+3] == '\n' ) { fwrite(buf + i + 4 , chunkLength - i -4 , 1 ,f); fflush(f); break; } if(receivedLength == imageLength) goto end; break; default: goto redirect; break; }; isFirstChunk ++; } else { if(strcmp(replyCode , "200") == 0){ fwrite(buf , chunkLength , 1 , f); fflush(f); } receivedLength += chunkLength; if(receivedLength == imageLength) break; } } if(strcmp(replyCode , "200") == 0) { fclose(f); f = NULL; tcp_connection_free(tcp); tcp = NULL; return 0; } redirect: if(strcmp(replyCode , "302") == 0) ret = fetion_user_download_portrait_again(filename , buf , config->proxy); end: if(f != NULL) fclose(f); tcp_connection_free(tcp); tcp = NULL; if(ret < 0) return -1; return 1; } static int fetion_user_download_portrait_again(const char* filepath , const char* buf , Proxy* proxy) { char location[1024] = { 0 }; char httpHost[50] = { 0 }; char httpPath[512] = { 0 }; char http[1024] = { 0 }; char replyCode[5] = { 0 }; FILE* f = NULL; FetionConnection* tcp = NULL; char* ip = NULL; char* pos = strstr(buf , "Location: ") ; int chunkLength = 0 , imageLength = 0 , receivedLength = 0; int i , n = 0; int ret; int isFirstChunk = 0; unsigned char img[2048] = { 0 }; if(pos == NULL) return -1; pos += 10; n = strlen(pos) - strlen(strstr(pos , "\r\n")); strncpy(location , pos , n ); pos = location + 7; n = strlen(pos) - strlen(strstr(pos , "/")); strncpy(httpHost , pos , n); pos += n; strcpy(httpPath , pos); sprintf(http , "GET %s HTTP/1.1\r\n" "User-Agent: IIC2.0/PC 3.3.0370\r\n" "Accept: image/pjpeg;image/jpeg;image/bmp;" "image/x-windows-bmp;image/png;image/gif\r\n" "Cache-Control: private\r\n" "Host: %s\r\n" "Connection: Keep-Alive\r\n\r\n" , httpPath , httpHost); ip = get_ip_by_name(httpHost); if(ip == NULL){ debug_error("Parse portrait server ip address failed , %s" , httpHost); return -1; } tcp = tcp_connection_new(); if(proxy != NULL && proxy->proxyEnabled) ret = tcp_connection_connect_with_proxy(tcp , ip , 80 , proxy); else ret = tcp_connection_connect(tcp , ip , 80); if(ret < 0) return -1; free(ip); ret = tcp_connection_send(tcp , http , strlen(http)); if(ret < 0) return -1; //read portrait data f = fopen(filepath , "wb+"); for(;;){ memset(img, 0 , sizeof(img)); chunkLength = tcp_connection_recv(tcp , img , sizeof(img)-1); if(chunkLength <= 0) break; if(isFirstChunk ++ == 0) { char* pos = (char*)(img); strncpy(replyCode , pos + 9 , 3 ); if(strcmp(replyCode , "404") == 0){ fclose(f); f = NULL; goto end; } imageLength = http_connection_get_body_length(pos); receivedLength = chunkLength - http_connection_get_head_length(pos) - 4; for(i = 0 ; i < chunkLength ; i ++) if( img[i] == '\r' && img[i+1] == '\n' &&img[i+2] == '\r' && img[i+3] == '\n' ) { fwrite(img + i +4 , chunkLength - i - 4 , 1 ,f); break; } if(receivedLength == imageLength) { fclose(f); f = NULL; goto end; } } else { fwrite(img , chunkLength , 1 , f); receivedLength += chunkLength; if(receivedLength == imageLength) break; } memset(img , 0 , sizeof(img)); } if(f != NULL) fclose(f); end: tcp_connection_free(tcp); tcp = NULL; return 0; } Contact* fetion_user_parse_presence_body(const char* body , User* user) { xmlDocPtr doc; xmlNodePtr node , cnode; xmlChar* pos; Contact* contact; Contact* contactres; Contact* contactlist = user->contactList; Contact* currentContact; contactres = fetion_contact_new(); doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "c"); while(node != NULL) { pos = xmlGetProp(node , BAD_CAST "id"); currentContact = fetion_contact_list_find_by_userid(contactlist , (char*)pos); if(currentContact == NULL) { /*not a valid information*/ /*debug_error("User %s is not a valid user" , (char*)pos);*/ node = node->next; continue; } cnode = node->xmlChildrenNode; if(xmlHasProp(cnode , BAD_CAST "sid")) { pos = xmlGetProp(cnode , BAD_CAST "sid"); strcpy(currentContact->sId , (char*)pos); xmlFree(pos); } if(xmlHasProp(cnode , BAD_CAST "m")) { pos = xmlGetProp(cnode , BAD_CAST "m"); strcpy(currentContact->mobileno , (char*)pos); xmlFree(pos); } if(xmlHasProp(cnode , BAD_CAST "l")) { pos = xmlGetProp(cnode , BAD_CAST "l"); currentContact->scoreLevel = atoi((char*)pos); xmlFree(pos); } if(xmlHasProp(cnode , BAD_CAST "n")) { pos = xmlGetProp(cnode , BAD_CAST "n"); strcpy(currentContact->nickname , (char*)pos); xmlFree(pos); } if(xmlHasProp(cnode , BAD_CAST "i")) { pos = xmlGetProp(cnode , BAD_CAST "i"); strcpy(currentContact->impression , (char*)pos); xmlFree(pos); } if(xmlHasProp(cnode , BAD_CAST "p")) { pos = xmlGetProp(cnode , BAD_CAST "p"); if(strcmp(currentContact->portraitCrc, (char*)pos) == 0 || strcmp((char*)pos, "0") == 0) currentContact->imageChanged = 0; else currentContact->imageChanged = 1; strcpy(currentContact->portraitCrc , (char*)pos); xmlFree(pos); }else{ currentContact->imageChanged = 0; } if(xmlHasProp(cnode , BAD_CAST "c")) { pos = xmlGetProp(cnode , BAD_CAST "c"); strcpy(currentContact->carrier , (char*)pos); xmlFree(pos); } if(xmlHasProp(cnode , BAD_CAST "cs")) { pos = xmlGetProp(cnode , BAD_CAST "cs"); currentContact->carrierStatus = atoi((char*)pos); xmlFree(pos); } if(xmlHasProp(cnode , BAD_CAST "s")) { pos = xmlGetProp(cnode , BAD_CAST "s"); currentContact->serviceStatus = atoi((char*)pos); xmlFree(pos); } #if 0 if(xmlHasProp(cnode , BAD_CAST "sms")){ pos = xmlGetProp(cnode , BAD_CAST "sms"); xmlFree(pos); } #endif cnode = xml_goto_node(node , "pr"); if(xmlHasProp(cnode , BAD_CAST "dt")) { pos = xmlGetProp(cnode , BAD_CAST "dt"); strcpy(currentContact->devicetype , *((char*)pos) == '\0' ? "PC" : (char*)pos); xmlFree(pos); } if(xmlHasProp(cnode , BAD_CAST "b")) { pos = xmlGetProp(cnode , BAD_CAST "b"); currentContact->state = atoi((char*)pos); xmlFree(pos); } contact = fetion_contact_new(); memset(contact , 0 , sizeof(contact)); memcpy(contact , currentContact , sizeof(Contact)); fetion_contact_list_append(contactres , contact); node = node->next; } xmlFreeDoc(doc); return contactres; } Contact* fetion_user_parse_syncuserinfo_body(const char* body , User* user) { xmlDocPtr doc; xmlNodePtr node; xmlChar* pos; Contact* contactlist = user->contactList; Contact* currentContact = NULL; doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "buddy"); if(node == NULL) return NULL; while(node){ if(xmlHasProp(node , BAD_CAST "action")){ pos = xmlGetProp(node , BAD_CAST "action"); if(xmlStrcmp(pos , BAD_CAST "add") != 0){ xmlFree(pos); node = node->next; continue; } xmlFree(pos); } pos = xmlGetProp(node , BAD_CAST "user-id"); currentContact = fetion_contact_list_find_by_userid(contactlist , (char*)pos); //currentContact = fetion_contact_new(); debug_info("synchronize user information"); if(currentContact == NULL) { /*not a valid information*/ debug_error("User %s is not a valid user" , (char*)pos); return NULL; } if(xmlHasProp(node , BAD_CAST "uri")) { pos = xmlGetProp(node , BAD_CAST "uri"); strcpy(currentContact->sipuri , (char*)pos); xmlFree(pos); } if(xmlHasProp(node , BAD_CAST "relation-status")) { pos = xmlGetProp(node , BAD_CAST "relation-status"); currentContact->relationStatus = atoi((char*)pos); if(atoi((char*)pos) == 1){ debug_info("User %s accepted your request" , currentContact->userId); }else{ debug_info("User %s refused your request" , currentContact->userId); } xmlFree(pos); } xmlFreeDoc(doc); return currentContact; node = node->next; } xmlFreeDoc(doc); return currentContact; } void fetion_user_save(User *user) { char path[256]; char sql[4096]; char password[4096]; char impression[4096]; sqlite3 *db; Config *config = user->config; sprintf(path, "%s/data.db", config->userPath); debug_info("Save user information"); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return; } sprintf(sql, "delete from user;"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ sprintf(sql, "create table user (" "sId,userId,mobileno,password,sipuri," "publicIp,lastLoginIp,lastLoginTime," "personalVersion, contactVersion," "nickname,impression,country,province," "city,gender,smsOnLineStatus," "customConfigVersion, customConfig," "boundToMobile);"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table user:%s", sqlite3_errmsg(db)); sqlite3_close(db); return; } } sprintf(password, "%s", user->password); sprintf(impression, "%s", user->impression); escape_sql(password); escape_sql(impression); snprintf(sql, sizeof(sql)-1, "insert into user " "values ('%s','%s','%s','%s','%s'," "'%s','%s','%s','%s','%s'," "'%s','%s','%s','%s','%s',%d,'%s'," " '%s', '%s',%d);", user->sId, user->userId, user->mobileno, password, user->sipuri, user->publicIp, user->lastLoginIp, user->lastLoginTime, user->personalVersion, user->contactVersion, user->nickname, impression, user->country, user->province, user->city, user->gender, user->smsOnLineStatus, user->customConfigVersion, user->customConfig, user->boundToMobile); if(sqlite3_exec(db, sql, NULL, NULL, NULL)) debug_error("update user:%s\n%s", sqlite3_errmsg(db), sql); sqlite3_close(db); } void fetion_user_load(User *user) { char path[256]; char sql[4096]; char **sqlres; sqlite3 *db; int ncols, nrows; Config *config = user->config; sprintf(path, "%s/data.db",config->userPath); debug_info("Load user information"); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return; } sprintf(sql, "select * from user;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ sqlite3_close(db); return; } if(nrows == 0 || ncols == 0){ sqlite3_close(db); return; } strcpy(user->sId , sqlres[ncols]); strcpy(user->userId , sqlres[ncols+1]); strcpy(user->mobileno , sqlres[ncols+2]); strcpy(user->password , sqlres[ncols+3]); strcpy(user->sipuri , sqlres[ncols+4]); strcpy(user->publicIp , sqlres[ncols+5]); strcpy(user->lastLoginIp , sqlres[ncols+6]); strcpy(user->lastLoginTime , sqlres[ncols+7]); strcpy(user->personalVersion , sqlres[ncols+8]); strcpy(user->contactVersion , sqlres[ncols+9]); strcpy(user->nickname , sqlres[ncols+10]); strcpy(user->impression , sqlres[ncols+11]); strcpy(user->country , sqlres[ncols+12]); strcpy(user->province , sqlres[ncols+13]); strcpy(user->city , sqlres[ncols+14]); user->gender = atoi(sqlres[ncols+15]); strcpy(user->smsOnLineStatus , sqlres[ncols+16]); strcpy(user->customConfigVersion , sqlres[ncols+17]); user->customConfig = (char*)malloc(strlen(sqlres[ncols+18])+1); memset(user->customConfig, 0, strlen(sqlres[ncols+18])+1); strcpy(user->customConfig, sqlres[ncols+18]); user->boundToMobile = atoi(sqlres[ncols+19]); unescape_sql(user->password); unescape_sql(user->impression); sqlite3_free_table(sqlres); sqlite3_close(db); } static char* generate_set_state_body(StateType state) { char s[16]; char data[] = ""; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(data , strlen(data)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "presence" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "basic" , NULL); snprintf(s, sizeof(s) - 1 , "%d" , state); xmlNewProp(node , BAD_CAST "value" , BAD_CAST s); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } static char* generate_set_moodphrase_body(const char* customConfigVersion , const char* customConfig , const char* personalVersion , const char* moodphrase) { char args[] = ""; xmlChar *res; xmlDocPtr doc; xmlNodePtr node , cnode; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "userinfo" , NULL); cnode = xmlNewChild(node , NULL , BAD_CAST "personal" , NULL); xmlNewProp(cnode , BAD_CAST "impresa" , BAD_CAST moodphrase); xmlNewProp(cnode , BAD_CAST "version" , BAD_CAST personalVersion); cnode = xmlNewChild(node , NULL , BAD_CAST "custom-config" , BAD_CAST customConfig); xmlNewProp(cnode , BAD_CAST "type" , BAD_CAST "PC"); xmlNewProp(cnode , BAD_CAST "version" , BAD_CAST customConfigVersion); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } static char* generate_update_information_body(User* user) { char args[] = ""; char gender[5]; xmlChar *res; xmlDocPtr doc; xmlNodePtr node , cnode; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "userinfo" , NULL); cnode = xmlNewChild(node , NULL , BAD_CAST "personal" , NULL); xmlNewProp(cnode , BAD_CAST "impresa" , BAD_CAST user->impression); xmlNewProp(cnode , BAD_CAST "nickname" , BAD_CAST user->nickname); sprintf(gender , "%d" , user->gender); xmlNewProp(cnode , BAD_CAST "gender" , BAD_CAST gender); xmlNewProp(cnode , BAD_CAST "version" , BAD_CAST "0"); cnode = xmlNewChild(node , NULL , BAD_CAST "custom-config" , BAD_CAST user->customConfig); xmlNewProp(cnode , BAD_CAST "type" , BAD_CAST "PC"); xmlNewProp(cnode , BAD_CAST "version" , BAD_CAST user->customConfigVersion); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } static char* generate_keep_alive_body() { char args[] = ""; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "credentials" , NULL); xmlNewProp(node , BAD_CAST "domains" , BAD_CAST "fetion.com.cn"); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } static void parse_set_moodphrase_response(User* user , const char* sipmsg) { char *pos; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode->xmlChildrenNode; res = xmlGetProp(node , BAD_CAST "version"); memset(user->personalVersion, 0, sizeof(user->personalVersion)); strcpy(user->personalVersion , (char*)res); xmlFree(res); res = xmlGetProp(node , BAD_CAST "impresa"); memset(user->impression, 0, sizeof(user->impression)); strcpy(user->impression , (char*)res); xmlFree(res); node = node->next; res = xmlGetProp(node , BAD_CAST "version"); memset(user->customConfigVersion, 0, sizeof(user->customConfigVersion)); strcpy(user->customConfigVersion , (char*)res); xmlFree(res); res = xmlNodeGetContent(node); free(user->customConfig); user->customConfig = (char*)malloc(strlen((char*)res) + 1); memset(user->customConfig, 0, strlen((char*)res) + 1); strcpy(user->customConfig , (char*)res); xmlFree(res); xmlFreeDoc(doc); } static char* generate_set_sms_status_body(int days) { char args[] = ""; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; char status[16]; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "userinfo" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "personal" , NULL); sprintf(status , "%d.00:00:00" , days); xmlNewProp(node , BAD_CAST "sms-online-status" , BAD_CAST status); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } static void parse_set_sms_status_response(User *user , const char *sipmsg) { char *pos; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "personal"); if(!node) return; if(!xmlHasProp(node , BAD_CAST "sms-online-status")) return; res = xmlGetProp(node , BAD_CAST "sms-online-status"); strcpy(user->smsOnLineStatus , (char*)res); xmlFree(res); xmlFreeDoc(doc); } libofetion-2.2.2/fetion_sip.h0000644000175000017500000002602511700115314014635 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_SIP_H #define FETION_SIP_H #define SIP_BUFFER_SIZE 2048 typedef enum { SIP_REGISTER = 1 , SIP_SERVICE , SIP_SUBSCRIPTION , SIP_NOTIFICATION , SIP_INVITATION , SIP_INCOMING , SIP_OPTION , SIP_MESSAGE , SIP_SIPC_4_0 , SIP_ACKNOWLEDGE , SIP_UNKNOWN } SipType; typedef enum { NOTIFICATION_TYPE_PRESENCE , NOTIFICATION_TYPE_CONTACT , NOTIFICATION_TYPE_CONVERSATION , NOTIFICATION_TYPE_REGISTRATION , NOTIFICATION_TYPE_SYNCUSERINFO , NOTIFICATION_TYPE_PGGROUP , NOTIFICATION_TYPE_UNKNOWN } NotificationType; typedef enum { NOTIFICATION_EVENT_PRESENCECHANGED , NOTIFICATION_EVENT_ADDBUDDYAPPLICATION , NOTIFICATION_EVENT_USERLEFT , NOTIFICATION_EVENT_DEREGISTRATION , NOTIFICATION_EVENT_SYNCUSERINFO , NOTIFICATION_EVENT_PGGETGROUPINFO , NOTIFICATION_EVENT_UNKNOWN } NotificationEvent; typedef enum { SIP_EVENT_PRESENCE = 0, SIP_EVENT_SETPRESENCE , SIP_EVENT_CONTACT , SIP_EVENT_CONVERSATION , SIP_EVENT_CATMESSAGE , SIP_EVENT_SENDCATMESSAGE , SIP_EVENT_STARTCHAT , SIP_EVENT_INVITEBUDDY , SIP_EVENT_GETCONTACTINFO , SIP_EVENT_CREATEBUDDYLIST , SIP_EVENT_DELETEBUDDYLIST , SIP_EVENT_SETCONTACTINFO , SIP_EVENT_SETUSERINFO , SIP_EVENT_SETBUDDYLISTINFO , SIP_EVENT_DELETEBUDDY , SIP_EVENT_ADDBUDDY , SIP_EVENT_KEEPALIVE , SIP_EVENT_DIRECTSMS , SIP_EVENT_SENDDIRECTCATSMS , SIP_EVENT_HANDLECONTACTREQUEST , SIP_EVENT_PGGETGROUPLIST , SIP_EVENT_PGGETGROUPINFO , SIP_EVENT_PGGETGROUPMEMBERS , SIP_EVENT_PGSENDCATSMS , SIP_EVENT_PGPRESENCE } SipEvent; typedef enum { INCOMING_NUDGE , INCOMING_SHARE_CONTENT , INCOMING_INPUT, INCOMING_UNKNOWN } IncomingType; typedef enum { INCOMING_ACTION_ACCEPT , INCOMING_ACTION_CANCEL , INCOMING_ACTION_UNKNOWN } IncomingActionType; /** * create a FetionSip object and initialize it * @param tcp The tcp connection object that FetionSip used to send and recv message * @param sid Login user`s fetion number * @return The FetionSip object created; */ extern FetionSip* fetion_sip_new(FetionConnection* tcp , const char* sid); /** * clone a new FetionSip object with the existed FetionSip object * @param sip The FetionSip object to be cloned from * @return The new FetionSip object just cloned */ extern FetionSip* fetion_sip_clone(FetionSip* sip); /** * create a sip header in type of in the form of "T:sip:*****@fetion.com.cn" * @note this function can just be used when you want to exannd the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. * @param name The name of the header , in the example above , name is "T" * @param value The value of the header , int the example above , value is "sip:*****@fetion.con.cn" * @return The sip header just created */ extern SipHeader* fetion_sip_header_new(const char* name , const char* value); /** * set the type of sip , only need to be called before * constructing a new sip request message * such as message with type 'M' , "I" , "S",etc... * @note this function can just be used when you want to expand the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. * @param sip The FetionSip object to be set. * @param type The new sip type. */ extern void fetion_sip_set_type(FetionSip* sip , SipType type); /** * set the sip`s callid with the given callid instead of using the autoincrement callid * @note this function can just be used when you want to exannd the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. * @param sip The sip object to be sest. * @param callid The new callid */ extern void fetion_sip_set_callid(FetionSip* sip , int callid); /** * @note this function can just be used when you want to expand the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. */ extern SipHeader* fetion_sip_authentication_header_new(const char* response); /** * @note this function can just be used when you want to expand the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. */ extern SipHeader* fetion_sip_ack_header_new(const char* code , const char* algorithm , const char* type , const char* guid); /** * @note this function can just be used when you want to expand the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. */ extern SipHeader* fetion_sip_event_header_new(int eventType); /** * @note this function can just be used when you want to expand the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. */ extern SipHeader* fetion_sip_credential_header_new(const char* credential); /** * @note this function can just be used when you want to expand the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. */ extern void fetion_sip_add_header(FetionSip* sip , SipHeader* header); /** * @note this function can just be used when you want to expand the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. */ extern char* fetion_sip_to_string(FetionSip* sip , const char* body); /** * free the resource of the sip object after use */ extern void fetion_sip_free(FetionSip* sip); /** * A very commonly used function.It convert the sipuri to sid * @param sipuri The sip uri to get sid from * @return sid get from the sipuri. Need to be freed after use. */ extern char* fetion_sip_get_sid_by_sipuri(const char* sipuri); /** * Another very commonly used function.It convert the fetion group uri * to sid , when pgsipuri is 'sip:PG444444@fetion.com.cn' , it returns 444444 * @return Need to be freed after use. */ extern char* fetion_sip_get_pgid_by_sipuri(const char *pgsipuri); /** * get the attribute value with the given attribute name in a sip message * @param sipmsg The sip message to be parsed * @param name The attribute name * @param retulst The attribute value * @return 1 if success , or else -1 */ extern int fetion_sip_get_attr(const char* sipmsg , const char* name , char* result); /** * get the length of the sip message body which is in form of xml * @return the length of the xml body , 0 if no xml body */ extern int fetion_sip_get_length(const char* sipmsg); /** * get the code of the reponse sip message , for example * the input message is "SIP-C/4.0 200 OK ...." , it returns 200 */ extern int fetion_sip_get_code(const char* sip); /** * get the type of the sip message */ extern int fetion_sip_get_type(const char* sip); /** * @note this function can just be used when you want to expand the * fetion protocal stack,otherwise just call the protocal functions , * they can meet most of your demand. */ extern void fetion_sip_get_auth_attr(const char* auth , char** ipaddress , int* port , char** credential); /** * get the response message when a request message already sent * @return The response message sent from the sipc server,need to be freed after use. */ extern char* fetion_sip_get_response(FetionSip* sip); /** * set a new tcp connection object for the specified sip object */ extern void fetion_sip_set_connection(FetionSip* sip , FetionConnection* conn); /** * listen the sipc message channel,and returns the sip message * pushed from the server. * @note this function should be put at a loop * @return the SipMsg object which contains the message related information */ extern SipMsg* fetion_sip_listen(FetionSip* sip, int *error); extern int fetion_sip_keep_alive(FetionSip* sip); extern void fetion_sip_message_free(SipMsg* msg); extern void fetion_sip_message_append(SipMsg* msglist , SipMsg* msg); extern void fetion_sip_parse_notification(const char* sip , int* type , int* event , char** xml); extern void fetion_sip_parse_message(FetionSip* sip , const char* sipmsg , Message** msg); extern void fetion_sip_parse_invitation(FetionSip* sip , Proxy *proxy, const char* sipmsg , FetionSip** conversionSip , char** sipuri); extern void fetion_sip_parse_addbuddyapplication(const char* sipmsg , char** sipuri , char** userid , char** desc , int* phrase); extern void fetion_sip_parse_incoming(FetionSip* sip , const char* sipmsg , char** sipuri , IncomingType* type , IncomingActionType *action); extern void fetion_sip_parse_userleft(const char* sipmsg , char** sipuri); extern int fetion_sip_parse_shareaccept(FetionSip *sip , const char* sipmsg , Share *share); extern void fetion_sip_parse_sysmsg(const char* sipmsg , int *type , int *showonce , char **content , char **url); extern int fetion_sip_parse_sipc(const char *sipmsg , int *callid , char **xml); extern struct tm convert_date(const char* date); extern inline void fetion_sip_set_conn(FetionSip *sip, FetionConnection *conn); #endif libofetion-2.2.2/fetion_sip.c0000644000175000017500000007132311700115314014631 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #define _XOPEN_SOURCE #include int callid = 1; FetionSip* fetion_sip_new(FetionConnection* tcp , const char* sid) { FetionSip* sip = (FetionSip*)malloc(sizeof(FetionSip)); memset(sip , 0 , sizeof(FetionSip)); strcpy(sip->from , sid); sip->sequence = 2; sip->tcp = tcp; sip->header = NULL; return sip; } FetionSip* fetion_sip_clone(FetionSip* sip) { FetionSip* res = (FetionSip*)malloc(sizeof(FetionSip)); memset(res , 0 , sizeof(FetionSip)); memcpy(res , sip , sizeof(FetionSip)); sip->header = NULL; return res; } SipHeader* fetion_sip_header_new(const char* name , const char* value) { SipHeader* header = (SipHeader*)malloc(sizeof(SipHeader)); memset(header , 0 , sizeof(SipHeader)); strcpy(header->name , name); header->value = (char*)malloc(strlen(value) + 2 ); memset(header->value , 0 , strlen(value) + 2); strcpy(header->value , value); header->next = NULL; return header; } void fetion_sip_set_type(FetionSip *sip, SipType type) { if(!sip) return; sip->type = type; sip->callid = callid; } void fetion_sip_set_callid(FetionSip* sip , int callid) { sip->callid = callid; } SipHeader* fetion_sip_authentication_header_new(const char* response) { int len; char* res; char start[] = "Digest response=\""; char end[] = "\",algorithm=\"SHA1-sess-v4\""; SipHeader* header; len = strlen(start) + strlen(end) + strlen(response) + 10; res = (char*)malloc(len); memset(res, 0 , len); sprintf(res, "%s%s%s" , start , response , end); header = (SipHeader*)malloc(sizeof(SipHeader)); memset(header , 0 , sizeof(SipHeader)); strcpy(header->name , "A"); header->value = res; return header; } SipHeader* fetion_sip_ack_header_new(const char* code , const char* algorithm , const char* type , const char* guid) { char ack[512]; sprintf(ack , "Verify response=\"%s\",algorithm=\"%s\",type=\"%s\",chid=\"%s\"" , code , algorithm , type , guid); return fetion_sip_header_new("A" , ack); } SipHeader* fetion_sip_event_header_new(int eventType) { char event[48]; memset(event, 0, sizeof(event)); switch(eventType) { case SIP_EVENT_PRESENCE : strcpy(event , "PresenceV4"); break; case SIP_EVENT_SETPRESENCE : strcpy(event , "SetPresenceV4"); break; case SIP_EVENT_CATMESSAGE : strcpy(event , "CatMsg"); break; case SIP_EVENT_SENDCATMESSAGE : strcpy(event , "SendCatSMS"); break; case SIP_EVENT_STARTCHAT : strcpy(event , "StartChat"); break; case SIP_EVENT_GETCONTACTINFO : strcpy(event , "GetContactInfoV4"); break; case SIP_EVENT_CONVERSATION : strcpy(event , "Conversation"); break; case SIP_EVENT_INVITEBUDDY : strcpy(event , "InviteBuddy"); break; case SIP_EVENT_CREATEBUDDYLIST : strcpy(event , "CreateBuddyList"); break; case SIP_EVENT_DELETEBUDDYLIST : strcpy(event , "DeleteBuddyList"); break; case SIP_EVENT_SETCONTACTINFO : strcpy(event , "SetContactInfoV4"); break; case SIP_EVENT_SETUSERINFO : strcpy(event , "SetUserInfoV4"); break; case SIP_EVENT_SETBUDDYLISTINFO : strcpy(event , "SetBuddyListInfo"); break; case SIP_EVENT_DELETEBUDDY : strcpy(event , "DeleteBuddyV4"); break; case SIP_EVENT_ADDBUDDY : strcpy(event , "AddBuddyV4"); break; case SIP_EVENT_KEEPALIVE : strcpy(event , "KeepAlive"); break; case SIP_EVENT_DIRECTSMS : strcpy(event , "DirectSMS"); break; case SIP_EVENT_HANDLECONTACTREQUEST : strcpy(event , "HandleContactRequestV4"); break; case SIP_EVENT_SENDDIRECTCATSMS : strcpy(event , "SendDirectCatSMS"); break; case SIP_EVENT_PGGETGROUPLIST: strcpy(event , "PGGetGroupList"); break; case SIP_EVENT_PGGETGROUPINFO: strcpy(event , "PGGetGroupInfo"); break; case SIP_EVENT_PGPRESENCE: strcpy(event , "PGPresence"); break; case SIP_EVENT_PGGETGROUPMEMBERS: strcpy(event , "PGGetGroupMembers"); break; case SIP_EVENT_PGSENDCATSMS: strcpy(event , "PGSendCatSMS"); break; default: break; } return fetion_sip_header_new("N" , event); } SipHeader* fetion_sip_credential_header_new(const char* credential) { char value[64]; memset(value , 0, sizeof(value)); sprintf(value , "TICKS auth=\"%s\"" , credential); return fetion_sip_header_new("A" , value); } void fetion_sip_add_header(FetionSip* sip , SipHeader* header) { SipHeader* pos = sip->header; if(pos == NULL) { sip->header = header; return; } while(pos != NULL) { if(pos->next == NULL) { pos->next = header; break; } pos = pos->next; } } char* fetion_sip_to_string(FetionSip* sip , const char* body) { char *res , *head , buf[1024] , type[128]; SipHeader *pos , *tmp; int len = 0; pos = sip->header; while(pos){ len += (strlen(pos->value) + strlen(pos->name) + 5); pos = pos->next; } len += (body == NULL ? 100 : strlen(body) + 100 ); res = (char*)malloc(len + 1); memset(res , 0 , len + 1); memset(type, 0 , sizeof(type)); switch(sip->type){ case SIP_REGISTER : strcpy(type , "R"); break; case SIP_SUBSCRIPTION : strcpy(type , "SUB"); break; case SIP_SERVICE : strcpy(type , "S"); break; case SIP_MESSAGE : strcpy(type , "M"); break; case SIP_INCOMING : strcpy(type , "IN"); break; case SIP_OPTION : strcpy(type , "O"); break; case SIP_INVITATION : strcpy(type , "I"); break; case SIP_ACKNOWLEDGE : strcpy(type , "A"); break; default: break; }; if(*type == '\0'){ free(res); return NULL; } sprintf(buf, "%s fetion.com.cn SIP-C/4.0\r\n" "F: %s\r\n" "I: %d\r\n" "Q: 2 %s\r\n", type, sip->from, sip->callid, type); strcat(res , buf); pos = sip->header; while(pos){ len = strlen(pos->value) + strlen(pos->name) + 5; head = (char*)malloc(len); sprintf(head , "%s: %s\r\n" , pos->name , pos->value); strcat(res , head); tmp = pos; pos = pos->next; free(head); free(tmp->value); free(tmp); } if(body){ sprintf(buf , "L: %d\r\n\r\n" , strlen(body)); strcat(res , buf); strcat(res , body); }else{ strcat(res , "\r\n"); } callid ++; sip->header = NULL; return res; } void fetion_sip_free(FetionSip* sip) { debug_info("Free sip struct and close socket"); if(sip != NULL) tcp_connection_free(sip->tcp); free(sip); } char* fetion_sip_get_sid_by_sipuri(const char* sipuri) { char *res , *pos; int n; pos = strstr(sipuri , ":") + 1; n = strlen(pos) - (strstr(pos , "@") == 0 ? 0 : strlen(strstr(pos , "@"))) ; res = (char*)malloc(n + 1); memset(res , 0 , n + 1); strncpy(res , pos , n); return res; } char* fetion_sip_get_pgid_by_sipuri(const char *pgsipuri) { char *res , *pos; int n; if(strstr(pgsipuri , "PG") == NULL) return NULL; pos = strstr(pgsipuri , "PG") + 2; n = strlen(pos) - (strstr(pos , "@") == 0 ? 0 : strlen(strstr(pos , "@"))) ; res = (char*)malloc(n + 1); memset(res , 0 , n + 1); strncpy(res , pos , n); return res; } int fetion_sip_get_attr(const char* sip , const char* name , char* result) { char m_name[16]; char* pos; int n; sprintf(m_name , "%s: " , name); if(strstr(sip , m_name) == NULL) return -1; pos = strstr(sip , m_name) + strlen(m_name); if(strstr(pos , "\r\n") == NULL) n = strlen(pos); else n = strlen(pos) - strlen(strstr(pos , "\r\n")); strncpy(result , pos , n); return 1; } int fetion_sip_get_length(const char* sip) { char res[6]; char name[] = "L"; memset(res, 0, sizeof(res)); if(fetion_sip_get_attr(sip , name , res) == -1) return 0; return atoi(res); } int fetion_sip_get_code(const char* sip) { char *pos , res[32]; int n; memset(res, 0, sizeof(res)); if(strstr(sip , "4.0 ") == NULL) return 400; pos = strstr(sip , "4.0 ") + 4; if(strstr(pos , " ") == NULL) return 400; n = strlen(pos) - strlen(strstr(pos , " ")); strncpy(res , pos , n); return atoi(res); } int fetion_sip_get_type(const char* sip) { char res[128]; int n; if(!strstr(sip, " ")) return SIP_UNKNOWN; n = strlen(sip) - strlen(strstr(sip , " ")); memset(res, 0, sizeof(res)); strncpy(res , sip , n); if(strcmp(res , "I") == 0 ) return SIP_INVITATION; if(strcmp(res , "M") == 0 ) return SIP_MESSAGE; if(strcmp(res , "BN") == 0) return SIP_NOTIFICATION; if(strcmp(res , "SIP-C/4.0") == 0 || strcmp(res , "SIP-C/2.0") == 0) return SIP_SIPC_4_0; if(strcmp(res , "IN") == 0) return SIP_INCOMING; if(strcmp(res , "O") == 0 ) return SIP_OPTION; return SIP_UNKNOWN; } char* fetion_sip_get_response(FetionSip* sip) { char *res; int len , n; int c, c1; char buf[1024 * 20]; memset(buf, 0, sizeof(buf)); if((c = tcp_connection_recv(sip->tcp , buf , sizeof(buf) - 2)) == -1) return (char*)0; len = fetion_sip_get_length(buf); while(strstr(buf , "\r\n\r\n") == NULL && c < (int)sizeof(buf)) c += tcp_connection_recv(sip->tcp, buf + c, sizeof(buf) - c - 1); n = strlen(buf) - strlen(strstr(buf , "\r\n\r\n") + 4); len += n; if(!(res = (char*)malloc(len + 10))) return (char*)0; memset(res, 0, len + 10); strcpy(res, buf); if(c < len) { for(;;) { memset(buf, 0, sizeof(buf)); if((c1 = tcp_connection_recv(sip->tcp , buf , len -c < (int)(sizeof(buf) - 1) ? len -c : (int)(sizeof(buf) - 1) )) == -1) {free(res); return (char*)0; } strncpy(res + c, buf, c1); c += c1; if(c >= len) { break; } } } return res; } void fetion_sip_set_connection(FetionSip* sip , FetionConnection* conn) { sip->tcp = conn; } static SipMsg *sipmsg_new(void) { SipMsg *msg = (SipMsg*)malloc(sizeof(SipMsg)); memset(msg, 0, sizeof(SipMsg)); msg->next = NULL; return msg; } static void sipmsg_set_msg(SipMsg *sipmsg, const char *msg, int n) { sipmsg->message = (char*)malloc(n + 1); memset(sipmsg->message, 0, n + 1); strncpy(sipmsg->message, msg, n); } #define BUFFER_SIZE (1024 * 100) /* the following code is hard to read,forgive me! */ SipMsg *fetion_sip_listen(FetionSip *sip, int *error) { int n; int body_len; char buffer[BUFFER_SIZE]; char holder[BUFFER_SIZE]; char *cur; char *pos; SipMsg *list = NULL; SipMsg *msg; *error = 0; memset(buffer, 0, sizeof(buffer)); n = tcp_connection_recv_dont_wait(sip->tcp, buffer, sizeof(buffer) - 1); if(n == 0){ debug_info("fetion_sip_listen 0"); *error = 1; return NULL; } if(n == -1){ *error = 1; return NULL; } cur = buffer; for(;;){ pos = strstr(cur, "\r\n\r\n"); body_len = 0; if(pos){ n = strlen(cur) - strlen(pos); memset(holder, 0, sizeof(holder)); strncpy(holder, cur, n); body_len = fetion_sip_get_length(holder); } if(cur == NULL || *cur == '\0') return list; if(body_len == 0 && pos){ msg = sipmsg_new(); n = strlen(cur) - strlen(pos) + 4; sipmsg_set_msg(msg, cur, n); if(list) fetion_sip_message_append(list, msg); else list = msg; cur += n; continue; } if((body_len == 0 && !pos) || (body_len != 0 && !pos)){ memset(holder, 0 , sizeof(holder)); strcpy(holder, cur); tcp_connection_recv(sip->tcp, holder + strlen(cur), BUFFER_SIZE - strlen(cur) - 1); memset(buffer, 0 , sizeof(buffer)); strcpy(buffer, holder); cur = buffer; continue; }else{ /* now body_len != 0 */ pos += 4; memset(holder, 0 , sizeof(holder)); if((int)strlen(pos) < body_len){ strcpy(holder, cur); tcp_connection_recv(sip->tcp, holder + strlen(cur), BUFFER_SIZE - strlen(cur) - 1); memset(buffer, 0, sizeof(buffer)); strcpy(buffer, holder); cur = buffer; continue; }else if((int)strlen(pos) == body_len){ msg = sipmsg_new(); sipmsg_set_msg(msg, cur, strlen(cur)); if(list) fetion_sip_message_append(list, msg); else list = msg; return list; }else{ msg = sipmsg_new(); n = strlen(cur) - strlen(pos) + body_len; sipmsg_set_msg(msg, cur, n); if(list) fetion_sip_message_append(list, msg); else list = msg; memset(holder, 0 , sizeof(holder)); strcpy(holder, cur + n); memset(buffer, 0, sizeof(buffer)); strcpy(buffer, holder); cur = buffer; continue; } } } } int fetion_sip_keep_alive(FetionSip* sip) { char *res = NULL; int ret; debug_info("Send a periodical chat keep alive request"); fetion_sip_set_type(sip , SIP_REGISTER); res = fetion_sip_to_string(sip , NULL); ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return ret; } void fetion_sip_message_free(SipMsg* msg) { SipMsg* pos = msg; SipMsg* pot; while(pos != NULL) { pot = pos; pos = pos->next; if(pot != NULL ){ free(pot->message); } free(pot); pot = NULL; } } void fetion_sip_message_append(SipMsg* msglist , SipMsg* msg) { SipMsg* pos = msglist; while(pos != NULL) { if(pos->next == NULL) { pos->next = msg; break; } pos = pos->next; } } void fetion_sip_parse_notification(const char* sip , int* type , int* event , char** xml) { char type1[16] , *pos; xmlChar *event1; xmlDocPtr doc; xmlNodePtr node; memset(type1, 0, sizeof(type1)); fetion_sip_get_attr(sip , "N" , type1); if(strcmp(type1 , "PresenceV4") == 0) *type = NOTIFICATION_TYPE_PRESENCE; else if(strcmp(type1 , "Conversation") == 0) *type = NOTIFICATION_TYPE_CONVERSATION; else if(strcmp(type1 , "contact") == 0) *type = NOTIFICATION_TYPE_CONTACT; else if(strcmp(type1 , "registration") == 0) *type = NOTIFICATION_TYPE_REGISTRATION; else if(strcmp(type1 , "SyncUserInfoV4") == 0) *type = NOTIFICATION_TYPE_SYNCUSERINFO; else if(strcmp(type1 , "PGGroup") == 0) *type = NOTIFICATION_TYPE_PGGROUP; else *type = NOTIFICATION_TYPE_UNKNOWN; pos = strstr(sip , "\r\n\r\n") + 4; *xml = (char*)malloc(strlen(pos) + 1); memset(*xml , 0 , strlen(pos) + 1); strcpy(*xml , pos); doc = xmlReadMemory(*xml , strlen(*xml) , NULL , "UTF-8" , XML_PARSE_RECOVER); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "event"); event1 = xmlGetProp(node , BAD_CAST "type"); if(xmlStrcmp(event1 , BAD_CAST "PresenceChanged") == 0) *event = NOTIFICATION_EVENT_PRESENCECHANGED; else if(xmlStrcmp(event1 , BAD_CAST "UserLeft") == 0) *event = NOTIFICATION_EVENT_USERLEFT; else if(xmlStrcmp(event1 , BAD_CAST "deregistered") == 0) *event = NOTIFICATION_EVENT_DEREGISTRATION; else if(xmlStrcmp(event1 , BAD_CAST "SyncUserInfo") == 0) *event = NOTIFICATION_EVENT_SYNCUSERINFO; else if(xmlStrcmp(event1 , BAD_CAST "AddBuddyApplication") == 0) *event = NOTIFICATION_EVENT_ADDBUDDYAPPLICATION; else if(xmlStrcmp(event1 , BAD_CAST "PGGetGroupInfo") == 0) *event = NOTIFICATION_EVENT_PGGETGROUPINFO; else *event = NOTIFICATION_EVENT_UNKNOWN; xmlFree(event1); xmlFreeDoc(doc); } void fetion_sip_parse_message(FetionSip* sip , const char* sipmsg , Message** msg) { char len[16] , callid[16] , sequence[16] ; char sendtime[32] , from[64] , rep[256]; char memsipuri[64]; char *pos = NULL; xmlDocPtr doc; xmlNodePtr node; memset(len , 0 , sizeof(len)); memset(callid , 0 , sizeof(callid)); memset(sequence , 0 , sizeof(sequence)); memset(sendtime , 0 , sizeof(sendtime)); memset(from , 0 , sizeof(from)); fetion_sip_get_attr(sipmsg , "F" , from); fetion_sip_get_attr(sipmsg , "L" , len); fetion_sip_get_attr(sipmsg , "I" , callid); fetion_sip_get_attr(sipmsg , "Q" , sequence); fetion_sip_get_attr(sipmsg , "D" , sendtime); *msg = fetion_message_new(); (*msg)->sysback = 0; if(strstr(sipmsg, "SIP-C/3.0") && !strstr(sipmsg, "SIP-C/4.0")) (*msg)->sysback = 1; /* group message */ if(strstr(from , "PG") != NULL){ fetion_message_set_pguri(*msg , from); memset(memsipuri , 0 , sizeof(memsipuri)); fetion_sip_get_attr(sipmsg , "SO" , memsipuri); fetion_message_set_sipuri(*msg , memsipuri); }else{ fetion_message_set_sipuri(*msg , from); } pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlReadMemory(pos , strlen(pos) , "UTF-8" , NULL , XML_PARSE_NOERROR); fetion_message_set_time(*msg , convert_date(sendtime)); if(doc != NULL){ node = xmlDocGetRootElement(doc); pos = (char*)xmlNodeGetContent(node); fetion_message_set_message(*msg , pos); free(pos); xmlFreeDoc(doc); }else{ fetion_message_set_message(*msg , pos); } memset(rep, 0, sizeof(rep)); if(strstr(from , "PG") == NULL) sprintf(rep ,"SIP-C/4.0 200 OK\r\nF: %s\r\nI: %s\r\nQ: %s\r\n\r\n" , from , callid , sequence ); else sprintf(rep ,"SIP-C/4.0 200 OK\r\nI: %s\r\nQ: %s\r\nF: %s\r\n\r\n" , callid , sequence , from); tcp_connection_send(sip->tcp , rep , strlen(rep)); } void fetion_sip_parse_invitation(FetionSip* sip , Proxy *proxy , const char* sipmsg , FetionSip** conversionSip , char** sipuri) { char from[50]; char auth[128]; char* ipaddress = NULL; char buf[1024]; int port; char* credential = NULL; FetionConnection* conn = NULL; SipHeader* aheader = NULL; SipHeader* theader = NULL; SipHeader* mheader = NULL; SipHeader* nheader = NULL; char* sipres = NULL; memset(from, 0, sizeof(from)); memset(auth, 0, sizeof(auth)); memset(buf, 0, sizeof(buf)); fetion_sip_get_attr(sipmsg , "F" , from); fetion_sip_get_attr(sipmsg , "A" , auth); fetion_sip_get_auth_attr(auth , &ipaddress , &port , &credential); conn = tcp_connection_new(); if(proxy != NULL && proxy->proxyEnabled) tcp_connection_connect_with_proxy(conn , ipaddress , port , proxy); else { int ret = tcp_connection_connect(conn , ipaddress , port); if(ret == -1) ret = tcp_connection_connect(conn , ipaddress , 443); if(ret == -1) { debug_error("Connect to server failed: %s:%d/%s:%d", ipaddress, port, ipaddress, 443); return; } } *conversionSip = fetion_sip_clone(sip); fetion_sip_set_connection(*conversionSip , conn); debug_info("Received a conversation invitation"); sprintf(buf , "SIP-C/4.0 200 OK\r\nF: %s\r\nI: -61\r\nQ: 200002 I\r\n\r\n" , from); *sipuri = (char*)malloc(48); memset(*sipuri , 0 , 48); strcpy(*sipuri , from); tcp_connection_send(sip->tcp , buf , strlen(buf)); fetion_sip_set_type(sip , SIP_REGISTER); aheader = fetion_sip_credential_header_new(credential); theader = fetion_sip_header_new("K" , "text/html-fragment"); mheader = fetion_sip_header_new("K" , "multiparty"); nheader = fetion_sip_header_new("K" , "nudge"); fetion_sip_add_header(sip , aheader); fetion_sip_add_header(sip , theader); fetion_sip_add_header(sip , mheader); fetion_sip_add_header(sip , nheader); sipres = fetion_sip_to_string(sip , NULL); debug_info("Register to conversation server %s:%d" , ipaddress , port); tcp_connection_send(conn , sipres , strlen(sipres)); free(sipres); free(ipaddress); memset(buf , 0 , sizeof(buf)); port = tcp_connection_recv(conn , buf , sizeof(buf)); memset((*conversionSip)->sipuri, 0, sizeof((*conversionSip)->sipuri)); strcpy((*conversionSip)->sipuri , *sipuri); } void fetion_sip_parse_addbuddyapplication(const char* sipmsg , char** sipuri , char** userid , char** desc , int* phrase) { char *pos = NULL; xmlDocPtr doc; xmlNodePtr node; xmlChar *res = NULL; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlReadMemory(pos , strlen(pos) , NULL , "UTF-8" , XML_PARSE_RECOVER); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "application"); res = xmlGetProp(node , BAD_CAST "uri"); *sipuri = (char*)malloc(strlen((char*)res) + 1); memset(*sipuri, 0, strlen((char*)res) + 1); strcpy(*sipuri , (char*)res); xmlFree(res); res = xmlGetProp(node , BAD_CAST "user-id"); *userid = (char*)malloc(strlen((char*)res) + 1); memset(*userid, 0, strlen((char*)res) + 1); strcpy(*userid , (char*)res); xmlFree(res); res = xmlGetProp(node , BAD_CAST "desc"); *desc = (char*)malloc(xmlStrlen(res) + 1); memset(*desc, 0, xmlStrlen(res) + 1); strcpy(*desc , (char*)res); xmlFree(res); res = xmlGetProp(node , BAD_CAST "addbuddy-phrase-id"); *phrase = atoi((char*)res); xmlFree(res); xmlFreeDoc(doc); } void fetion_sip_parse_incoming(FetionSip* sip , const char* sipmsg , char** sipuri , IncomingType* type , IncomingActionType *action) { char *pos = NULL; xmlDocPtr doc = NULL; xmlNodePtr node = NULL; xmlChar *res = NULL; char replyMsg[128]; char callid[10]; char seq[10]; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); if(xmlStrcmp(node->name , BAD_CAST "share-content") == 0){ debug_info("Received a share-content IN message"); *sipuri = (char*)malloc(48); memset(*sipuri, 0, 48); fetion_sip_get_attr(sipmsg , "F" , *sipuri); *type = INCOMING_SHARE_CONTENT; if(! xmlHasProp(node , BAD_CAST "action")){ *action = INCOMING_ACTION_UNKNOWN; xmlFreeDoc(doc); return; } res = xmlGetProp(node , BAD_CAST "action"); if(xmlStrcmp(res , BAD_CAST "accept") == 0){ *action = INCOMING_ACTION_ACCEPT; } else if( xmlStrcmp(res , BAD_CAST "cancel") == 0){ *action = INCOMING_ACTION_CANCEL; } else { *action = INCOMING_ACTION_UNKNOWN; } xmlFree(res); xmlFreeDoc(doc); return; } if(xmlStrcmp(node->name , BAD_CAST "is-composing") != 0){ debug_info("Received a unhandled sip message , thanks for sending it to the author"); *type = INCOMING_UNKNOWN; xmlFreeDoc(doc); return; } node = node->xmlChildrenNode; res = xmlNodeGetContent(node); if(xmlStrcmp(res, BAD_CAST "nudge") == 0 || xmlStrcmp(res, BAD_CAST "input") == 0) { *type = INCOMING_UNKNOWN; *sipuri = (char*)malloc(50); memset(replyMsg, 0, sizeof(replyMsg)); memset(callid, 0, sizeof(callid)); memset(seq, 0, sizeof(seq)); memset(*sipuri, 0, 50); fetion_sip_get_attr(sipmsg , "I" , callid); fetion_sip_get_attr(sipmsg , "Q" , seq); fetion_sip_get_attr(sipmsg , "F" , *sipuri); sprintf(replyMsg , "SIP-C/4.0 200 OK\r\n" "F: %s\r\n" "I: %s \r\n" "Q: %s\r\n\r\n" , *sipuri , callid , seq); tcp_connection_send(sip->tcp , replyMsg , strlen(replyMsg)); if(xmlStrcmp(res, BAD_CAST "nudge") == 0) *type = INCOMING_NUDGE; else *type = INCOMING_INPUT; } xmlFree(res); xmlFreeDoc(doc); } void fetion_sip_parse_userleft(const char* sipmsg , char** sipuri) { char *pos = NULL; xmlDocPtr doc = NULL; xmlNodePtr node = NULL; xmlChar *res; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "member"); res = xmlGetProp(node , BAD_CAST "uri"); *sipuri = (char*)malloc(xmlStrlen(res) + 1); memset(*sipuri, 0, xmlStrlen(res) + 1); strcpy(*sipuri , (char*)res); xmlFreeDoc(doc); } static char *generate_action_accept_body(Share *share) { xmlChar *buf = NULL; xmlDocPtr doc; xmlNodePtr node , root; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); root = xmlDocGetRootElement(doc); node = xmlNewChild(root , NULL , BAD_CAST "client" , NULL); xmlNewProp(node , BAD_CAST "prefer-types" , BAD_CAST share->preferType); printf("%s\n" , hexip_to_dotip("3B408066")); xmlNewProp(node , BAD_CAST "inner-ip" , BAD_CAST "3B408066"); xmlNewProp(node , BAD_CAST "net-type" , BAD_CAST "0"); xmlNewProp(node , BAD_CAST "tcp-port" , BAD_CAST "443"); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } int fetion_sip_parse_shareaccept(FetionSip *sip , const char* sipmsg , Share *share) { xmlDocPtr doc; xmlNodePtr node; xmlChar *res; char callid[16]; char from[48]; char seq[16]; char response[1024]; char *pos; memset(callid, 0, sizeof(callid)); memset(from, 0, sizeof(from)); memset(seq, 0, sizeof(seq)); fetion_sip_get_attr(sipmsg , "I" , callid); fetion_sip_get_attr(sipmsg , "F" , from); fetion_sip_get_attr(sipmsg , "Q" , seq); pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlReadMemory(pos , strlen(pos) , NULL , "UTF-8" , XML_PARSE_RECOVER ); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode->next; if(xmlStrcmp(node->name , BAD_CAST "client") != 0) return -1; res = xmlGetProp(node , BAD_CAST "prefer-types"); strcpy(share->preferType , (char*)res); xmlFree(res); res = xmlGetProp(node , BAD_CAST "inner-ip"); pos = hexip_to_dotip((char*)res); xmlFree(res); strcpy(share->outerIp , pos); free(pos); pos = NULL; res = xmlGetProp(node , BAD_CAST "udp-inner-port"); share->outerUdpPort = atoi((char*)res); xmlFree(res); res = xmlGetProp(node , BAD_CAST "tcp-port"); share->outerTcpPort = atoi((char*)res); xmlFree(res); pos = generate_action_accept_body(share); memset(response, 0, sizeof(response)); sprintf(response , "SIP-C/4.0 200 OK\r\n" "F: %s\r\n" "I: %s\r\n" "Q: %s\r\n" "L: %d\r\n\r\n%s" , from , callid , seq , strlen(pos) , pos); free(pos); pos = NULL; printf("%s\n" , response); tcp_connection_send(sip->tcp , response , strlen(response) ); return 1; } void fetion_sip_parse_sysmsg(const char* sipmsg , int *type , int* showonce , char **content , char **url){ char *pos; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlReadMemory(pos , strlen(pos) , NULL , "UTF-8" , XML_PARSE_RECOVER); node = xmlDocGetRootElement(doc); res = xmlGetProp(node , BAD_CAST "type"); *type = atoi((char*)type); xmlFree(res); res = xmlGetProp(node , BAD_CAST "show-once"); *showonce = atoi((char*)res); xmlFree(res); node = node->xmlChildrenNode->next->next->next; res = xmlNodeGetContent(node); *content = (char*)malloc(xmlStrlen(res) + 1); memset(*content, 0, xmlStrlen(res) + 1); strcpy(*content , (char*)res); xmlFree(res); node = node->next->next; res = xmlNodeGetContent(node); *url = (char*)malloc(xmlStrlen(res) + 1); memset(*url, 0, xmlStrlen(res) + 1); strcpy(*url , (char*)res); xmlFree(res); } int fetion_sip_parse_sipc(const char *sipmsg , int *callid , char **xml) { char callid_str[16]; char *pos; int n; char code[5]; pos = strstr(sipmsg , " ") + 1; n = strlen(pos) - strlen(strstr(pos , " ")); strncpy(code , pos , n); fetion_sip_get_attr(sipmsg , "I" , callid_str); *callid = atoi(callid_str); pos = strstr(sipmsg , "\r\n\r\n"); if(pos) pos += 4; else{ *xml = NULL; return -1; } *xml = (char*)malloc(strlen(pos) + 1); memset(*xml , 0 , strlen(pos) + 1); strcpy(*xml , pos); return atoi(code); } struct tm convert_date(const char* date) { char* pos = strstr(date , ",") + 2; struct tm dstr; strptime(pos , "%d %b %Y %T %Z" , &dstr); dstr.tm_hour += 8; if(dstr.tm_hour > 23) dstr.tm_hour -= 24; return dstr; } void fetion_sip_get_auth_attr(const char* auth , char** ipaddress , int* port , char** credential) { char* pos = strstr(auth , "address=\"") + 9; int n = strlen(pos) - strlen(strstr(pos , ":")); char port_str[6] = { 0 }; *credential = (char*)malloc(256); memset(*credential , 0 , 256); *ipaddress = (char*)malloc(256); memset(*ipaddress , 0 , 256); strncpy(*ipaddress , pos , n); pos = strstr(pos , ":") + 1; n = strlen(pos) - strlen(strstr(pos , ";")); strncpy(port_str , pos , n); *port = atoi(port_str); pos = strstr(pos , "credential=\"") + 12; strncpy(*credential , pos , strlen(pos) - 1); } inline void fetion_sip_set_conn(FetionSip *sip, FetionConnection *conn) { sip->tcp = conn; } libofetion-2.2.2/fetion_share.h0000644000175000017500000000540311700115314015141 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_SHARE_H #define FETION_SHARE_H #define MAX_FILE_SIZE 2097151 extern Share *fetion_share_new_with_path(const char *sipuri , const char *absolutePath); extern Share *fetion_share_new(const char *sipuri); extern void fetion_share_request(FetionSip *sip , Share *share); extern char* fetion_share_compute_md5(const char *absolutePath); extern long long fetion_share_get_filesize(const char *absolutePath); extern void fetion_share_response_accept(FetionSip *sip , Share *share); #endif libofetion-2.2.2/fetion_share.c0000644000175000017500000001536111700115314015140 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include #include #include #define GUID "9741dc51-43d3-448b-bfc2-dbf4661a27f7" #define SESSIONID "xz4BBcV9741dc5143d3448bbfc2dbf4661a27f7" Share *fetion_share_new(const char *sipuri) { Share *share = (Share*)malloc(sizeof(Share)); memset(share , 0 , sizeof(Share)); strcpy(share->sipuri , sipuri); return share; } Share *fetion_share_new_with_path(const char *sipuri , const char *absolutePath) { Share *share = (Share*)malloc(sizeof(Share)); char *name = NULL; char *md5 = NULL; memset(share , 0 , sizeof(Share)); strcpy(share->guid , GUID); strcpy(share->sessionid , SESSIONID); strcpy(share->sipuri , sipuri); strcpy(share->absolutePath , absolutePath); name = basename((char*)absolutePath); strcpy(share->filename , name); share->filesize = fetion_share_get_filesize(absolutePath); md5 = fetion_share_compute_md5(absolutePath); strcpy(share->md5 , md5); free(md5); return share; } static char* generate_share_request_body(Share *share) { xmlChar *buf = NULL; xmlDocPtr doc; xmlNodePtr node , fnode , root; char size[16]; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); root = xmlDocGetRootElement(doc); xmlNewProp(root , BAD_CAST "id" , BAD_CAST share->guid); node = xmlNewChild(root , NULL , BAD_CAST "caps" , NULL); xmlNewProp(node , BAD_CAST "modes" , BAD_CAST "block;relay;p2p;p2pV2;relayV2;p2pV3;scV2"); xmlNewProp(node , BAD_CAST "max-size" , BAD_CAST "2097151"); node = xmlNewChild(root , NULL , BAD_CAST "client" , NULL); xmlNewProp(node , BAD_CAST "outer-ip" , BAD_CAST ""); xmlNewProp(node , BAD_CAST "inner-ip" , BAD_CAST "59.64.128.102:1429;"); xmlNewProp(node , BAD_CAST "port" , BAD_CAST "443"); node = xmlNewChild(root , NULL , BAD_CAST "fileinfo" , NULL); fnode = xmlNewChild(node , NULL , BAD_CAST "transmit" , NULL); xmlNewProp(fnode , BAD_CAST "type" , BAD_CAST "p2p"); xmlNewProp(fnode , BAD_CAST "session-id" , BAD_CAST share->sessionid); fnode = xmlNewChild(node , NULL , BAD_CAST "file" , NULL); xmlNewProp(fnode , BAD_CAST "name" , BAD_CAST share->filename); memset(size, 0, sizeof(size)); xmlNewProp(fnode , BAD_CAST "size" , BAD_CAST size); xmlNewProp(fnode , BAD_CAST "url" , BAD_CAST ""); xmlNewProp(fnode , BAD_CAST "md5" , BAD_CAST share->md5); xmlNewProp(fnode , BAD_CAST "id" , BAD_CAST share->guid); xmlNewProp(fnode , BAD_CAST "p2ptorelay" , BAD_CAST "1"); xmlNewProp(fnode , BAD_CAST "file-type" , BAD_CAST "unknown"); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } static void fetion_start_transfer(FetionSip *sip){ SipHeader *kheader = NULL; SipHeader *theader = NULL; char *res = NULL; char buf[2048]; fetion_sip_set_type(sip , SIP_SERVICE); kheader = fetion_sip_header_new("N" , "StartTransfer"); theader = fetion_sip_header_new("XI" , SESSIONID); fetion_sip_add_header(sip , kheader); fetion_sip_add_header(sip , theader); res = fetion_sip_to_string(sip , NULL); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); memset(buf, 0, sizeof(buf)); tcp_connection_recv(sip->tcp , buf , sizeof(buf)); printf("%s\n" , buf); } void fetion_share_request(FetionSip *sip , Share *share) { SipHeader *kheader = NULL; SipHeader *theader = NULL; char *res = NULL; char *body = NULL; char buf[2048]; fetion_sip_set_type(sip , SIP_OPTION); kheader = fetion_sip_header_new("K" , "ShareContent"); theader = fetion_sip_header_new("T" , share->sipuri); fetion_sip_add_header(sip , kheader); fetion_sip_add_header(sip , theader); body = generate_share_request_body(share); res = fetion_sip_to_string(sip , body); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); memset(buf, 0, sizeof(buf)); tcp_connection_recv(sip->tcp , buf , sizeof(buf)); printf("%s\n" , buf); fetion_start_transfer(sip); } char* fetion_share_compute_md5(const char *absolutePath) { MD5_CTX ctx; FILE *file; unsigned char input[1024]; unsigned char output[16]; int n , i = 0; char* res = (char*)malloc(33); file = fopen(absolutePath , "r"); MD5_Init(&ctx); while(1) { n = fread(input , 1 , sizeof(input) , file); if(n == 0) break; MD5_Update(&ctx , input , n); } MD5_Final(output , &ctx); memset(res, 0, 33); while(i < 16) { sprintf(res + i * 2 , "%02x" , output[i]); i ++; }; return res; } long long fetion_share_get_filesize(const char *absolutePath) { struct stat sb; if(stat(absolutePath , &sb) == -1) { debug_error("Can not get the file size"); return -1; } return (long long)(sb.st_size); } libofetion-2.2.2/fetion_message.h0000644000175000017500000000630711700115314015467 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_MESSAGE_H #define FETION_MESSAGE_H extern Message* fetion_message_new(); extern int fetion_message_set_sipuri(Message* msg , const char* sipuri); extern int fetion_message_set_pguri(Message* msg , const char* sipuri); extern int fetion_message_set_message(Message* msg , const char* message); extern void fetion_message_set_time(Message* msg , struct tm sendtime); extern void fetion_message_set_callid(Message* msg , int callid); extern void fetion_message_free(Message* msg); extern struct unacked_list *unacked_list_new(Message *message); extern void unacked_list_append(struct unacked_list *head, struct unacked_list *newnode); extern void unacked_list_remove(struct unacked_list *head, struct unacked_list *delnode); #define unacked_list_empty(head) (head->next == head) #define foreach_unacked_list(head,c) \ for(c=head;(c=c->next)!=head;) extern char* contruct_message_sip(const char *sid, Message *msg); #endif libofetion-2.2.2/fetion_message.c0000644000175000017500000001270611700115314015462 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include Message* fetion_message_new() { Message* msg = (Message*)malloc(sizeof(Message)); if(msg == NULL){ return NULL; } memset(msg , 0 , sizeof(Message)); msg->sipuri = NULL; msg->pguri = NULL; msg->message = NULL; return msg; } int fetion_message_set_pguri(Message* msg , const char* sipuri) { if(msg == NULL){ debug_error("Message is NULL , at(fetion_message_set_sipuri)"); return -1; } char *tmp = (char*)malloc(strlen(sipuri) + 1); if(tmp == NULL){ return -1; } msg->pguri = tmp; memset(msg->pguri , 0 , strlen(sipuri) + 1); strcpy(msg->pguri , sipuri); return 0; } int fetion_message_set_sipuri(Message* msg , const char* sipuri) { if(msg == NULL){ debug_error("Message is NULL , at(fetion_message_set_sipuri)"); return -1; } char *tmp = (char*)malloc(strlen(sipuri) + 1); if(tmp == NULL){ return -1; } msg->sipuri = tmp; memset(msg->sipuri , 0 , strlen(sipuri) + 1); strcpy(msg->sipuri , sipuri); return 0; } int fetion_message_set_message(Message* msg , const char* message) { if(msg == NULL) { debug_error("Message is NULL , at(fetion_message_set_message)"); return -1; } char *tmp = (char*)malloc(strlen(message) + 1); if(tmp == NULL){ return -1; } msg->message = tmp; memset(msg->message , 0 , strlen(message) + 1); strcpy(msg->message , message); return 0; } void fetion_message_set_time(Message* msg , struct tm sendtime) { if(msg == NULL) { debug_error("Message is NULL , at(fetion_message_set_time)"); return; } msg->sendtime = sendtime; } void fetion_message_set_callid(Message* msg , int callid) { if(msg == NULL) { debug_error("Message is NULL , at(fetion_message_set_callid)"); return; } msg->callid = callid; } void fetion_message_free(Message* msg) { if(msg != NULL) { if(msg->sipuri != NULL) free(msg->sipuri); if(msg->message != NULL) free(msg->message); free(msg); } } struct unacked_list *unacked_list_new(Message *message) { struct unacked_list *list = (struct unacked_list*)malloc(sizeof(struct unacked_list)); if(list == NULL){ return NULL; } list->timeout = 0; list->message = message; list->next = list->pre = list; return list; } void unacked_list_append(struct unacked_list *head , struct unacked_list *newnode) { head->next->pre = newnode; newnode->next = head->next; newnode->pre = head; head->next = newnode; } void unacked_list_remove(struct unacked_list *head, struct unacked_list *delnode) { delnode->next->pre = delnode->pre; delnode->pre->next = delnode->next; if(delnode->timeout && head->timeout) head->timeout --; } char* contruct_message_sip(const char *sid, Message *msg) { char *res; char time[128]; char buffer[2048]; struct tm st = msg->sendtime; memset(time , 0 , sizeof(time)); st.tm_hour -= 8; strftime(time , sizeof(time), ", %d Sep %Y %T GMT" , &st); snprintf(buffer , sizeof(buffer) - 1 , "M %s SIP-C/3.0\r\n" "I: 15\r\n" "Q: 5 M\r\n" "F: %s\r\n" "C: text/html-fragment\r\n" "K: SaveHistory\r\n" "D: %s\r\n" "XI: BB6EE2B50BB01CA526C194D0C99B99FE\r\n\r\n%s", sid , msg->sipuri , time, msg->message); res = (char*)malloc(strlen(buffer) + 1); memset(res , 0 , strlen(buffer) + 1); strcpy(res , buffer); return res; } libofetion-2.2.2/fetion_login.h0000644000175000017500000001312511700115314015147 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_LOGIN_H #define FETION_LOGIN_H enum { PASSWORD_ERROR_MAX = 0 }; /** * ssi login through https to get some information as user-id * @param user Global User object initialized before login * @return Returns the response string by ssi server * NULL if error occuered , need to be freed after use. */ extern char* ssi_auth_action(User *user); /** * sipc register action to sipc server. * @param user Global User object initialized before login * @returns Returns the response string by sipc server * NULL if error occured , need to be freed after use. */ extern char* sipc_reg_action(User *user); /** * parse the ssi registration response string to get information as user-id * @param ssi_response The return value of function ssi_auth_action. * @param user Global User object initialized before login. * The result code will be store in its member variable 'loginStatus' */ extern void parse_ssi_auth_response(const char *ssi_response, User *user); /** * parse the sipc registration response string to get nonce string and key string * for sipc authentication * @param reg_response The return value of function sipc_auth_action * @param nouce Will be filled by the nonce string parsed from reg_response. * need to be freed after use. * @param key Will be filled by the key string parsed from reg_response. * need to be freed after use. */ extern void parse_sipc_reg_response(const char *reg_response, char **nouce, char **key) ; /** * generate response string for sipc authentication. * @param nouce. Nonce string get from function "parse_sipc_reg_response()" * @param userid. UserId get from ssi register result. * @param password. Nothing special,just your password. * @param publickey. Key string get from function "parse_sipc_reg_response()" , which in fact unused. * @param key. Private key string need for generate sipc authentication response string. * and can be generated by the function "generate_aes_key()" * @return The response string generated for sipc authentication.Need to be freed after use. */ extern char* generate_response(const char *nouce, const char *userid, const char *password, const char *publickey, const char *key); /** * sipc authentication using the response string generated by the function "generate_response()" * @param user Global User object initialized before login. * @return sipc authencation response string from sipc server.Need to be freed after use. */ extern char* sipc_aut_action(User *user, const char *response); /** * parse the user`s personal information and user`s contact information * from the sipc authentication response string. * @param auth_response. Response string returns by the function "sipc_aut_action()" * @user Global User object initialized before login,and will be filled with * user`s personal information and user`s contact list information if success, * orelse the member variable "loginStatus" will be filled with errno. */ extern int parse_sipc_auth_response(const char *auth_response, User *user, int *group_count, int *buddy_count); /** * generate comfirm code picture. */ extern void generate_pic_code(User *user); /** * generate private key string for generating response string for sipc authentication * @returns Need to be freed after use. */ extern char* generate_aes_key(); extern char* hash_password(const char *password); #endif libofetion-2.2.2/fetion_login.c0000644000175000017500000007016611700115314015152 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include #include #include /*private method*/ static char* generate_auth_body(User *user); static void parse_personal_info(xmlNodePtr node, User *user); static void parse_contact_list(xmlNodePtr node, User *user, int *group_count, int *buddy_count); static void parse_stranger_list(xmlNodePtr node, User *user); static void parse_ssi_auth_success(xmlNodePtr node, User *user); static void parse_ssi_auth_failed(xmlNodePtr node, User *user); static unsigned char *strtohex(const char *in , int *len) ; static char *hextostr(const unsigned char *in , int len) ; static char *hash_password_v1(const unsigned char* b0 , int b0len , const unsigned char* password , int psdlen); static char *hash_password_v2(const char *userid, const char *passwordhex); static char *hash_password_v4(const char *userid, const char *password); static char *hash_password_v5(const char *userid, const char *hashed_password); static char *generate_cnouce() ; static unsigned char *decode_base64(const char* in , int* len); char* generate_response(const char *nouce, const char *userid, const char *password, const char *publickey, const char *key) { char* psdhex = hash_password_v4(userid , password); char modulus[257]; char exponent[7]; int ret, flen; BIGNUM *bnn, *bne; unsigned char *out; unsigned char *nonce , *aeskey , *psd , *res; int nonce_len , aeskey_len , psd_len; RSA *r = RSA_new(); key = NULL; memset(modulus, 0, sizeof(modulus)); memset(exponent, 0, sizeof(exponent)); memcpy(modulus , publickey , 256); memcpy(exponent , publickey + 256 , 6); nonce = (unsigned char*)malloc(strlen(nouce) + 1); memset(nonce , 0 , strlen(nouce) + 1); memcpy(nonce , (unsigned char*)nouce , strlen(nouce)); nonce_len = strlen(nouce); psd = strtohex(psdhex , &psd_len); aeskey = strtohex(generate_aes_key() , &aeskey_len); res = (unsigned char*)malloc(nonce_len + aeskey_len + psd_len + 1); memset(res , 0 , nonce_len + aeskey_len + psd_len + 1); memcpy(res , nonce , nonce_len); memcpy(res + nonce_len , psd , psd_len ); memcpy(res + nonce_len + psd_len , aeskey , aeskey_len); bnn = BN_new(); bne = BN_new(); BN_hex2bn(&bnn, modulus); BN_hex2bn(&bne, exponent); r->n = bnn; r->e = bne; r->d = NULL; // RSA_print_fp(stdout, r, 5); flen = RSA_size(r); out = (unsigned char*)malloc(flen); memset(out , 0 , flen); debug_info("Start encrypting response"); ret = RSA_public_encrypt(nonce_len + aeskey_len + psd_len, res , out, r, RSA_PKCS1_PADDING); if (ret < 0){ debug_info("Encrypt response failed!"); free(res); free(aeskey); free(psd); free(nonce); return NULL; } RSA_free(r); debug_info("Encrypting reponse success"); free(res); free(aeskey); free(psd); free(nonce); return hextostr(out , ret); } void generate_pic_code(User *user) { char buf[1024] , *res , *code; char codePath[128]; char cookie[1024]; char* ip; FILE* picfd; int piclen = 0; unsigned char* pic; int n; Config *config = user->config; xmlDocPtr doc; xmlNodePtr node; memset(buf , 0 , sizeof(buf)); ip = get_ip_by_name(NAVIGATION_URI); FetionConnection* con = tcp_connection_new(); if(config->proxy != NULL && config->proxy->proxyEnabled) tcp_connection_connect_with_proxy(con , ip, 80 , config->proxy); else tcp_connection_connect(con , ip , 80); memset(cookie , 0 , sizeof(cookie)); if(user->ssic){ sprintf(cookie , "Cookie: ssic=%s\r\n" , user->ssic); } sprintf(buf , "GET /nav/GetPicCodeV4.aspx?algorithm=%s HTTP/1.1\r\n" "%sHost: %s\r\n" "User-Agent: IIC2.0/PC "PROTO_VERSION"\r\n" "Connection: close\r\n\r\n" , user->verification->algorithm == NULL ? "" : user->verification->algorithm , user->ssic == NULL ? "" : cookie , NAVIGATION_URI); tcp_connection_send(con , buf , strlen(buf)); res = http_connection_get_response(con); tcp_connection_free(con); doc = xmlParseMemory(res , strlen(res)); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; user->verification->guid = (char*)xmlGetProp(node , BAD_CAST "id"); code = (char*)xmlGetProp(node , BAD_CAST "pic"); xmlFreeDoc(doc); debug_info("Generating verification code picture"); pic = decode_base64(code , &piclen); free(code); memset(codePath, 0, sizeof(codePath)); sprintf(codePath , "%s/code.gif" , user->config->globalPath); picfd = fopen(codePath , "wb+"); n = 0; for(; n != piclen ;){ n += fwrite(pic + n , 1 , piclen - n , picfd); } fclose(picfd); free(res); } char *ssi_auth_action(User *user) { char sslbuf[2048] = { 0 }; const char ssiName[] = "uid.fetion.com.cn"; char noUri[128]; char verifyUri[256]; char *password , *ssi_ip , *res; int passwordType; debug_info("Initialize ssi authentication action"); if(strlen(user->password) == 40) /* must be a hashed password */ password = hash_password_v5(user->userId, user->password); else password = hash_password_v4(user->userId, user->password); memset(noUri, 0, sizeof(noUri)); if(user->loginType == LOGIN_TYPE_MOBILENO) sprintf(noUri , "mobileno=%s" , user->mobileno); else sprintf(noUri , "sid=%s" , user->sId); memset(verifyUri, 0, sizeof(verifyUri)); if(user->verification != NULL && user->verification->code != NULL) { sprintf(verifyUri , "&pid=%s&pic=%s&algorithm=%s" , user->verification->guid , user->verification->code , user->verification->algorithm); } passwordType = (strlen(user->userId) == 0 ? 1 : 2); sprintf(sslbuf, "GET /ssiportal/SSIAppSignInV4.aspx?%s" "&domains=fetion.com.cn%s&v4digest-type=%d&v4digest=%s\r\n" "User-Agent: IIC2.0/pc "PROTO_VERSION"\r\n" "Host: %s\r\n" "Cache-Control: private\r\n" "Connection: Keep-Alive\r\n\r\n", noUri , verifyUri , passwordType , password , "uid.fetion.com.cn"); ssi_ip = get_ip_by_name(ssiName); FetionConnection* ssl; ssl = tcp_connection_new(); if(user->config->proxy != NULL && user->config->proxy->proxyEnabled) { int ret; ret = tcp_connection_connect_with_proxy(ssl , ssi_ip , 443 , user->config->proxy); if(ret < 0) return NULL; } else { if(tcp_connection_connect(ssl , ssi_ip , 443) < 0) return NULL; } debug_info("Start ssi login with %s password , user number %s" , passwordType == 1 ? "v3Temp" : "v4" , user->loginType == LOGIN_TYPE_MOBILENO ? user->mobileno : user->sId); if(ssl_connection_start(ssl) == -1) { debug_error("Initialize ssl failed,please retry or check your system`s configuration"); return NULL; } res = ssl_connection_get(ssl , sslbuf); tcp_connection_free(ssl); free(password); free(ssi_ip); return res; } char *sipc_reg_action(User *user) { char* sipmsg; char* cnouce = generate_cnouce(); FetionSip* sip = user->sip; debug_info("Initialize sipc registeration action"); fetion_sip_set_type(sip , SIP_REGISTER); SipHeader* cheader = fetion_sip_header_new("CN" , cnouce); SipHeader* client = fetion_sip_header_new("CL" , "type=\"pc\" ,version=\""PROTO_VERSION"\""); fetion_sip_add_header(sip , cheader); fetion_sip_add_header(sip , client); free(cnouce); sipmsg = fetion_sip_to_string(sip , NULL); debug_info("Start registering to sip server(%s:%d)" , sip->tcp->remote_ipaddress , sip->tcp->remote_port); tcp_connection_send(sip->tcp , sipmsg , strlen(sipmsg)); free(sipmsg); #if 0 sipmsg = (char*)malloc(1024); memset(sipmsg, 0 , 1024); if(tcp_connection_recv(sip->tcp , sipmsg , 1023) <= 0){ debug_info("Network error occured here"); return NULL; } #endif sipmsg = fetion_sip_get_response(sip); return sipmsg; } char* sipc_aut_action(User* user , const char* response) { char* sipmsg; char* xml; char* res; SipHeader* aheader = NULL; SipHeader* akheader = NULL; SipHeader* ackheader = NULL; FetionSip* sip = user->sip; debug_info("Initialize sipc authencation action"); xml = generate_auth_body(user); fetion_sip_set_type(sip , SIP_REGISTER); aheader = fetion_sip_authentication_header_new(response); akheader = fetion_sip_header_new("AK" , "ak-value"); fetion_sip_add_header(sip , aheader); fetion_sip_add_header(sip , akheader); if(user->verification != NULL && user->verification->algorithm != NULL) { ackheader = fetion_sip_ack_header_new(user->verification->code , user->verification->algorithm , user->verification->type , user->verification->guid); fetion_sip_add_header(sip , ackheader); } sipmsg = fetion_sip_to_string(sip , xml); debug_info("Start sipc authentication , with ak-value"); tcp_connection_send(sip->tcp , sipmsg , strlen(sipmsg)); res = fetion_sip_get_response(sip); debug_info("Got sipc response"); //free(sipmsg); return res; } void parse_ssi_auth_response(const char* ssi_response , User* user) { xmlDocPtr doc; xmlNodePtr node; char* pos; char* xml = strstr(ssi_response , "\r\n\r\n") + 4; if(strstr(ssi_response , "ssic=")){ int n; pos = strstr(ssi_response , "ssic=") + 5; n = strlen(pos) - strlen(strstr(pos , ";")); user->ssic = (char*)malloc(n + 1); memset(user->ssic, 0, n + 1); strncpy(user->ssic , pos , n); } doc = xmlReadMemory(xml , strlen(xml) , NULL , "UTF-8" , XML_PARSE_RECOVER); node = xmlDocGetRootElement(doc); pos = (char*)xmlGetProp(node , BAD_CAST "status-code"); user->loginStatus = atoi(pos); node = node->xmlChildrenNode; if(atoi(pos) == 200) { debug_info("SSI login success"); parse_ssi_auth_success(node , user); } else { debug_info("SSI login failed , status-code :%s" , pos); parse_ssi_auth_failed(node , user); } free(pos); xmlFreeDoc(doc); } void parse_sipc_reg_response(const char* reg_response , char** nouce , char** key) { char digest[2048] = { 0 }; char* pos; int n; fetion_sip_get_attr(reg_response , "W" , digest); pos = strstr(digest , "nonce") + 7; n = strlen(pos) - strlen(strstr(pos , "\",")); *nouce = (char*)malloc(n + 1); strncpy(*nouce , pos , n); (*nouce)[n] = '\0'; pos = strstr(pos , "key") + 5; n = strlen(pos) - strlen(strstr(pos , "\",")); *key = (char*)malloc(n + 1); strncpy(*key , pos , n); (*key)[n] = '\0'; debug_info("Register to sip server success"); debug_info("nonce:%s" , *nouce); } static void parse_sms_frequency(xmlNodePtr node , User *user) { xmlChar *res; node = node->xmlChildrenNode; if(xmlHasProp(node , BAD_CAST "day-limit")){ res = xmlGetProp(node , BAD_CAST "day-limit"); user->smsDayLimit = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "day-count")){ res = xmlGetProp(node , BAD_CAST "day-count"); user->smsDayCount = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "month-limit")){ res = xmlGetProp(node , BAD_CAST "month-limit"); user->smsMonthLimit = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "month-count")){ res = xmlGetProp(node , BAD_CAST "month-count"); user->smsMonthCount = atoi((char*)res); xmlFree(res); } } int parse_sipc_auth_response(const char* auth_response , User* user, int *group_count, int *buddy_count) { char *pos; xmlChar* buf = NULL; xmlDocPtr doc = NULL; xmlNodePtr rootnode = NULL; xmlNodePtr node = NULL; xmlNodePtr node1 = NULL; int code; code = fetion_sip_get_code(auth_response); user->loginStatus = code; if(code == 200){ fetion_verification_free(user->verification); user->verification = NULL; debug_info("Sipc authentication success"); }else if(code == 421 || code == 420){ parse_add_buddy_verification(user , auth_response); return 2; }else{ debug_error("Sipc authentication failed\n"); printf("%s\n", auth_response); return -1; } if(!strstr(auth_response, "\r\n\r\n")) return -1; pos = strstr(auth_response , "\r\n\r\n") + 4; if(!pos) return -1; doc = xmlParseMemory(pos , strlen(pos)); if(!doc) return -1; rootnode = xmlDocGetRootElement(doc); node = rootnode->xmlChildrenNode; buf = xmlGetProp(node , BAD_CAST "public-ip"); strcpy(user->publicIp , (char*)buf); xmlFree(buf); buf = xmlGetProp(node , BAD_CAST "last-login-ip"); strcpy(user->lastLoginIp , (char*)buf); xmlFree(buf); buf = xmlGetProp(node , BAD_CAST "last-login-time"); strcpy(user->lastLoginTime , (char*)buf); xmlFree(buf); node = node->next; node1 = node->xmlChildrenNode; parse_personal_info(node1 , user); node1 = xml_goto_node(node , "custom-config"); buf = xmlGetProp(node1 , BAD_CAST "version"); strcpy(user->customConfigVersion , (char*)buf); xmlFree(buf); buf = xmlNodeGetContent(node1); if(xmlStrlen(buf) > 0){ user->customConfig = malloc(strlen((char*)buf) + 1); memset(user->customConfig , 0 , strlen((char*)buf) + 1); strcpy(user->customConfig , (char*)buf); } xmlFree(buf); node1 = xml_goto_node(node , "contact-list"); parse_contact_list(node1 , user, group_count, buddy_count); node1 = xml_goto_node(node , "chat-friends"); if(node1) parse_stranger_list(node1 , user); node1 = xml_goto_node(node , "quota-frequency"); if(node1) parse_sms_frequency(node1 , user); xmlFreeDoc(doc); return 1; } char* generate_aes_key() { char* key = (char*)malloc(65); if(key == NULL){ return NULL; } memset( key , 0 , 65 ); FILE* rand_fd = fopen("/dev/urandom", "r"); if(rand_fd == NULL){ free(key); return NULL; } int ret = fread(key, 64, 1, rand_fd); if(ret != 1){ free(key); fclose(rand_fd); return NULL; } fclose(rand_fd); return key; } static char* generate_auth_body(User* user) { char basexml[] = ""; char state[5]; xmlChar* buf = NULL; xmlDocPtr doc = NULL; xmlNodePtr rootnode = NULL; xmlNodePtr node = NULL; xmlNodePtr node1 = NULL; doc = xmlParseMemory( basexml , strlen(basexml)); rootnode = xmlDocGetRootElement(doc); node = xmlNewChild(rootnode , NULL , BAD_CAST "device" , NULL); xmlNewProp(node , BAD_CAST "machine-code" , BAD_CAST "001676C0E351"); node = xmlNewChild(rootnode , NULL , BAD_CAST "caps" , NULL); xmlNewProp(node , BAD_CAST "value" , BAD_CAST "1ff"); node = xmlNewChild(rootnode , NULL , BAD_CAST "events" , NULL); xmlNewProp(node , BAD_CAST "value" , BAD_CAST "7f"); node = xmlNewChild(rootnode , NULL , BAD_CAST "user-info" , NULL); xmlNewProp(node , BAD_CAST "mobile-no" , BAD_CAST user->mobileno); xmlNewProp(node , BAD_CAST "user-id" , BAD_CAST user->userId); node1 = xmlNewChild(node , NULL , BAD_CAST "personal" , NULL); xmlNewProp(node1 , BAD_CAST "version" , BAD_CAST "0"/*user->personalVersion*/); xmlNewProp(node1 , BAD_CAST "attributes" , BAD_CAST "v4default"); node1 = xmlNewChild(node , NULL , BAD_CAST "custom-config" , NULL); xmlNewProp(node1 , BAD_CAST "version" , BAD_CAST "0"/*user->customConfigVersion*/); node1 = xmlNewChild(node , NULL , BAD_CAST "contact-list" , NULL); xmlNewProp(node1 , BAD_CAST "version" , BAD_CAST "0"/*user->contactVersion*/); xmlNewProp(node1 , BAD_CAST "buddy-attributes" , BAD_CAST "v4default"); node = xmlNewChild(rootnode , NULL , BAD_CAST "credentials" , NULL); xmlNewProp(node , BAD_CAST "domains" , BAD_CAST "fetion.com.cn"); node = xmlNewChild(rootnode , NULL , BAD_CAST "presence" , NULL); node1 = xmlNewChild(node , NULL , BAD_CAST "basic" , NULL); sprintf(state , "%d" , user->state); xmlNewProp(node1 , BAD_CAST "value" , BAD_CAST state); xmlNewProp(node1 , BAD_CAST "desc" , BAD_CAST ""); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } static void parse_personal_info(xmlNodePtr node , User* user) { xmlChar *buf; char *pos; buf = xmlGetProp(node , BAD_CAST "version"); strcpy(user->personalVersion , (char*)buf); xmlFree(buf); if(xmlHasProp(node , BAD_CAST "sid")) { buf = xmlGetProp(node , BAD_CAST "sid"); strcpy(user->sId , (char*)buf); xmlFree(buf); } if(xmlHasProp(node , BAD_CAST "mobile-no")) { buf = xmlGetProp(node , BAD_CAST "mobile-no"); if(xmlStrlen(buf)){ user->boundToMobile = BOUND_MOBILE_ENABLE; }else{ user->boundToMobile = BOUND_MOBILE_DISABLE; } strcpy(user->mobileno , (char*)buf); xmlFree(buf); } if(xmlHasProp(node , BAD_CAST "carrier-status")) { buf = xmlGetProp(node , BAD_CAST "carrier-status"); user->carrierStatus = atoi((char*)buf); xmlFree(buf); } if(xmlHasProp(node , BAD_CAST "nickname")) { buf = xmlGetProp(node , BAD_CAST "nickname"); strcpy(user->nickname , (char*)buf); xmlFree(buf); } if(xmlHasProp(node , BAD_CAST "gender")) { buf = xmlGetProp(node , BAD_CAST "gender"); user->gender = atoi((char*)buf); xmlFree(buf); } if(xmlHasProp(node , BAD_CAST "sms-online-status")) { buf = xmlGetProp(node , BAD_CAST "sms-online-status"); strcpy(user->smsOnLineStatus , (char*)buf); xmlFree(buf); } if(xmlHasProp(node , BAD_CAST "impresa")) { buf = xmlGetProp(node , BAD_CAST "impresa"); strcpy(user->impression , (char*)buf); xmlFree(buf); } if(xmlHasProp(node , BAD_CAST "carrier-region")) { int n; buf = xmlGetProp(node , BAD_CAST "carrier-region"); pos = (char*)buf; n = strlen(pos) - strlen(strstr(pos , ".")); strncpy(user->country , pos , n); pos = strstr(pos , ".") + 1; n = strlen(pos) - strlen(strstr(pos , ".")); strncpy(user->province , pos , n); pos = strstr(pos , ".") + 1; n = strlen(pos) - strlen(strstr(pos , ".")); strncpy(user->city , pos , n); xmlFree(buf); } } static void parse_contact_list(xmlNodePtr node, User* user, int *group_count, int *buddy_count) { xmlChar* buf = NULL; xmlNodePtr node1 , node2; Group* group = NULL; Contact* contact = NULL; int hasGroup = 1 , hasBuddy = 1; int nr = 0; *group_count = 0; *buddy_count = 0; buf = xmlGetProp(node , BAD_CAST "version"); debug_info("Start reading contact list "); if(strcmp(user->contactVersion , (char*) buf) == 0){ debug_info("Contact list is the same as that stored in the local disk!"); return ; } strcpy(user->contactVersion , (char*)buf); xmlFree(buf); node1 = xml_goto_node(node , "buddy-lists"); node2 = node1->xmlChildrenNode; user->groupCount = 0; while(node2 != NULL){ hasGroup = 1; buf = xmlGetProp(node2 , BAD_CAST "id"); group = fetion_group_list_find_by_id(user->groupList , atoi((char*)buf)); if(group == NULL){ hasGroup = 0; group = fetion_group_new(); } group->groupid = atoi((char*)buf); xmlFree(buf); buf = xmlGetProp(node2 , BAD_CAST "name"); strcpy(group->groupname , (char*)buf); xmlFree(buf); nr ++; group->dirty = 1; user->groupCount ++; if(hasGroup == 0){ fetion_group_list_append(user->groupList , group); hasGroup = 1; } node2 = node2->next; } *group_count = nr; nr = 0; node1 = xml_goto_node(node , "buddies"); node1 = node1->xmlChildrenNode; user->contactCount = 0; while(node1 != NULL){ hasBuddy = 1; if(! xmlHasProp(node1 , BAD_CAST "i")){ node1 = node1->next; continue; } buf = xmlGetProp(node1 , BAD_CAST "i"); contact = fetion_contact_list_find_by_userid(user->contactList , (char*)buf); if(contact == NULL){ hasBuddy = 0; contact = fetion_contact_new(); } strcpy(contact->userId , (char*)buf); xmlFree(buf); /* maybe a buddy belongs to two groups */ if(contact->dirty == 1){ node = node->next; continue; } user->contactCount ++; /* set the dirty flags */ contact->dirty = 1; nr ++; if(xmlHasProp(node1 , BAD_CAST "n")){ buf = xmlGetProp(node1 , BAD_CAST "n"); strcpy(contact->localname , (char*)buf); xmlFree(buf); } if(xmlHasProp(node1 , BAD_CAST "l")){ buf = xmlGetProp(node1 , BAD_CAST "l"); strncpy(contact->groupids, (char*)buf, sizeof(contact->groupids) - 1); if(strlen(contact->groupids) == 0) strcpy(contact->groupids, "0"); contact->groupid = atoi((char*)buf); if(xmlStrstr(buf , BAD_CAST ";") != NULL || contact->groupid < 0) contact->groupid = 0; xmlFree(buf); } if(xmlHasProp(node1 , BAD_CAST "p")){ buf = xmlGetProp(node1 , BAD_CAST "p"); if(strstr((char*)buf , "identity=1") != NULL) contact->identity = 1; else contact->identity = 0; xmlFree(buf); } if(xmlHasProp(node1 , BAD_CAST "r")){ buf = xmlGetProp(node1 , BAD_CAST "r"); contact->relationStatus = atoi((char*)buf); xmlFree(buf); } if(xmlHasProp(node1 , BAD_CAST "u")){ buf = xmlGetProp(node1 , BAD_CAST "u"); strcpy(contact->sipuri , (char*)buf); //if(strstr((char*)buf , "tel") != NULL) // contact->serviceStatus = STATUS_SMS_ONLINE; xmlFree(buf); } strcpy(contact->portraitCrc , "0"); if(hasBuddy == 0){ fetion_contact_list_append(user->contactList , contact); hasBuddy = 1; } node1 = node1->next; } *buddy_count = nr; debug_info("Read contact list complete"); } static void parse_stranger_list(xmlNodePtr node , User* user) { xmlNodePtr node1 = node->xmlChildrenNode; xmlChar *buf = NULL; Contact *contact = NULL; int hasBuddy; while(node1 != NULL) { hasBuddy = 1; user->contactCount ++; buf = xmlGetProp(node1 , BAD_CAST "i"); contact = fetion_contact_list_find_by_userid(user->contactList , (char*)buf); if(contact == NULL){ hasBuddy = 0; contact = fetion_contact_new(); } strcpy(contact->userId , (char*)buf); xmlFree(buf); buf = xmlGetProp(node1 , BAD_CAST "u"); strcpy(contact->sipuri , (char*)buf); contact->groupid = BUDDY_LIST_STRANGER; contact->dirty = 1; if(hasBuddy == 0) fetion_contact_list_append(user->contactList , contact); node1 = node1->next; } } static void parse_ssi_auth_success(xmlNodePtr node , User* user) { char* pos; pos = (char*)xmlGetProp(node , BAD_CAST "uri"); strcpy(user->sipuri , pos); free(pos); pos = fetion_sip_get_sid_by_sipuri(user->sipuri); strcpy(user->sId , pos); free(pos); pos = (char*)xmlGetProp(node , BAD_CAST "mobile-no"); strcpy(user->mobileno , pos); free(pos); pos = (char*)xmlGetProp(node , BAD_CAST "user-id"); strcpy(user->userId , pos); free(pos); } static void parse_ssi_auth_failed(xmlNodePtr node , User* user) { Verification* ver = fetion_verification_new(); ver->algorithm = (char*)xmlGetProp(node , BAD_CAST "algorithm"); ver->type = (char*)xmlGetProp(node , BAD_CAST "type"); ver->text = (char*)xmlGetProp(node , BAD_CAST "text"); ver->tips = (char*)xmlGetProp(node , BAD_CAST "tips"); user->verification = ver; } static unsigned char* strtohex(const char* in , int* len) { unsigned char* out = (unsigned char*)malloc(strlen(in)/2 ); int i = 0 , j = 0 , k = 0 ,length = 0; char tmp[3] = { 0 }; memset(out , 0 , strlen(in) / 2); int inlength; inlength=(int)strlen(in); while(i < inlength) { tmp[k++] = in[i++]; tmp[k] = '\0'; if(k == 2) { out[j++] = (unsigned char)strtol(tmp , (char**)NULL , 16); k = 0; length ++; } } if(len != NULL ) *len = length; return out; } static char* hextostr(const unsigned char* in , int len) { char* res = (char*)malloc(len * 2 + 1); int i = 0; memset(res , 0 , len * 2 + 1); while(i < len) { sprintf(res + i * 2 , "%02x" , in[i]); i ++; }; i = 0; int reslength; reslength=(int)strlen(res); while(i < reslength) { res[i] = toupper(res[i]); i ++; }; return res; } static char* hash_password_v1(const unsigned char* b0 , int b0len , const unsigned char* password , int psdlen) { unsigned char* dst = (unsigned char*)malloc(b0len + psdlen + 1); unsigned char tmp[20]; char* res; memset(tmp , 0 , sizeof(tmp)); memset(dst , 0 , b0len + psdlen + 1); memcpy(dst , b0 , b0len); memcpy(dst + b0len , password , psdlen); SHA_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx , dst , b0len + psdlen ); SHA1_Final(tmp , &ctx); free(dst); res = hextostr(tmp , 20); return res; } static char* hash_password_v2(const char* userid , const char* passwordhex) { int id = atoi(userid); char* res; unsigned char* bid = (unsigned char*)(&id); unsigned char ubid[4]; int bpsd_len; unsigned char* bpsd = strtohex(passwordhex , &bpsd_len); memcpy(ubid , bid , 4); res = hash_password_v1(ubid , sizeof(id) , bpsd , bpsd_len); free(bpsd); return res; } static char* hash_password_v4(const char* userid , const char* password) { const char* domain = "fetion.com.cn:"; char *res , *dst; unsigned char* udomain = (unsigned char*)malloc(strlen(domain)); unsigned char* upassword = (unsigned char*)malloc(strlen(password)); memset(udomain , 0 , strlen(domain)); memcpy(udomain , (unsigned char*)domain , strlen(domain)); memset(upassword , 0 , strlen(password)); memcpy(upassword , (unsigned char*)password , strlen(password)); res = hash_password_v1(udomain , strlen(domain) , upassword , strlen(password)); free(udomain); free(upassword); if(userid == NULL || *userid == '\0') return res; dst = hash_password_v2(userid , res); free(res); return dst; } char* hash_password(const char* password) { const char* domain = "fetion.com.cn:"; char *res; unsigned char* udomain = (unsigned char*)malloc(strlen(domain)); unsigned char* upassword = (unsigned char*)malloc(strlen(password)); memset(udomain , 0 , strlen(domain)); memcpy(udomain , (unsigned char*)domain , strlen(domain)); memset(upassword , 0 , strlen(password)); memcpy(upassword , (unsigned char*)password , strlen(password)); res = hash_password_v1(udomain , strlen(domain) , upassword , strlen(password)); free(udomain); free(upassword); return res; } /* login with the hashed password stored locally */ static char *hash_password_v5(const char *userid, const char *hashed_password) { char *res, *dst; int len = 0; if(userid == NULL || *userid == '\0') { len = strlen(hashed_password); res = (char*)malloc(len + 1); strncpy(res, hashed_password, len); res[len] = '\0'; return res; } dst = hash_password_v2(userid, hashed_password); return dst; } static char* generate_cnouce() { char* cnouce = (char*)malloc(33); memset( cnouce , 0 , 33 ); sprintf( cnouce , "%04X%04X%04X%04X%04X%04X%04X%04X" , rand() & 0xFFFF , rand() & 0xFFFF , rand() & 0xFFFF , rand() & 0xFFFF , rand() & 0xFFFF , rand() & 0xFFFF, rand() & 0xFFFF , rand() & 0xFFFF ); return cnouce; } static unsigned char* decode_base64(const char* in , int* len) { unsigned int n , t = 0 , c = 0; unsigned char* res; unsigned char out[3]; unsigned char inp[4]; n = strlen(in); if(n % 4 != 0) { debug_error("Try to decode a string which is not a base64 string(decode_base64)"); return NULL; } n = n / 4 * 3; if(len != NULL) *len = n; res = (unsigned char*)malloc(n); memset(res , 0 , n); while(1) { memset(inp , 0 , 4); memset(out , 0 , 3); memcpy(inp , in + c , 4); c += 4; n = EVP_DecodeBlock(out , inp , 4 ); memcpy(res + t , out , n); t += n; if(c >= strlen(in)) break; } return res; } libofetion-2.2.2/fetion_list.h0000644000175000017500000000541311700115314015013 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_LIST_H #define FETION_LIST_H #define foreach_list(head , item) \ for(item = head; (item = item->next) != head; ) #define foreach_list_back(head , item) \ for(item = head; (item = item->pre) != head; ) #define list_empty(list) (list->next == list) extern FxList* fx_list_new(void *data); extern void fx_list_free(); extern void fx_list_append(FxList *fxlist , FxList *fxitem); extern void fx_list_prepend(FxList *fxlist , FxList *fxitem); extern void fx_list_remove(FxList *fxitem); #endif libofetion-2.2.2/fetion_list.c0000644000175000017500000000576311700115314015016 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include FxList* fx_list_new(void* data) { FxList* fxlist = (FxList*)malloc(sizeof(FxList)); memset(fxlist , 0 , sizeof(FxList)); fxlist->pre = fxlist; fxlist->data = data; fxlist->next = fxlist; return fxlist; } void fx_list_free(FxList *fxlist) { if(fxlist != NULL) free(fxlist); } void fx_list_append(FxList *fxlist , FxList *fxitem) { fxlist->next->pre = fxitem; fxitem->next = fxlist->next; fxitem->pre = fxlist; fxlist->next = fxitem; } void fx_list_prepend(FxList *fxlist , FxList *fxitem) { fxlist->pre->next = fxitem; fxitem->pre = fxlist->pre; fxitem->next = fxlist; fxlist->pre = fxitem; } void fx_list_remove(FxList *fxitem) { fxitem->next->pre = fxitem->pre; fxitem->pre->next = fxitem->next; } libofetion-2.2.2/fetion_include.h0000644000175000017500000000614611700115314015467 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_INCLUDE_H #define FETION_INCLUDE_H #include #include #include #include #include #define _XOPEN_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "fetion_types.h" #include "fetion_list.h" #include "fetion_debug.h" #include "fetion_message.h" #include "fetion_connection.h" #include "fetion_sip.h" #include "fetion_user.h" #include "fetion_contact.h" #include "fetion_login.h" #include "fetion_config.h" #include "fetion_conversation.h" #include "fetion_buddylist.h" #include "fetion_history.h" #include "fetion_share.h" #include "fetion_directsms.h" #endif libofetion-2.2.2/fetion_history.h0000644000175000017500000000622711700115314015545 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_HISTORY_H #define FETION_HISTORY_H #define HISTORY_TODAY 1 #define HISTORY_WEEK 2 #define HISTORY_MONTH 3 #define HISTORY_ALL 4 extern History* fetion_history_message_new(const char* name , const char* userid , struct tm time , const char* msg , const int issend); extern void fetion_history_message_free(History* history); extern FetionHistory* fetion_history_new(User* user); extern void fetion_history_free(FetionHistory* fhistory); extern void fetion_history_add(FetionHistory* fhistory , History* history); extern FxList* fetion_history_get_list(Config* config , const char* sid , int count); extern FxList* fetion_history_get_e_list(Config *config , const char *userid , int type); extern int fetion_history_export(Config *config , const char *myid , const char *userid , const char *filename); extern int fetion_history_delete(Config *config, const char *userid); #endif libofetion-2.2.2/fetion_history.c0000644000175000017500000002216311700115314015535 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include #include History* fetion_history_message_new(const char* name, const char* userid, struct tm time, const char* msg , const int issend) { History* history = (History*)malloc(sizeof(History)); memset(history , 0 , sizeof(History)); strcpy(history->name , name); strcpy(history->userid , userid); strftime(history->sendtime, sizeof(history->sendtime), "%Y-%m-%d %H:%M:%S" , &time); snprintf(history->message, sizeof(history->message) - 1, "%s" , msg); history->issend = issend; return history; } void fetion_history_message_free(History* history) { free(history); } FetionHistory* fetion_history_new(User* user) { FetionHistory* fhistory; Config* config = user->config; char filepath[128]; fhistory = (FetionHistory*)malloc(sizeof(FetionHistory)); memset(fhistory , 0 , sizeof(FetionHistory)); fhistory->user = user; sprintf(filepath, "%s/data.db", config->userPath); if(sqlite3_open(filepath, &(fhistory->db))) debug_error("open data.db:%s", sqlite3_errmsg(fhistory->db)); return fhistory; } void fetion_history_free(FetionHistory* fhistory) { if(fhistory){ if(fhistory->db) sqlite3_close(fhistory->db); free(fhistory); } } void fetion_history_add(FetionHistory* fhistory , History* history) { sqlite3 *db; char sql[4096]; char sql1[4096]; db = fhistory->db; if(!db){ debug_error("db is closed,write history FAILED"); return; } escape_sql(history->message); snprintf(sql, sizeof(sql), "insert into history values" " (NULL,'%s','%s','%s',datetime('%s'),%d);", history->name, history->userid, history->message, history->sendtime, history->issend); if(sqlite3_exec(db, sql, 0, 0, NULL)){ snprintf(sql1, sizeof(sql1),"create table history (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "name TEXT,userid TEXT,message TEXT," "updatetime TEXT,issend INTEGER);"); if(sqlite3_exec(db, sql1, 0, 0, NULL)){ debug_error("create table history:%s",sqlite3_errmsg(db)); return; } if(sqlite3_exec(db, sql, 0, 0, NULL)) debug_error("%s\n%s",sqlite3_errmsg(db), sql); } } FxList* fetion_history_get_list(Config* config, const char* userid , int count) { sqlite3 *db; char sql[4096]; char path[256]; char **res; int nrows, ncols, start, i; FxList *hislist, *pos; History *his; snprintf(path, sizeof(path),"%s/data.db", config->userPath); hislist = fx_list_new(NULL); debug_info("Load chat history with %s", userid); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return hislist; } snprintf(sql, sizeof(sql),"select * from history" " where userid='%s' order" " by id desc limit %d;", userid, count); if(sqlite3_get_table(db, sql, &res, &nrows, &ncols, NULL)){ sqlite3_close(db); return hislist; } for(i = 0; i < nrows; i ++){ start = ncols + i * ncols; his = (History*)malloc(sizeof(History)); memset(his , 0 , sizeof(History)); strcpy(his->name, res[start+1]); strcpy(his->userid, res[start+2]); strcpy(his->message, res[start+3]); if(res[start+4]) strcpy(his->sendtime, res[start+4]); his->issend = atoi(res[start+5]); unescape_sql(his->message); pos = fx_list_new(his); fx_list_prepend(hislist , pos); } sqlite3_free_table(res); sqlite3_close(db); return hislist; } FxList* fetion_history_get_e_list(Config *config, const char *userid , int type) { sqlite3 *db; char sql[4096]; char path[256]; char condition[256]; char **res; int nrows, ncols, start, i; FxList *hislist, *pos; History *his; snprintf(path, sizeof(path),"%s/data.db", config->userPath); hislist = fx_list_new(NULL); debug_info("Load chat history with %s", userid); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return hislist; } switch(type){ case HISTORY_TODAY: snprintf(condition, sizeof(condition), "strftime('%%Y',updatetime) == strftime('%%Y','now') and " "strftime('%%m',updatetime) == strftime('%%m','now') and " "strftime('%%d',updatetime) == strftime('%%d','now') "); break; case HISTORY_WEEK: snprintf(condition, sizeof(condition), "strftime('%%Y',updatetime) == strftime('%%Y','now') and " "strftime('%%W',updatetime) == strftime('%%W','now') "); break; case HISTORY_MONTH: snprintf(condition, sizeof(condition), "strftime('%%Y',updatetime) == strftime('%%Y','now') and " "strftime('%%m',updatetime) == strftime('%%m','now') "); break; case HISTORY_ALL: sprintf(condition, "1==1"); break; default: break; }; snprintf(sql, sizeof(sql),"select * from history" " where userid='%s' and %s order" " by id desc;", userid, condition); if(sqlite3_get_table(db, sql, &res, &nrows, &ncols, NULL)){ sqlite3_close(db); return hislist; } for(i = 0; i < nrows; i ++){ start = ncols + i * ncols; his = (History*)malloc(sizeof(History)); memset(his , 0 , sizeof(History)); strcpy(his->name, res[start+1]); strcpy(his->userid, res[start+2]); strcpy(his->message, res[start+3]); if(res[start+4]) strcpy(his->sendtime, res[start+4]); his->issend = atoi(res[start+5]); unescape_sql(his->message); pos = fx_list_new(his); fx_list_prepend(hislist , pos); } sqlite3_free_table(res); return hislist; } int fetion_history_export(Config *config , const char *myid , const char *userid , const char *filename) { sqlite3 *db; char sql[4096]; char text[4096]; char path[256]; char **res; int nrows, ncols, start, i; FILE *f; if(!(f = fopen(filename, "w+"))){ debug_error("export chat history FAILED"); return -1; } sprintf(path, "%s/data.db", config->userPath); debug_info("Export chat history with %s", userid); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); fclose(f); return -1; } sprintf(sql, "select * from history" " where userid='%s' order" " by id;", userid); if(sqlite3_get_table(db, sql, &res, &nrows, &ncols, NULL)){ sqlite3_close(db); fclose(f); return -1; } for(i = 0; i < nrows; i ++){ start = ncols * (i + 1); sprintf(text, "%s(%s) %s\n", res[start+1], atoi(res[start+5]) ? myid : res[start+2], res[start+4]); strcpy(sql, res[start+3]); unescape_sql(sql); strcat(text , sql); strcat(text , "\n\n"); fwrite(text , strlen(text) , 1 , f); fflush(f); } sqlite3_free_table(res); sqlite3_close(db); fclose(f); return 1; } int fetion_history_delete(Config *config, const char *userid) { sqlite3 *db; char sql[4096]; char path[256]; snprintf(path, sizeof(path),"%s/data.db", config->userPath); debug_info("Delete chat history with %s", userid); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return -1; } sprintf(sql, "delete from history where userid = '%s'", userid); if(sqlite3_exec(db, sql, 0, 0, NULL)){ debug_error("delete history with %s failed:%s", userid, sqlite3_errmsg(db)); sqlite3_close(db); return -1; } sqlite3_close(db); return 1; } libofetion-2.2.2/fetion_group.h0000644000175000017500000001357011700115314015177 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_GROUP_H #define FETION_GROUP_H #define foreach_pg_group(head , cur) \ for(cur = head; (cur = cur->next) != head ;) /** * send get group list request to server * @param user Global User object */ extern int pg_group_get_list(User *user); /** * parse the response string for get group list request * @param sipmsg The response string * @return head of group list */ extern PGGroup *pg_group_parse_list(const char *sipmsg); /** * send a get group information request to server * @param user Global User object * @param pg To specify which group to get information for */ extern int pg_group_get_info(User *user , PGGroup *pg); /** * send a group subscribtion request to server * @param user Global User object * @param pg To specify which group to subscribe */ extern int pg_group_subscribe(User *user , PGGroup *pg); /** * parse the response string of get group info request * @param pg The head of the group list * @param sipmsg The response string to be parsed */ extern int pg_group_parse_info(PGGroup *pg , const char *sipmsg ); /** * send a get group members request to server * @param user Global User object * @param pg To specify which group to get members for */ extern int pg_group_get_group_members(User *user , PGGroup *pg); /** * parse the response string of get members request * @param pggroup The head of group list * @param sipmsg The response string */ extern int pg_group_parse_member_list(PGGroup *pggroup , const char *sipmsg); #define foreach_pg_member(head , cur) \ for(cur = head; (cur = cur->next)!= head ;) /** * Construct a PGGroupMember object */ extern PGGroupMember *pg_group_member_new(); /** * parse the member presence information pushed from the server * @param pg The head of the group list * @param the notification sip message */ extern int pg_group_parse_member(PGGroup *pg , const char *sipmsg); /** * send update group member information request to server * and sip message containing user information will be pushed from the server * @param user Global User object * @param To specify which group will update its member information */ extern int pg_group_update_group_info(User *user , PGGroup *pg); /** * get member count of a specified group * @param pg The group to be calculated * @return the member count of the specified group */ extern int pg_group_get_member_count(PGGroup *pg); /** * parse the body of respones string pushed from the server after function * "pg_group_update_group_info()" was called * @param the information sip message * @return A new contact parsed from the xml */ extern Contact* pg_group_parse_contact_info(const char* xml); /** * send a dialog invitation to a specified group * @param user Global User object * @param pg To specfy which group the invitation will be sent to */ extern int pg_group_send_invitation(User *user , PGGroup *pg); /** * send a group message to a specified group * @param user Global User object * @param pg To specify whicl group the message will be sent to * @param message The message body */ extern int pg_group_send_message(User *user , PGGroup *pg , const char *message); /** * send a group sms to a specified group * @param user Global User object * @param pg To specify whicl group the message will be sent to * @param message The message body */ extern int pg_group_send_sms(User *user , PGGroup *pg , const char *message); /** * send an acknowledge message after receiving the dialog invitation response message * @param user Global User object * @param sipmsg The dialog invitation response message */ extern int pg_group_send_invite_ack(User *user , const char *sipmsg); #endif libofetion-2.2.2/fetion_group.c0000644000175000017500000005457411700115314015203 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include static char* generate_contact_info_by_no_body(const char* no); static char* generate_get_members_body(const char *pguri); static void pg_group_member_append(PGGroupMember *head , PGGroupMember *newmem); static void pg_group_append(PGGroup *head , PGGroup *n); static void pg_group_prepend(PGGroup *head , PGGroup *n); static PGGroup *pg_group_new(const char *pguri , int identity) { PGGroup *pggroup = (PGGroup*)malloc(sizeof(PGGroup)); if(pggroup == NULL){ return NULL; } memset(pggroup , 0 , sizeof(PGGroup)); if(pguri) strcpy(pggroup->pguri , pguri); pggroup->member = pg_group_member_new(); if(pggroup->member == NULL){ free(pggroup); return NULL; } pggroup->identity = identity; pggroup->next = pggroup->pre = pggroup; return pggroup; } static void pg_group_append(PGGroup *head , PGGroup *n) { head->next->pre = n; n->pre = head; n->next = head->next; head->next = n; } static void pg_group_prepend(PGGroup *head , PGGroup *n) { head->pre->next = n; n->pre = head->pre; n->next = head; head->pre = n; } PGGroup *pg_group_parse_list(const char *in) { xmlDocPtr doc; xmlNodePtr node; xmlChar *res; PGGroup *pggroup , *newpg; doc = xmlReadMemory(in , strlen(in) , NULL , "UTF-8" , XML_PARSE_RECOVER); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "group"); if(!node) return NULL; pggroup = pg_group_new(NULL , 0); if(pggroup == NULL){ return NULL; } while(node){ newpg = pg_group_new(NULL , 0); res = xmlGetProp(node , BAD_CAST "uri"); strcpy(newpg->pguri , (char*)res); xmlFree(res); if(xmlHasProp(node , BAD_CAST "identity")){ res = xmlGetProp(node , BAD_CAST "identity"); newpg->identity = atoi((char*)res); xmlFree(res); } if(newpg->identity == 1) pg_group_prepend(pggroup , newpg); else pg_group_append(pggroup , newpg); node = node->next; } xmlFreeDoc(doc); return pggroup; } int pg_group_get_list(User *user) { FetionSip *sip; SipHeader *eheader; const char *body = ""; char *res; extern int callid; sip = user->sip; eheader = fetion_sip_event_header_new(SIP_EVENT_PGGETGROUPLIST); if(eheader == NULL){ return -1; } fetion_sip_set_type(sip , SIP_SERVICE); fetion_sip_add_header(sip , eheader); user->pgGroupCallId = callid; res = fetion_sip_to_string(sip , body); if(res == NULL){ return -1; } int ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return ret; } static char *generate_get_info_body(PGGroup *pg) { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node; xmlNodePtr node1; PGGroup *cur; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "groups" , NULL); xmlNewProp(node , BAD_CAST "attributes" , BAD_CAST "all"); foreach_pg_group(pg , cur){ node1 = xmlNewChild(node , NULL , BAD_CAST "group" , NULL); xmlNewProp(node1 , BAD_CAST "uri" , BAD_CAST cur->pguri); } xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } int pg_group_get_info(User *user , PGGroup *pg) { FetionSip *sip; SipHeader *eheader; char *res; char *body; extern int callid; sip = user->sip; eheader = fetion_sip_event_header_new(SIP_EVENT_PGGETGROUPINFO); if(eheader == NULL){ return -1; } fetion_sip_add_header(sip , eheader); fetion_sip_set_type(sip , SIP_SERVICE); user->groupInfoCallId = callid; body = generate_get_info_body(pg); if(body == NULL){ return -1; } res = fetion_sip_to_string(sip , body); if(res == NULL){ return -1; } free(body); int ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return ret; } int pg_group_parse_info(PGGroup *pg , const char *sipmsg) { xmlDocPtr doc; xmlNodePtr node; xmlChar *res; PGGroup *pgcur; char *pos; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlReadMemory(pos , strlen(pos) , NULL , "UTF-8" , XML_PARSE_RECOVER); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "group"); if(!node) return -1; while(node != NULL){ res = xmlGetProp(node , BAD_CAST "uri"); foreach_pg_group(pg , pgcur){ if(xmlStrcmp(res , BAD_CAST pgcur->pguri) == 0) break; } if(xmlHasProp(node , BAD_CAST "status-code")){ res = xmlGetProp(node , BAD_CAST "status-code"); pgcur->statusCode = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "name")){ res = xmlGetProp(node , BAD_CAST "name"); strcpy(pgcur->name , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "category")){ res = xmlGetProp(node , BAD_CAST "category"); pgcur->category = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "current-member-count")){ res = xmlGetProp(node , BAD_CAST "current-member-count"); pgcur->currentMemberCount = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "limit-member-count")){ res = xmlGetProp(node , BAD_CAST "limit-member-count"); pgcur->limitMemberCount = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "group-rank")){ res = xmlGetProp(node , BAD_CAST "group-rank"); pgcur->groupRank = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "max-rank")){ res = xmlGetProp(node , BAD_CAST "max-rank"); pgcur->maxRank = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "bulletin")){ res = xmlGetProp(node , BAD_CAST "bulletin"); strcpy(pgcur->bulletin , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "introduce")){ res = xmlGetProp(node , BAD_CAST "introduce"); strcpy(pgcur->summary , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "create-time")){ res = xmlGetProp(node , BAD_CAST "create-time"); strcpy(pgcur->createTime , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "get-group-portrait-hds")){ res = xmlGetProp(node , BAD_CAST "get-group-portrait-hds"); strcpy(pgcur->getProtraitUri , (char*)res); xmlFree(res); } node = node->next; } return 0; } static char *generate_pg_subscribe_body(PGGroup *pg) { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node0; xmlNodePtr node; xmlNodePtr node1; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node0 = xmlNewChild(node , NULL , BAD_CAST "subscription" , NULL); node = xmlNewChild(node0 , NULL , BAD_CAST "groups" , NULL); node1 = xmlNewChild(node , NULL , BAD_CAST "group" , NULL); xmlNewProp(node1 , BAD_CAST "uri" , BAD_CAST pg->pguri); node = xmlNewChild(node0 , NULL , BAD_CAST "presence" , NULL); node1 = xmlNewChild(node , NULL , BAD_CAST "basic" , NULL); xmlNewProp(node1 , BAD_CAST "attributes" , BAD_CAST "all"); node1 = xmlNewChild(node , NULL , BAD_CAST "member" , NULL); xmlNewProp(node1 , BAD_CAST "attributes" , BAD_CAST "identity"); node1 = xmlNewChild(node , NULL , BAD_CAST "management" , NULL); xmlNewProp(node1 , BAD_CAST "attributes" , BAD_CAST "all"); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } int pg_group_subscribe(User *user , PGGroup *pg) { FetionSip *sip; SipHeader *eheader; char *res; char *body; sip = user->sip; eheader = fetion_sip_event_header_new(SIP_EVENT_PGPRESENCE); if(eheader == NULL){ return -1; } fetion_sip_add_header(sip , eheader); fetion_sip_set_type(sip , SIP_SUBSCRIPTION); body = generate_pg_subscribe_body(pg); if(body == NULL){ return -1; } res = fetion_sip_to_string(sip , body); if(res == NULL){ free(body); return -1; } free(body); int ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return ret; } int pg_group_get_group_members(User *user , PGGroup *pg) { FetionSip *sip; SipHeader *nheader; char *body; char *res; sip = user->sip; nheader = fetion_sip_event_header_new(SIP_EVENT_PGGETGROUPMEMBERS); if(nheader == NULL){ return -1; } fetion_sip_add_header(sip , nheader); fetion_sip_set_type(sip , SIP_SERVICE); pg->getMembersCallId = sip->callid; body = generate_get_members_body(pg->pguri); if(body == NULL){ return -1; } res = fetion_sip_to_string(sip , body); if(res == NULL){ free(body); return -1; } int ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return ret; } int pg_group_parse_member_list(PGGroup *pggroup , const char *sipmsg) { xmlDocPtr doc; xmlNodePtr node; xmlNodePtr cnode; xmlChar *res; PGGroup *pgcur; PGGroupMember *member; char *pos; if(strstr(sipmsg , "\r\n\r\n") == NULL){ fprintf(stderr , "FATAL ERROR\n"); return -1; } pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); if(doc == NULL){ return -1; } node = xmlDocGetRootElement(doc); if(node == NULL){ xmlFreeDoc(doc); return -1; } node = node->xmlChildrenNode->xmlChildrenNode; while(node != NULL){ if(xmlHasProp(node , BAD_CAST "uri")){ res = xmlGetProp(node , BAD_CAST "uri"); foreach_pg_group(pggroup , pgcur){ if(xmlStrcmp(res , BAD_CAST pgcur->pguri) == 0) break; } }else{ xmlFreeDoc(doc); return -1; } cnode = node->xmlChildrenNode; while(cnode != NULL){ member = pg_group_member_new(); if(xmlHasProp(cnode , BAD_CAST "uri")){ res = xmlGetProp(cnode , BAD_CAST "uri"); strcpy(member->sipuri , (char*)res); xmlFree(res); } if(xmlHasProp(cnode , BAD_CAST "iicnickname")){ res = xmlGetProp(cnode , BAD_CAST "iicnickname"); strcpy(member->nickname , (char*)res); xmlFree(res); } if(xmlHasProp(cnode , BAD_CAST "identity")){ res = xmlGetProp(cnode , BAD_CAST "identity"); member->identity = atoi((char*)res); xmlFree(res); } if(xmlHasProp(cnode , BAD_CAST "user-id")){ res = xmlGetProp(cnode , BAD_CAST "user-id"); strcpy(member->userId , (char*)res); xmlFree(res); } pg_group_member_append(pgcur->member , member); cnode = cnode->next; } node = node->next; } xmlFreeDoc(doc); return 0; } PGGroupMember *pg_group_member_new() { PGGroupMember *pgmem = (PGGroupMember*)malloc(sizeof(PGGroupMember)); if(pgmem == NULL){ return NULL; } memset(pgmem , 0 , sizeof(PGGroupMember)); pgmem->contact = NULL; pgmem->next = pgmem->pre = pgmem; return pgmem; } static void pg_group_member_append(PGGroupMember *head , PGGroupMember *newmem) { head->next->pre = newmem; newmem->next = head->next; newmem->pre = head; head->next = newmem; } #if 0 static void pg_group_member_prepend(PGGroupMember *head , PGGroupMember *newmem) { head->pre->next = newmem; newmem->pre = head->pre; newmem->next = head; head->pre = newmem; } #endif int pg_group_parse_member(PGGroup *pg , const char *sipmsg) { xmlDocPtr doc; xmlNodePtr node; xmlNodePtr mnode; xmlChar *res; PGGroup *pgcur; PGGroupMember *member; char *pos; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "group"); while(node != NULL){ res = xmlGetProp(node , BAD_CAST "uri"); foreach_pg_group(pg , pgcur){ if(xmlStrcmp(res , BAD_CAST pgcur->pguri) == 0) break; } mnode = node->xmlChildrenNode; if(!mnode){ node = node->next; continue; } while(mnode != NULL){ res = xmlGetProp(mnode , BAD_CAST "uri"); foreach_pg_member(pgcur->member , member){ if(xmlStrcmp(res , BAD_CAST member->sipuri) == 0) break; } if(xmlHasProp(mnode , BAD_CAST "identity")){ res = xmlGetProp(mnode , BAD_CAST "identity"); member->identity = atoi((char*)res); xmlFree(res); } if(xmlHasProp(mnode , BAD_CAST "state")){ res = xmlGetProp(mnode , BAD_CAST "state"); member->state = atoi((char*)res); xmlFree(res); } if(xmlHasProp(mnode , BAD_CAST "client-type")){ res = xmlGetProp(mnode , BAD_CAST "client-type"); strcpy(member->clientType , (char*)res); xmlFree(res); } mnode = mnode->next; } node = node->next; } xmlFreeDoc(doc); return 0; } int pg_group_update_group_info(User *user , PGGroup *pg) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; char *sid; extern int callid; PGGroupMember *memcur; int ret; if(pg == NULL || pg_group_get_member_count(pg) == 0) return 0; pg->hasDetails = 1; foreach_pg_member(pg->member , memcur){ eheader = fetion_sip_event_header_new(SIP_EVENT_GETCONTACTINFO); if(eheader == NULL){ return -1; } fetion_sip_add_header(sip , eheader); fetion_sip_set_type(sip , SIP_SERVICE); memcur->getContactInfoCallId = callid; sid = fetion_sip_get_sid_by_sipuri(memcur->sipuri); if(sid == NULL){ return -1; } body = generate_contact_info_by_no_body(sid); if(body == NULL){ free(sid); return -1; } free(sid); res = fetion_sip_to_string(sip , body); if(res == NULL){ free(body); return -1; } free(body); ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = NULL; if(ret == -1){ return -1; } } return 0; } int pg_group_get_member_count(PGGroup *pg) { int count = 0; PGGroupMember *memcur; foreach_pg_member(pg->member , memcur){ count ++; } return count; } Contact* pg_group_parse_contact_info(const char* xml) { Contact* contact; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; char *pos; contact = fetion_contact_new(); if(contact == NULL){ return NULL; } doc = xmlParseMemory(xml , strlen(xml)); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; if(xmlHasProp(node , BAD_CAST "uri")) { res = xmlGetProp(node , BAD_CAST "uri"); strcpy(contact->sipuri , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "user-id")) { res = xmlGetProp(node , BAD_CAST "user-id"); strcpy(contact->userId , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "sid")) { res = xmlGetProp(node , BAD_CAST "sid"); strcpy(contact->sId , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "nickname")) { res = xmlGetProp(node , BAD_CAST "nickname"); strcpy(contact->nickname , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "gender")) { res = xmlGetProp(node , BAD_CAST "gender"); contact->gender = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "birth-date")) { res = xmlGetProp(node , BAD_CAST "birth-date"); strcpy(contact->birthday , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "impresa")) { res = xmlGetProp(node , BAD_CAST "impresa"); strcpy(contact->impression , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "mobile-no")) { res = xmlGetProp(node , BAD_CAST "mobile-no"); strcpy(contact->mobileno , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "carrier-region")) { int n; res = xmlGetProp(node , BAD_CAST "carrier-region"); pos = (char*)res; n = strlen(pos) - strlen(strstr(pos , ".")); strncpy(contact->country , pos , n); pos = strstr(pos , ".") + 1; n = strlen(pos) - strlen(strstr(pos , ".")); strncpy(contact->province , pos , n); pos = strstr(pos , ".") + 1; n = strlen(pos) - strlen(strstr(pos , ".")); strncpy(contact->city , pos , n); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "portrait-crc")) { res = xmlGetProp(node , BAD_CAST "portrait-crc"); strcpy(contact->portraitCrc , (char*)res); xmlFree(res); } xmlFreeDoc(doc); return contact; } int pg_group_send_invitation(User *user , PGGroup *pg) { FetionSip *sip = user->sip; SipHeader *theader; SipHeader *kheader1; SipHeader *kheader2; SipHeader *kheader3; SipHeader *kheader4; SipHeader *kheader5; extern int callid; const char *body = "s=session m=message"; char *res; fetion_sip_set_type(sip , SIP_INVITATION); theader = fetion_sip_header_new("T" , pg->pguri); if(theader == NULL){ goto theader_error; } kheader1 = fetion_sip_header_new("K" , "text/html-fragment"); if(kheader1 == NULL){ goto kheader1_error; } kheader2 = fetion_sip_header_new("K" , "multiparty"); if(kheader1 == NULL){ goto kheader2_error; } kheader3 = fetion_sip_header_new("K" , "nudge"); if(kheader1 == NULL){ goto kheader3_error; } kheader4 = fetion_sip_header_new("K" , "share-background"); if(kheader1 == NULL){ goto kheader4_error; } kheader5 = fetion_sip_header_new("K" , "fetion-show"); if(kheader1 == NULL){ goto kheader5_error; } pg->inviteCallId = callid; fetion_sip_add_header(sip , theader); fetion_sip_add_header(sip , kheader1); fetion_sip_add_header(sip , kheader2); fetion_sip_add_header(sip , kheader3); fetion_sip_add_header(sip , kheader4); fetion_sip_add_header(sip , kheader5); res = fetion_sip_to_string(sip , body); if(res == NULL){ return -1; } int ret = tcp_connection_send(sip->tcp , res , strlen(res)); return ret; kheader5_error: free(kheader4); kheader4_error: free(kheader3); kheader3_error: free(kheader2); kheader2_error: free(kheader1); kheader1_error: free(theader); theader_error: return -1; } int pg_group_send_invite_ack(User *user , const char *sipmsg) { FetionSip *sip = user->sip; SipHeader *theader; char callid[16]; char touri[64]; char *res; memset(callid , 0 , sizeof(callid)); memset(touri , 0 , sizeof(touri)); fetion_sip_get_attr(sipmsg , "I" , callid); fetion_sip_get_attr(sipmsg , "T" , touri); fetion_sip_set_type(sip , SIP_ACKNOWLEDGE); theader = fetion_sip_header_new("T" , touri); if(theader == NULL){ return -1; } fetion_sip_set_callid(sip , atoi(callid)); fetion_sip_add_header(sip , theader); res = fetion_sip_to_string(sip , NULL); if(res == NULL){ return -1; } int ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return ret; } int pg_group_send_message(User *user , PGGroup *pg , const char *message) { FetionSip *sip = user->sip; SipHeader *theader; SipHeader *cheader; SipHeader *kheader; char *res; fetion_sip_set_type(sip , SIP_MESSAGE); theader = fetion_sip_header_new("T" , pg->pguri); if(theader == NULL){ goto theader_error; } cheader = fetion_sip_header_new("C" , "text/html-fragment"); if(cheader == NULL){ goto cheader_error; } kheader = fetion_sip_header_new("K" , "SaveHistory"); if(kheader == NULL){ goto kheader_error; } fetion_sip_add_header(sip , theader); fetion_sip_add_header(sip , cheader); fetion_sip_add_header(sip , kheader); fetion_sip_set_callid(sip , pg->inviteCallId); res = fetion_sip_to_string(sip , message); if(res == NULL){ return -1; } int ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return ret; kheader_error: free(cheader); cheader_error: free(theader); theader_error: return -1; } int pg_group_send_sms(User *user , PGGroup *pg , const char *message) { FetionSip *sip = user->sip; SipHeader *theader; SipHeader *eheader; char *res; fetion_sip_set_type(sip , SIP_MESSAGE); theader = fetion_sip_header_new("T" , pg->pguri); if(theader == NULL){ goto theader_error; } eheader = fetion_sip_event_header_new(SIP_EVENT_PGSENDCATSMS); if(eheader == NULL){ goto eheader_error; } fetion_sip_add_header(sip , theader); fetion_sip_add_header(sip , eheader); res = fetion_sip_to_string(sip , message); if(res == NULL){ return -1; } int ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return ret; eheader_error: free(theader); theader_error: return -1; } static char* generate_get_members_body(const char *pguri) { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "groups" , NULL); xmlNewProp(node , BAD_CAST "attributes" , BAD_CAST "member-uri;member-nickname;member-iicnickname;member-identity;member-t6svcid"); node = xmlNewChild(node , NULL , BAD_CAST "group" , NULL); xmlNewProp(node , BAD_CAST "uri" , BAD_CAST pguri); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); if(buf == NULL){ return NULL; } return xml_convert(buf); } static char* generate_contact_info_by_no_body(const char* no) { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node; char uri[32]; char body[] = ""; memset(uri, 0, sizeof(uri)); sprintf(uri , "sip:%s" , no); doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contact" , NULL); xmlNewProp(node , BAD_CAST "uri" , BAD_CAST uri); xmlDocDumpMemory(doc , &buf , NULL); if(buf == NULL){ return NULL; } xmlFreeDoc(doc); return xml_convert(buf); } libofetion-2.2.2/fetion_directsms.h0000644000175000017500000000545611700115314016044 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_DIRECTSMS_H #define FETION_DIRECTSMS_H #define PIC_SUCCESS 1 #define PIC_ERROR -1 #define UNKNOW_ERROR -2 #define SEND_SMS_SUCCESS 1 #define SEND_SMS_NEED_AUTHENTICATION -1 #define SEND_SMS_OTHER_ERROR -2 #define DSMS_OPTION_SUCCESS 1 #define DSMS_OPTION_FAILED -1 extern int fetion_directsms_send_option(User *user , const char *response); extern int fetion_directsms_send_subscribe(User *user , const char *code , char **error); extern int fetion_directsms_send_sms(User *user , const char *to , const char *msg); #endif libofetion-2.2.2/fetion_directsms.c0000644000175000017500000001751611700115314016037 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include static void parse_option_verification(User *user , const char *in) { int n; char *pos , w[256]; xmlDocPtr doc; xmlNodePtr node; xmlChar *res; user->verification = fetion_verification_new(); memset(w, 0, sizeof(w)); fetion_sip_get_attr(in , "W" , w); pos = strstr(w , "thm=\"") + 5; n = strlen(pos) - strlen(strstr(pos , "\"")); user->verification->algorithm = (char*)malloc(n + 1); memset(user->verification->algorithm, 0, n + 1); strncpy(user->verification->algorithm , pos , n); pos = strstr(pos , "type=\"") + 6; n = strlen(pos) - strlen(strstr(pos , "\"")); user->verification->type = (char*)malloc(n + 1); memset(user->verification->type, 0, n + 1); strncpy(user->verification->type , pos , n); pos = strstr(in , "\r\n\r\n") + 4; doc = xmlReadMemory(pos , strlen(pos) , NULL , "UTF-8" , XML_PARSE_RECOVER); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; if(xmlHasProp(node , BAD_CAST "text")){ res = xmlGetProp(node , BAD_CAST "text"); user->verification->text = (char*)malloc(xmlStrlen(res) + 1); memset(user->verification->text, 0, xmlStrlen(res) + 1); strcpy(user->verification->text , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "tips")){ res = xmlGetProp(node , BAD_CAST "tips"); if(strstr((char*)res , ",verification->tips = (char*)malloc(n + 1); memset(user->verification->tips, 0, n + 1); strncpy(user->verification->tips , (char*)res , n); } xmlFree(res); } } int fetion_directsms_send_option(User *user , const char *response) { FetionSip *sip = user->sip; SipHeader *eheader , *aheader; int code; char *res , atext[1024]; fetion_sip_set_type(sip , SIP_OPTION); eheader = fetion_sip_event_header_new(SIP_EVENT_DIRECTSMS); fetion_sip_add_header(sip , eheader); if(user->verification != NULL && response != NULL){ memset(atext, 0, sizeof(atext)); sprintf(atext , "Verify algorithm=\"%s\"," "type=\"%s\",response=\"%s\",chid=\"%s\"" , user->verification->algorithm , user->verification->type , response , user->verification->guid); aheader = fetion_sip_header_new("A" , atext); fetion_sip_add_header(sip , aheader); } res = fetion_sip_to_string(sip , NULL); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = fetion_sip_get_response(sip); code = fetion_sip_get_code(res); if(code == 200){ return DSMS_OPTION_SUCCESS; }else{ parse_option_verification(user , res); return DSMS_OPTION_FAILED; } free(res); } static int parse_subscribe_response(const char *in , char **error) { char *pos , c[4]; int n; xmlDocPtr doc; xmlNodePtr node; xmlChar *res; pos = strstr(in , " ") + 1; n = strlen(pos) - strlen(strstr(pos , " ")); memset(c, 0, sizeof(c)); strncpy(c , pos , n); if(strcmp(c , "200") == 0){ *error = NULL; return PIC_SUCCESS; } pos = strstr(in , "\r\n\r\n") + 4; doc = xmlReadMemory(pos , strlen(pos) , NULL , "UTF-8" , XML_PARSE_RECOVER ); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; if(xmlStrcmp(node->name , BAD_CAST "error") == 0){ if(xmlHasProp(node , BAD_CAST "user-msg")){ res = xmlGetProp(node , BAD_CAST "user-msg"); *error = (char*)malloc(xmlStrlen(res) + 1); strcpy(*error , (char*)res); xmlFree(res); return PIC_ERROR; }else{ *error = NULL; return UNKNOW_ERROR; } }else{ *error = NULL; return UNKNOW_ERROR; } } int fetion_directsms_send_subscribe(User *user , const char *code , char **error) { char body[256]; char http[2048]; char *ip; FetionConnection *tcp; ip = get_ip_by_name(NAVIGATION_URI); memset(body, 0, sizeof(body)); sprintf(body , "PicCertSessionId=%s&PicCertCode=%s&MobileNo=%s" , user->verification->guid , code , user->mobileno); memset(http, 0, sizeof(http)); sprintf(http , "POST /nav/ApplySubscribe.aspx HTTP/1.1\r\n" "Cookie: ssic=%s\r\n" "Accept: */*\r\n" "Host: %s\r\n" "Content-Length: %d\r\n" "Content-Type: application/x-www-form-urlencoded;" "charset=utf-8\r\n" "User-Agent: IIC2.0/PC "PROTO_VERSION"\r\n" "Connection: Keep-Alive\r\n" "Cache-Control: no-cache\r\n\r\n%s" , user->ssic , NAVIGATION_URI , strlen(body) , body); printf("%s\n" , http); tcp = tcp_connection_new(); tcp_connection_connect(tcp , ip , 80); tcp_connection_send(tcp , http , strlen(http)); memset(http, 0, sizeof(http)); tcp_connection_recv(tcp , http , sizeof(http)); printf("%s\n" , http); return parse_subscribe_response(http , error); } int fetion_directsms_send_sms(User *user , const char *to , const char *msg) { FetionSip *sip = user->sip; SipHeader *svheader , *eheader , *theader; char tostr[24] , *res , rep[1024]; int code; fetion_sip_set_type(sip , SIP_MESSAGE); memset(tostr, 0, sizeof(tostr)); sprintf(tostr , "tel:%s" , to); theader = fetion_sip_header_new("T" , tostr); fetion_sip_add_header(sip , theader); svheader = fetion_sip_header_new("SV" , "1"); fetion_sip_add_header(sip , svheader); eheader = fetion_sip_event_header_new(SIP_EVENT_SENDDIRECTCATSMS); fetion_sip_add_header(sip , eheader); res = fetion_sip_to_string(sip , msg); tcp_connection_send(sip->tcp , res , strlen(res)); printf("%s\n" , res); memset(rep, 0, sizeof(rep)); int ret = tcp_connection_recv(sip->tcp , rep , sizeof(rep)); printf("%d\n" , ret); printf("%s\n" , rep); code = fetion_sip_get_code(rep); if(code == 280){ return SEND_SMS_SUCCESS; }else{ if(code == 420 || code == 421){ parse_option_verification(user , rep); return SEND_SMS_NEED_AUTHENTICATION; }else{ return SEND_SMS_OTHER_ERROR; } } } libofetion-2.2.2/fetion_debug.h0000644000175000017500000000471211700115314015127 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_DEBUG_H #define FETION_DEBUG_H extern struct tm* get_currenttime(); extern void debug_info(const char* format , ...); extern void debug_error(const char* format , ...); #endif libofetion-2.2.2/fetion_debug.c0000644000175000017500000000557611700115314015133 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include struct tm* get_currenttime() { time_t t; time(&t); return localtime(&t); } void debug_info(const char* format , ...) { char t_str[32] = { 0 }; char fmt[4096] = { 0 }; va_list ap; struct tm* t = get_currenttime(); strftime(t_str , sizeof(t_str) , "%T" , t ); sprintf(fmt , "[\e[32m\e[1m%s\e[0m] %s\n" , t_str , format); va_start(ap, format); vfprintf(stdout , fmt , ap); va_end(ap); } void debug_error(const char* format , ...) { char fmt[4096] = { 0 }; va_list ap; sprintf(fmt , "[\e[31m\e[1mFAIL\e[0m] %s\n" , format); va_start(ap, format); vfprintf(stderr , fmt , ap); va_end(ap); } libofetion-2.2.2/fetion_conversation.h0000644000175000017500000001135311700115314016552 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_CONVERSION_H #define FETION_CONVERSION_h /** * construct a conversation object * @uesr Global User object * @sipuri To specify the user in the conversation */ extern Conversation* fetion_conversation_new(User* user , const char* sipuri , FetionSip* sip); /** * send a message to the user in this conversation * @note before you send a message to an online buddy , in other word , * the buddy`s state is larger than 0 , then you need to send an invitation * to the buddy first using function "fetion_conversation_invite_friend()" * or else the message will fail to send * @param conv To specify the conversation to send a sms to * @param msg the message to be sent */ extern int fetion_conversation_send_sms(Conversation* conv , const char* msg); extern int fetion_conversation_send_sms_with_reply(Conversation *conv, const char *msg); /** * send a sms to yourself */ extern int fetion_conversation_send_sms_to_myself(Conversation* conversation , const char* message); int fetion_conversation_send_sms_to_myself_with_reply(Conversation* conversation, const char* message); /** * send a message directly to the user`s phone in the specified conversation * @param conversation To specify the user to whom the message will be sent * @param message The message body * @return 1 if success , or else -1 */ extern int fetion_conversation_send_sms_to_phone(Conversation* conversation , const char* message); /** * send a message directly to the user`s phone in the specified conversation * and parse the response message. * @param conversation To specify the buddy to whom the message will be sent * @param message The message body * @param daycount Will be filled with the count of messages you send in the current day * @param mountcount Will be filled with the count of messages you send in the current month * @return 1 if success , or else -1 */ extern int fetion_conversation_send_sms_to_phone_with_reply(Conversation* conversation , const char* message , int* daycount , int* monthcount); /** * invite an online buddy to a conversation * @param conversation To specify the buddy to whom the message will be sent * @return 1 if success , or else -1 */ extern int fetion_conversation_invite_friend(Conversation* conversation); /** * send a window nudge to a buddy * @param conversation To specify the buddy to whom the nudge will be sent * @return 1 if success , or else -1 */ extern int fetion_conversation_send_nudge(Conversation* conversation); #endif libofetion-2.2.2/fetion_conversation.c0000644000175000017500000003607511700115314016555 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include extern char* generate_invite_friend_body(const char* sipuri); extern char* generate_send_nudge_body(); extern void fetion_conversation_parse_send_sms(const char* xml , int* daycount , int* mountcount); extern struct unacked_list *unackedlist; Conversation* fetion_conversation_new(User* user, const char* sipuri , FetionSip* sip) { Conversation* conversation = (Conversation*)malloc(sizeof(Conversation)); memset(conversation , 0 , sizeof(Conversation)); conversation->currentUser = user; if(sipuri != NULL) conversation->currentContact = fetion_contact_list_find_by_sipuri(user->contactList , sipuri); else conversation->currentContact = NULL; if(sipuri != NULL && conversation->currentContact == NULL){ free(conversation); return NULL; } conversation->currentSip = sip; return conversation; } int fetion_conversation_send_sms(Conversation* conversation , const char* msg) { FetionSip* sip = conversation->currentSip == NULL ? conversation->currentUser->sip : conversation->currentSip; SipHeader *toheader , *cheader , *kheader , *nheader; Message *message; struct unacked_list *unacked; char* res; struct tm *now; struct tm now_copy; fetion_sip_set_type(sip , SIP_MESSAGE); nheader = fetion_sip_event_header_new(SIP_EVENT_CATMESSAGE); toheader = fetion_sip_header_new("T" , conversation->currentContact->sipuri); cheader = fetion_sip_header_new("C" , "text/plain"); kheader = fetion_sip_header_new("K" , "SaveHistory"); fetion_sip_add_header(sip , toheader); fetion_sip_add_header(sip , cheader); fetion_sip_add_header(sip , kheader); fetion_sip_add_header(sip , nheader); /* add message to list */ now = get_currenttime(); now_copy = *now; message = fetion_message_new(); fetion_message_set_sipuri(message , conversation->currentContact->sipuri); fetion_message_set_time(message , now_copy); fetion_message_set_message(message , msg); fetion_message_set_callid(message , sip->callid); unacked = unacked_list_new(message); unacked_list_append(unackedlist , unacked); res = fetion_sip_to_string(sip , msg); debug_info("Sent a message to %s" , conversation->currentContact->sipuri); if(tcp_connection_send(sip->tcp , res , strlen(res)) == -1){ free(res); return -1; } free(res); return 1; } int fetion_conversation_send_sms_with_reply(Conversation *conv, const char *msg) { char rep[1024]; FetionSip* sip = conv->currentSip == NULL ? conv->currentUser->sip : conv->currentSip; SipHeader *toheader , *cheader , *kheader , *nheader; Message *message; char* res; struct tm *now; struct tm now_copy; fetion_sip_set_type(sip , SIP_MESSAGE); nheader = fetion_sip_event_header_new(SIP_EVENT_CATMESSAGE); toheader = fetion_sip_header_new("T" , conv->currentContact->sipuri); cheader = fetion_sip_header_new("C" , "text/plain"); kheader = fetion_sip_header_new("K" , "SaveHistory"); fetion_sip_add_header(sip , toheader); fetion_sip_add_header(sip , cheader); fetion_sip_add_header(sip , kheader); fetion_sip_add_header(sip , nheader); /* add message to list */ now = get_currenttime(); now_copy = *now; message = fetion_message_new(); fetion_message_set_sipuri(message , conv->currentContact->sipuri); fetion_message_set_time(message , now_copy); fetion_message_set_message(message , msg); fetion_message_set_callid(message , sip->callid); res = fetion_sip_to_string(sip , msg); debug_info("Sent a message to %s" , conv->currentContact->sipuri); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); memset(rep , 0 , sizeof(rep)); tcp_connection_recv(sip->tcp , rep , sizeof(rep)); if(fetion_sip_get_code(rep) == 280 || fetion_sip_get_code(rep) == 200){ return 1; }else{ return -1; } } int fetion_conversation_send_sms_to_myself(Conversation* conversation, const char* message) { SipHeader *toheader = NULL; SipHeader *eheader = NULL; char* res = NULL; FetionSip* sip = conversation->currentUser->sip; fetion_sip_set_type(sip , SIP_MESSAGE); toheader = fetion_sip_header_new("T" , conversation->currentUser->sipuri); eheader = fetion_sip_event_header_new(SIP_EVENT_SENDCATMESSAGE); fetion_sip_add_header(sip , toheader); fetion_sip_add_header(sip , eheader); res = fetion_sip_to_string(sip , message); debug_info("Sent a message to myself" , conversation->currentContact->sipuri); if(tcp_connection_send(sip->tcp , res , strlen(res)) == -1) { free(res); return -1; } free(res); res = fetion_sip_get_response(sip); free(res); return 1; } int fetion_conversation_send_sms_to_myself_with_reply(Conversation* conversation, const char* message) { SipHeader *toheader = NULL; SipHeader *eheader = NULL; char *res = NULL; char rep[1024]; int code; FetionSip *sip = conversation->currentUser->sip; fetion_sip_set_type(sip , SIP_MESSAGE); toheader = fetion_sip_header_new("T" , conversation->currentUser->sipuri); eheader = fetion_sip_event_header_new(SIP_EVENT_SENDCATMESSAGE); fetion_sip_add_header(sip , toheader); fetion_sip_add_header(sip , eheader); res = fetion_sip_to_string(sip , message); debug_info("Sent a message to myself" , conversation->currentContact->sipuri); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); memset(rep, 0, sizeof(rep)); tcp_connection_recv(sip->tcp , rep , sizeof(rep)); code = fetion_sip_get_code(rep); if(code == 200 || code == 280){ return 1; }else{ return -1; } } int fetion_conversation_send_sms_to_phone(Conversation* conversation, const char* message) { SipHeader *toheader = NULL; SipHeader *eheader = NULL; SipHeader *aheader = NULL; User *user = conversation->currentUser; char* res = NULL; FetionSip* sip = user->sip; char* sipuri = conversation->currentContact->sipuri; char astr[256] , rep[1024]; int code; fetion_sip_set_type(sip , SIP_MESSAGE); toheader = fetion_sip_header_new("T" , sipuri); eheader = fetion_sip_event_header_new(SIP_EVENT_SENDCATMESSAGE); fetion_sip_add_header(sip , toheader); if(user->verification != NULL){ memset(astr, 0, sizeof(astr)); sprintf(astr , "Verify algorithm=\"picc\",chid=\"%s\",response=\"%s\"" , user->verification->guid , user->verification->code); aheader = fetion_sip_header_new("A" , astr); fetion_sip_add_header(sip , aheader); } fetion_sip_add_header(sip , eheader); res = fetion_sip_to_string(sip , message); debug_info("Sent a message to (%s)`s mobile phone" , sipuri); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); memset(rep, 0, sizeof(rep)); tcp_connection_recv(sip->tcp , rep , sizeof(rep)); code = fetion_sip_get_code(rep); if(code == 420 || code == 421){ return -1; }else{ return 1; } } int fetion_conversation_send_sms_to_phone_with_reply(Conversation* conversation , const char* message , int* daycount , int* monthcount) { SipHeader *toheader , *eheader , *aheader; char* res; char* xml; User *user = conversation->currentUser; FetionSip* sip = user->sip; char astr[256] , rep[1024]; char* sipuri = conversation->currentContact->sipuri; fetion_sip_set_type(sip , SIP_MESSAGE); toheader = fetion_sip_header_new("T" , sipuri); eheader = fetion_sip_event_header_new(SIP_EVENT_SENDCATMESSAGE); fetion_sip_add_header(sip , toheader); if(user->verification != NULL){ sprintf(astr , "Verify algorithm=\"picc\",chid=\"%s\",response=\"%s\"" , user->verification->guid , user->verification->code); aheader = fetion_sip_header_new("A" , astr); fetion_sip_add_header(sip , aheader); } fetion_sip_add_header(sip , eheader); res = fetion_sip_to_string(sip , message); debug_info("Sent a message to (%s)`s mobile phone" , sipuri); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); memset(rep , 0 , sizeof(rep)); tcp_connection_recv(sip->tcp , rep , sizeof(rep)); if(fetion_sip_get_code(rep) == 280){ xml = strstr(rep , "\r\n\r\n") + 4; fetion_conversation_parse_send_sms(xml , daycount , monthcount); return 1; }else{ debug_error("Send a message to (%s)`s mobile phone failed", sipuri); return -1; } } int fetion_conversation_invite_friend(Conversation* conversation) { FetionSip* sip = conversation->currentUser->sip; char *res , *ip , *credential , auth[256] , *body; int port , ret; FetionConnection* conn; Proxy *proxy = conversation->currentUser->config->proxy; SipHeader *eheader , *theader , *mheader , *nheader , *aheader; /*start chat*/ fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_STARTCHAT); fetion_sip_add_header(sip , eheader); res = fetion_sip_to_string(sip , NULL); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = NULL; res = fetion_sip_get_response(sip); if(!res) return -1; memset(auth , 0 , sizeof(auth)); fetion_sip_get_attr(res , "A" , auth); if(auth==NULL) return -1; fetion_sip_get_auth_attr(auth , &ip , &port , &credential); free(res); res = NULL; conn = tcp_connection_new(); if(proxy != NULL && proxy->proxyEnabled) ret = tcp_connection_connect_with_proxy(conn, ip, port, proxy); else { ret = tcp_connection_connect(conn, ip, port); if(ret == -1) ret = tcp_connection_connect(conn, ip, 443); } if(ret == -1) return -1; /*clone sip*/ conversation->currentSip = fetion_sip_clone(conversation->currentUser->sip); memset(conversation->currentSip->sipuri, 0 , sizeof(conversation->currentSip->sipuri)); strcpy(conversation->currentSip->sipuri , conversation->currentContact->sipuri); fetion_sip_set_connection(conversation->currentSip , conn); free(ip); ip = NULL; /*register*/ sip = conversation->currentSip; fetion_sip_set_type(sip , SIP_REGISTER); aheader = fetion_sip_credential_header_new(credential); theader = fetion_sip_header_new("K" , "text/html-fragment"); mheader = fetion_sip_header_new("K" , "multiparty"); nheader = fetion_sip_header_new("K" , "nudge"); fetion_sip_add_header(sip , aheader); fetion_sip_add_header(sip , theader); fetion_sip_add_header(sip , mheader); fetion_sip_add_header(sip , nheader); res = fetion_sip_to_string(sip , NULL); tcp_connection_send(conn , res , strlen(res)); free(res);res = NULL; free(credential); credential = NULL; res = fetion_sip_get_response(sip); free(res); res = NULL; /*invite buddy*/ fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_INVITEBUDDY); fetion_sip_add_header(sip , eheader); body = generate_invite_friend_body(conversation->currentContact->sipuri); res = fetion_sip_to_string(sip , body); free(body); body = NULL; tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = NULL; res = fetion_sip_get_response(sip); if(fetion_sip_get_code(res) == 200) { free(res); char lastbuf[2048]; tcp_connection_recv(sip->tcp, lastbuf, sizeof(lastbuf)); return 1; }else{ free(res); return -1; } } int fetion_conversation_send_nudge(Conversation* conversation) { SipHeader *toheader = NULL; char* res = NULL; char* body = NULL; FetionSip* sip = conversation->currentSip; if(sip == NULL) { debug_error("Did not start a chat chanel , can not send a nudge"); return -1; } char* sipuri = conversation->currentContact->sipuri; fetion_sip_set_type(sip , SIP_INCOMING); toheader = fetion_sip_header_new("T" , sipuri); fetion_sip_add_header(sip , toheader); body = generate_send_nudge_body(); res = fetion_sip_to_string(sip , body); free(body); debug_info("Sent a nudge to (%s)" , sipuri); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); /* res = fetion_sip_get_response(sip); if(fetion_sip_get_code(res) == 280) { free(res); return 1; } else { printf("%s\n" , res); free(res); debug_error("Send nuge failed"); return -1; }*/ return 1; } char* generate_invite_friend_body(const char* sipuri) { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "contact" , NULL); xmlNewProp(node , BAD_CAST "uri" , BAD_CAST sipuri); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } char* generate_send_nudge_body() { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "state" , NULL); xmlNodeSetContent(node , BAD_CAST "nudge"); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } void fetion_conversation_parse_send_sms(const char* xml , int* daycount , int* mountcount) { xmlDocPtr doc; xmlNodePtr node; xmlChar* res; doc = xmlParseMemory(xml , strlen(xml)); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "frequency"); res = xmlGetProp(node , BAD_CAST "day-count"); *daycount = atoi((char*)res); xmlFree(res); res = xmlGetProp(node , BAD_CAST "month-count"); *mountcount = atoi((char*)res); xmlFree(res); xmlFreeDoc(doc); } libofetion-2.2.2/fetion_contact.h0000644000175000017500000002165611700115314015502 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_CONTACT_H #define FETION_CONTACT_H typedef enum { FETION_NO = 1, MOBILE_NO } NumberType; typedef enum { BUDDY_OK = 200 , BUDDY_SAME_USER_DAILY_LIMIT = 486 , BUDDY_USER_EXIST = 521 , BUDDY_BAD_REQUEST = 400 } AddBuddyType; #define foreach_contactlist(head , cl) \ for(cl = head ; (cl = cl->next) != head ;) #define foreach_groupids(groupids) { char group_str[16] = { 0 }, *pos, *tmp; \ int group_id; tmp = groupids; \ while(*tmp) { \ for(pos = group_str; *tmp != '\0' && *tmp != ';'; *pos++ = *tmp++); \ *pos = '\0'; if (*tmp == ';') tmp ++; group_id = atoi(group_str); \ #define end_groupids(groupids) }} /** * constuct a Contact object */ extern Contact* fetion_contact_new(); /** * append a contact object to the contact list */ extern void fetion_contact_list_append(Contact* cl , Contact* contact); /** * find the contact in the contact list by the specified userid */ extern Contact *fetion_contact_list_find_by_userid(Contact* contactlist , const char* userid); /** * find the contact in the contact list by the specified userid */ extern Contact *fetion_contact_list_find_by_mobileno(Contact *contactlist, const char *mobileno); /** * find the contact in the contact list by the specified sipuri */ extern Contact* fetion_contact_list_find_by_sipuri(Contact* contactlist , const char* sipuri); /** * remove a contact with the specified userid from the contact list */ extern void fetion_contact_list_remove_by_userid(Contact* contactlist , const char* userid); extern void fetion_contact_list_remove(Contact *contact); /** * free the resource of the while contact list * @param contactlist the head of the contact list */ extern void fetion_contact_list_free(Contact* contactlist); /** * test whether there is an ungrouped contact in the contact list * @param contactlist the head of the contact list * @return 1 if there is ungrouped contact , or else -1 */ extern int fetion_contact_has_ungrouped(Contact *contactlist); /** * test whether there is a stranger contact in the contact list * @param contactlist the head of the contact list * @return 1 if there is a stranger contact , or else -1 */ extern int fetion_contact_has_strangers(Contact *contactlist); /** * subscribe the contact`s information after login,and then * the presence information of contacts will be pushed from the server * @return 1 if success , or else -1 */ extern int fetion_contact_subscribe_only(User* user); /** * get the contact`s detail information from the sipc server * @param user Global User object * @param userid The user-id of the contact for which to get information * @return The Contact object with detail information if success , or else NULL */ extern Contact* fetion_contact_get_contact_info(User* user , const char* userid); /** * get the contact`s detail information from the sipc server with the specified number type * @param user Global User object * @param userid The user-id of the contact for which to get information * @param no Fetion number if 'nt' is FETION_NO , or phone number if 'nt' is MOBILE_NO * @param nt Number type to specify the type of the second argument * @return The Contact object with detail information if success , or else NULL */ extern Contact* fetion_contact_get_contact_info_by_no(User* user , const char* no , NumberType nt); /** * modify whether to show your mobile phone number to the user specified by userid * @param user Global User object * @param userid The user-id of the user for whom to set permission * @param show If set to 1,then show phone number to this user , while 0 not show * @return 1 if success , or else -1 */ extern int fetion_contact_set_mobileno_permission(User* user , const char* userid , int show); /** * modify the display name of the user specified by the userid * @return 1 if success , or else -1 */ extern int fetion_contact_set_displayname(User* user , const char* userid , const char* name); /** * move the user specified by userid to the new user group specified by the buddylist * @param user Global User object * @return 1 if success , orelse -1 */ extern int fetion_contact_move_to_group(User *user, const char *userid, int old_bl, int new_bl); /** * copy the buddy specified by userid to the new group specified by the buddylist * @param user Global User object * @return 1 if success , orelse -1 */ extern int fetion_contact_copy_to_group(User *user, const char *userid, int buddylist); /** * remove the buddy specified by userid from the group specified by the buddylist * @param user Global User object * @return 1 if success , orelse -1 */ extern int fetion_contact_remove_from_group(User *user, const char *userid, int buddylist); /** * delete a user specified by userid from your contact * @param user Global User object * @param userid To specify the user to be deleted */ extern int fetion_contact_delete_buddy(User* user , const char* userid); /** * send an Add-Buddy request to sipc server * @param user Global User object * @param no Fetion number is 'notype' is FETION_NO , mobile number if 'notype' it MOBILE_NO * @param notype To specify the number type * @param buddylist To specify which user group the new user will be located * @param localname To specify the local name of the new user * @param desc To specify your display name that will be contained in the request sent to the new uesr * @param phraseid To specify which Add-Buddy phrase to use * @return the contact contains the basic information of the new uesr */ extern Contact* fetion_contact_add_buddy(User* user , const char* no , NumberType notype , int buddylist , const char* localname , const char* desc , int phraseid , int* statuscode); extern Contact* fetion_contact_handle_contact_request(User* user, const char* sipuri , const char* userid , const char* localname , int buddylist , int result); /** * load contact list from local database * @param gcount to be filled with count of group stored in local database * @param bcount to be filled with count of buddy count stored in local database */ extern void fetion_contact_load(User *user, int *gcount, int *bcount); /** * save contact list into local database */ extern void fetion_contact_save(User *user); /** * update a specified contact information in the database */ extern void fetion_contact_update(User *user, Contact *contact); /** * delete buddy information with specified userid from local database */ extern int fetion_contact_del_localbuddy(User *user, const char *userid); /** * delete group information with specified groupid from local database; */ extern int fetion_contact_del_localgroup(User *user, const char *groupid); extern int parse_add_buddy_verification(User* user , const char* str); #endif libofetion-2.2.2/fetion_contact.c0000644000175000017500000011777211700115314015502 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include /*private */ static char* generate_subscribe_body(const char* version); static char* generate_contact_info_body(const char* userid); static char* generate_contact_info_by_no_body(const char* no , NumberType nt); static char* generate_set_mobileno_perssion(const char* userid , int show); static char* generate_set_displayname_body(const char* userid , const char* name); static char* generate_move_to_group_body(const char *userid, const char *groupids); static char* generate_delete_buddy_body(const char* userid); static char* generate_add_buddy_body(const char* no , NumberType notype , int buddylist , const char* localname , const char* desc , int phraseid); static char* generate_handle_contact_request_body(const char* sipuri , const char* userid , const char* localname , int buddylist , int result ); static Contact* parse_handle_contact_request_response(const char* sipmsg); static Contact* parse_add_buddy_response(const char* sipmsg , int* statuscode); static int parse_set_mobileno_permission_response(User* user , const char* sipmsg); static Contact* parse_contact_info_by_no_response(const char* sipmsg); static int has_special_word(const char *in); static char *generate_group_body(const char *userid, const char *buddylist); Contact* fetion_contact_new() { Contact* list = (Contact*)malloc(sizeof(Contact)); if(list == NULL){ return NULL; } memset(list , 0 , sizeof(Contact)); list->imageChanged = IMAGE_NOT_INITIALIZED; list->state = P_HIDDEN; list->pre = list; list->next = list; return list; } void fetion_contact_list_append(Contact* cl , Contact* contact) { cl->next->pre = contact; contact->next = cl->next; contact->pre = cl; cl->next = contact; } Contact* fetion_contact_list_find_by_userid(Contact* contactlist , const char* userid) { Contact* cl_cur; foreach_contactlist(contactlist , cl_cur){ if(strcmp(cl_cur->userId , userid) == 0) return cl_cur; } return NULL; } Contact* fetion_contact_list_find_by_sipuri(Contact* contactlist , const char* sipuri) { Contact *cl_cur; char *sid , *sid1; foreach_contactlist(contactlist , cl_cur){ sid = fetion_sip_get_sid_by_sipuri(cl_cur->sipuri); sid1 = fetion_sip_get_sid_by_sipuri(sipuri); if(strcmp(sid , sid1) == 0){ free(sid); free(sid1); return cl_cur; } free(sid); free(sid1); } return NULL; } Contact *fetion_contact_list_find_by_mobileno(Contact *contactlist, const char *mobileno) { Contact *cl_cur; foreach_contactlist(contactlist, cl_cur) { if(strcmp(cl_cur->mobileno, mobileno) == 0) return cl_cur; } return NULL; } void fetion_contact_list_remove_by_userid(Contact* contactlist , const char* userid) { Contact *cl_cur; foreach_contactlist(contactlist , cl_cur){ if(strcmp(cl_cur->userId , userid) == 0){ cl_cur->pre->next = cl_cur->next; cl_cur->next->pre = cl_cur->pre; free(cl_cur); break; } } } void fetion_contact_list_remove(Contact *contact) { contact->next->pre = contact->pre; contact->pre->next = contact->next; } void fetion_contact_list_free(Contact* contact) { Contact *cl_cur , *del_cur; for(cl_cur = contact->next ; cl_cur != contact ;){ cl_cur->pre->next = cl_cur->next; cl_cur->next->pre = cl_cur->pre; del_cur = cl_cur; cl_cur = cl_cur->next; free(del_cur); } free(contact); } int fetion_contact_subscribe_only(User* user) { char *res, *body; FetionSip* sip; SipHeader* eheader; sip = user->sip; fetion_sip_set_type(sip , SIP_SUBSCRIPTION); eheader = fetion_sip_event_header_new(SIP_EVENT_PRESENCE); if(eheader == NULL){ return -1; } fetion_sip_add_header(sip , eheader); body = generate_subscribe_body("0"); if(body == NULL){ free(eheader); return -1; } res = fetion_sip_to_string(sip , body); if(res == NULL){ free(eheader); free(body); return -1; } free(body); debug_info("Start subscribe contact list"); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); return 0; } Contact* fetion_contact_get_contact_info(User* user , const char* userid) { FetionSip* sip = user->sip; char *res , *body , *pos; char *cur; Contact* contact; xmlChar* cs; xmlDocPtr doc; xmlNodePtr node; contact = fetion_contact_list_find_by_userid(user->contactList , userid); body = generate_contact_info_body(userid); if(body == NULL) return NULL; fetion_sip_set_type(sip , SIP_SERVICE); SipHeader* eheader = fetion_sip_event_header_new(SIP_EVENT_GETCONTACTINFO); if(eheader == NULL){ free(body); return NULL; } fetion_sip_add_header(sip , eheader); res = fetion_sip_to_string(sip , body); free(body); if(res == NULL){ free(res); return NULL; } tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = fetion_sip_get_response(sip); if(res == NULL){ return NULL; } pos = strstr(res , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); if(!doc){ return NULL; } node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; if(xmlHasProp(node , BAD_CAST "carrier-region")){ cs = xmlGetProp(node , BAD_CAST "carrier-region"); pos = (char*)cs; for(cur = contact->country;*pos && *pos != '.';*cur ++ = *pos ++); *cur = '\0'; pos ++; for(cur = contact->province;*pos && *pos != '.';*cur ++ = *pos ++); *cur = '\0'; pos ++; for(cur = contact->city;*pos && *pos != '.';*cur ++ = *pos ++); *cur = '\0'; xmlFree(cs); free(res); } return contact; } int fetion_contact_has_ungrouped(Contact *contactlist) { Contact *cur; foreach_contactlist(contactlist , cur){ if(cur->groupid == BUDDY_LIST_NOT_GROUPED) return 1; } return 0; } int fetion_contact_has_strangers(Contact *contactlist) { Contact *cur; foreach_contactlist(contactlist , cur){ if(cur->groupid == BUDDY_LIST_STRANGER) return 1; } return 0; } Contact* fetion_contact_get_contact_info_by_no(User* user , const char* no , NumberType nt) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; Contact* contact; int ret; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_GETCONTACTINFO); if(eheader == NULL){ return NULL; } fetion_sip_add_header(sip , eheader); body = generate_contact_info_by_no_body(no , nt); if(body == NULL){ return NULL; } res = fetion_sip_to_string(sip , body); free(body); if(res == NULL){ return NULL; } ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = NULL; if(ret < 0) return NULL; res = fetion_sip_get_response(sip); if(res == NULL){ return NULL; } ret = fetion_sip_get_code(res); if(ret == 200){ contact = parse_contact_info_by_no_response(res); free(res); debug_info("Get user information by mobile number success"); return contact; }else{ free(res); debug_error("Get user information by mobile number failed , errno :" , ret); return NULL; } } int fetion_contact_set_mobileno_permission(User* user , const char* userid , int show) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; int ret; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_SETCONTACTINFO); if(eheader == NULL) return -1; fetion_sip_add_header(sip , eheader); body = generate_set_mobileno_perssion(userid , show); if(body == NULL) return -1; res = fetion_sip_to_string(sip , body); free(body); if(res == NULL) return -1; ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res) ; if(ret < 0) return -1; res = fetion_sip_get_response(sip); if(res == NULL) return -1; ret = fetion_sip_get_code(res); if(ret == 200){ parse_set_mobileno_permission_response(user , res); free(res); debug_info("Get user information by mobile number success"); return 0; }else{ free(res); debug_error("Get user information by mobile number failed , errno :" , ret); return -1; } } int fetion_contact_set_displayname(User* user , const char* userid , const char* name) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; int ret; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_SETCONTACTINFO); if(eheader == NULL){ return -1; } fetion_sip_add_header(sip , eheader); body = generate_set_displayname_body(userid , name); if(body == NULL){ return -1; } res = fetion_sip_to_string(sip , body); free(body); if(res == NULL){ return -1; } ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); if(ret < 0) return -1; res = fetion_sip_get_response(sip); if(res == NULL){ return -1; } ret = fetion_sip_get_code(res); free(res); if(ret == 200){ debug_info("Set buddy(%s)`s localname to %s success" , userid , name); return 0; }else{ debug_info("Set buddy(%s)`s localname to %s failed" , userid , name); return -1; } } int fetion_contact_move_to_group(User *user, const char *userid, int old_bl, int new_bl) { FetionSip *sip = user->sip; SipHeader *eheader; Contact *cnt; char bls[1024] = { 0, }; char *res, *body; int ret; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_SETCONTACTINFO); fetion_sip_add_header(sip , eheader); cnt = fetion_contact_list_find_by_userid(user->contactList, userid); foreach_groupids(cnt->groupids) { if(group_id == old_bl) continue; sprintf(bls + strlen(bls), "%d;", group_id); } end_groupids(cnt->groupids) sprintf(bls + strlen(bls), "%d", new_bl); sprintf(cnt->groupids, "%s", bls); body = generate_move_to_group_body(userid, bls); if(!body) return -1; res = fetion_sip_to_string(sip , body); free(body); if(!res) return -1; ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); if(ret < 0) return -1; return 0; } int fetion_contact_copy_to_group(User *user, const char *userid, int buddylist) { FetionSip *sip = user->sip; SipHeader *eheader; Contact *cnt; char *res, *body, newbl[48] = { 0,}; int ret; fetion_sip_set_type(sip , SIP_SERVICE); if (!(eheader = fetion_sip_event_header_new(SIP_EVENT_SETCONTACTINFO))) return -1; fetion_sip_add_header(sip , eheader); cnt = fetion_contact_list_find_by_userid(user->contactList, userid); foreach_groupids(cnt->groupids) { if(group_id == buddylist) return -1; sprintf(newbl + strlen(newbl), "%d;", group_id); } end_groupids(cnt->groupids) sprintf(newbl + strlen(newbl), "%d", buddylist); sprintf(cnt->groupids, "%s", newbl); body = generate_group_body(userid, newbl); res = fetion_sip_to_string(sip, body); free(body); if(!res) return -1; ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); if(ret < 0) return -1; res = fetion_sip_get_response(sip); if(!res) return -1; ret = fetion_sip_get_code(res); free(res); return 0; } int fetion_contact_remove_from_group(User *user, const char *userid, int buddylist) { FetionSip *sip = user->sip; SipHeader *eheader; Contact *cnt; char *res, *body, newbl[48] = { 0,}; int ret; fetion_sip_set_type(sip , SIP_SERVICE); if (!(eheader = fetion_sip_event_header_new(SIP_EVENT_SETCONTACTINFO))) return -1; fetion_sip_add_header(sip , eheader); cnt = fetion_contact_list_find_by_userid(user->contactList, userid); foreach_groupids(cnt->groupids) { if(group_id == buddylist) continue; sprintf(newbl + strlen(newbl), "%d;", group_id); } end_groupids(cnt->groupids) if(newbl[strlen(newbl) - 1] == ';') newbl[strlen(newbl) - 1] = '\0'; sprintf(cnt->groupids, "%s", newbl); body = generate_group_body(userid, newbl); res = fetion_sip_to_string(sip, body); free(body); if(!res) return -1; ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); if(ret < 0) return -1; res = fetion_sip_get_response(sip); if(!res) return -1; ret = fetion_sip_get_code(res); free(res); return 0; } int fetion_contact_delete_buddy(User* user , const char* userid) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; int ret; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_DELETEBUDDY); fetion_sip_add_header(sip , eheader); body = generate_delete_buddy_body(userid); if(body == NULL) return -1; res = fetion_sip_to_string(sip , body); free(body); if(res == NULL) return -1; #if 0 if(fetion_contact_del_localbuddy(user, userid) == -1) return -1; #endif ret = tcp_connection_send(sip->tcp , res , strlen(res)); free(res); if(ret < 0) return -1; res = fetion_sip_get_response(sip); if(res == NULL) return -1; ret = fetion_sip_get_code(res); free(res); return 0; } Contact* fetion_contact_add_buddy(User* user , const char* no , NumberType notype , int buddylist , const char* localname , const char* desc , int phraseid , int* statuscode) { FetionSip* sip = user->sip; SipHeader* eheader = NULL; SipHeader* ackheader = NULL; char *res = NULL; char *body = NULL; int ret; Contact* contact; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_ADDBUDDY); if(eheader == NULL){ return NULL; } fetion_sip_add_header(sip , eheader); if(user->verification != NULL && user->verification->algorithm != NULL) { ackheader = fetion_sip_ack_header_new(user->verification->code , user->verification->algorithm , user->verification->type , user->verification->guid); if(ackheader == NULL){ return NULL; } fetion_sip_add_header(sip , ackheader); } body = generate_add_buddy_body(no , notype , buddylist , localname , desc , phraseid); if(body == NULL){ return NULL; } res = fetion_sip_to_string(sip , body); free(body); if(res == NULL){ return NULL; } tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = fetion_sip_get_response(sip); if(res == NULL){ return NULL; } ret = fetion_sip_get_code(res); *statuscode = ret; int rtv; switch(ret) { case 200 : contact = parse_add_buddy_response(res , statuscode); fetion_verification_free(user->verification); user->verification = NULL; free(res); if(contact == NULL){ debug_info("Add buddy(%s) failed" , no); return NULL; } fetion_contact_list_append(user->contactList , contact); debug_info("Add buddy(%s) success" , no); return contact; case 421 : case 420 : rtv = parse_add_buddy_verification(user , res); free(res); if(rtv != 0){ debug_info("Add buddy(%s) falied , need verification, but parse error" , no); return NULL; } debug_info("Add buddy(%s) falied , need verification" , no); return NULL; default: free(res); debug_info("Add buddy(%s) failed" , no); return NULL; } } Contact* fetion_contact_handle_contact_request(User* user , const char* sipuri , const char* userid , const char* localname , int buddylist , int result) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; int ret; Contact* contact; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_HANDLECONTACTREQUEST); if(eheader == NULL){ return NULL; } fetion_sip_add_header(sip , eheader); body = generate_handle_contact_request_body(sipuri , userid , localname , buddylist , result); if(body == NULL){ return NULL; } res = fetion_sip_to_string(sip , body); free(body); if(res == NULL){ return NULL; } tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = fetion_sip_get_response(sip); if(res == NULL){ return NULL; } ret = fetion_sip_get_code(res); switch(ret) { case 200 : contact = parse_handle_contact_request_response(res); free(res); if(contact == NULL){ debug_info("handle contact request from (%s) failed" , userid); return NULL; } fetion_contact_list_append(user->contactList , contact); debug_info("handle contact request from (%s) success" , userid); return contact; default: free(res); debug_info("handle contact request from (%s) failed" , userid); return NULL; } return NULL; } char* generate_subscribe_body(const char* version) { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "subscription" , NULL); xmlNewProp(node , BAD_CAST "self" , BAD_CAST "v4default;mail-count"); xmlNewProp(node , BAD_CAST "buddy" , BAD_CAST "v4default"); xmlNewProp(node , BAD_CAST "version" , BAD_CAST version); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } char* generate_contact_info_body(const char* userid) { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contact" , NULL); xmlNewProp(node , BAD_CAST "user-id" , BAD_CAST userid); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } char* generate_contact_info_by_no_body(const char* no , NumberType nt) { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node; char uri[32]; char body[] = ""; if(nt == MOBILE_NO) sprintf(uri , "tel:%s" , no); else sprintf(uri , "sip:%s" , no); doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contact" , NULL); xmlNewProp(node , BAD_CAST "uri" , BAD_CAST uri); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } char* generate_set_mobileno_perssion(const char* userid , int show) { xmlChar *buf; xmlDocPtr doc; xmlNodePtr node; char permission[32]; char body[] = ""; sprintf(permission , "identity=%d" , show); doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "contact" , NULL); xmlNewProp(node , BAD_CAST "user-id" , BAD_CAST userid); xmlNewProp(node , BAD_CAST "permission" , BAD_CAST permission); xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } char* generate_handle_contact_request_body(const char* sipuri , const char* userid , const char* localname , int buddylist , int result ) { char args[] = ""; char result_s[4]; char buddylist_s[4]; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddies" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddy" , NULL); xmlNewProp(node , BAD_CAST "user-id" , BAD_CAST userid); xmlNewProp(node , BAD_CAST "uri" , BAD_CAST sipuri); sprintf(result_s , "%d" , result); sprintf(buddylist_s , "%d" , buddylist); xmlNewProp(node , BAD_CAST "result" , BAD_CAST result_s); xmlNewProp(node , BAD_CAST "buddy-lists" , BAD_CAST buddylist_s); xmlNewProp(node , BAD_CAST "expose-mobile-no" , BAD_CAST "1"); xmlNewProp(node , BAD_CAST "expose-name" , BAD_CAST "1"); xmlNewProp(node , BAD_CAST "local-name" , BAD_CAST localname); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } char* generate_set_displayname_body(const char* userid , const char* name) { char args[] = ""; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "contact" , NULL); xmlNewProp(node , BAD_CAST "user-id" , BAD_CAST userid); xmlNewProp(node , BAD_CAST "local-name" , BAD_CAST name); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } static char *generate_move_to_group_body(const char *userid, const char *groupids) { char args[] = ""; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "contact" , NULL); xmlNewProp(node , BAD_CAST "user-id" , BAD_CAST userid); xmlNewProp(node , BAD_CAST "buddy-lists" , BAD_CAST groupids); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } char* generate_delete_buddy_body(const char* userid) { char args[] = ""; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddies" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddy" , NULL); xmlNewProp(node , BAD_CAST "user-id" , BAD_CAST userid); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } char* generate_add_buddy_body(const char* no , NumberType notype , int buddylist , const char* localname , const char* desc , int phraseid) { char args[] = ""; char uri[48]; char phrase[4]; char groupid[4]; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddies" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddy" , NULL); if(notype == FETION_NO) sprintf(uri , "sip:%s" , no); else sprintf(uri , "tel:%s" , no); sprintf(phrase , "%d" , phraseid); sprintf(groupid , "%d" , buddylist); xmlNewProp(node , BAD_CAST "uri" , BAD_CAST uri); xmlNewProp(node , BAD_CAST "local-name" , BAD_CAST localname); xmlNewProp(node , BAD_CAST "buddy-lists" , BAD_CAST groupid); xmlNewProp(node , BAD_CAST "desc" , BAD_CAST desc); xmlNewProp(node , BAD_CAST "expose-mobile-no" , BAD_CAST "1"); xmlNewProp(node , BAD_CAST "expose-name" , BAD_CAST "1"); xmlNewProp(node , BAD_CAST "addbuddy-phrase-id" , BAD_CAST phrase); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } static char *generate_group_body(const char *userid, const char *buddylist) { char args[] = ""; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "contact" , NULL); xmlNewProp(node , BAD_CAST "user-id" , BAD_CAST userid); xmlNewProp(node , BAD_CAST "buddy-lists" , BAD_CAST buddylist); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } static int parse_set_mobileno_permission_response(User* user , const char* sipmsg) { char *pos; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; res = xmlGetProp(node , BAD_CAST "contact-list-version"); memset(user->contactVersion, 0, sizeof(user->contactVersion)); strcpy(user->contactVersion , (char*)res); xmlFree(res); xmlFreeDoc(doc); return 0; } static Contact* parse_contact_info_by_no_response(const char* sipmsg) { char *pos; Contact* contact; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; contact = fetion_contact_new(); pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; if(xmlHasProp(node , BAD_CAST "uri")) { res = xmlGetProp(node , BAD_CAST "uri"); strcpy(contact->sipuri , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "user-id")) { res = xmlGetProp(node , BAD_CAST "user-id"); strcpy(contact->userId , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "sid")) { res = xmlGetProp(node , BAD_CAST "sid"); strcpy(contact->sId , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "nickname")) { res = xmlGetProp(node , BAD_CAST "nickname"); strcpy(contact->nickname , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "gender")) { res = xmlGetProp(node , BAD_CAST "gender"); contact->gender = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "birth-date")) { res = xmlGetProp(node , BAD_CAST "birth-date"); strcpy(contact->birthday , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "impresa")) { res = xmlGetProp(node , BAD_CAST "impresa"); strcpy(contact->impression , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "mobile-no")) { res = xmlGetProp(node , BAD_CAST "mobile-no"); strcpy(contact->mobileno , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "carrier-region")) { int n; res = xmlGetProp(node , BAD_CAST "carrier-region"); pos = (char*)res; if (!(pos == NULL || strcmp(pos, "") == 0)) { n = strlen(pos) - strlen(strstr(pos , ".")); strncpy(contact->country , pos , n); pos = strstr(pos , ".") + 1; n = strlen(pos) - strlen(strstr(pos , ".")); strncpy(contact->province , pos , n); pos = strstr(pos , ".") + 1; n = strlen(pos) - strlen(strstr(pos , ".")); strncpy(contact->city , pos , n); } xmlFree(res); } if(xmlHasProp(node , BAD_CAST "portrait-crc")) { res = xmlGetProp(node , BAD_CAST "portrait-crc"); strcpy(contact->portraitCrc , (char*)res); xmlFree(res); } xmlFreeDoc(doc); return contact; } static Contact* parse_add_buddy_response(const char* sipmsg , int* statuscode) { char *pos; Contact* contact; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; contact = fetion_contact_new(); pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "buddy"); if(node == NULL) { *statuscode = 400; free(contact); return NULL; } if(xmlHasProp(node , BAD_CAST "uri")) { res = xmlGetProp(node , BAD_CAST "uri"); strcpy(contact->sipuri , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "user-id")) { res = xmlGetProp(node , BAD_CAST "user-id"); strcpy(contact->userId , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "mobile-no")) { res = xmlGetProp(node , BAD_CAST "mobile-no"); strcpy(contact->mobileno , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "local-name")) { res = xmlGetProp(node , BAD_CAST "local-name"); strcpy(contact->localname , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "buddy-lists")) { res = xmlGetProp(node , BAD_CAST "buddy-lists"); contact->groupid = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "status-code")) { res = xmlGetProp(node , BAD_CAST "status-code"); *statuscode = atoi((char*)res); xmlFree(res); } else { *statuscode = 200; } if(xmlHasProp(node , BAD_CAST "basic-service-status")) { res = xmlGetProp(node , BAD_CAST "basic-service-status"); contact->serviceStatus = atoi((char*)res); xmlFree(res); } contact->relationStatus = STATUS_NOT_AUTHENTICATED; xmlFreeDoc(doc); return contact; } Contact* parse_handle_contact_request_response(const char* sipmsg) { char *pos = NULL; Contact* contact = NULL; xmlChar* res = NULL; xmlDocPtr doc; xmlNodePtr node; contact = fetion_contact_new(); pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); node = xml_goto_node(node , "buddy"); if(xmlHasProp(node , BAD_CAST "uri")) { res = xmlGetProp(node , BAD_CAST "uri"); strcpy(contact->sipuri , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "user-id")) { res = xmlGetProp(node , BAD_CAST "user-id"); strcpy(contact->userId , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "local-name")) { res = xmlGetProp(node , BAD_CAST "local-name"); strcpy(contact->localname , (char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "buddy-lists")) { res = xmlGetProp(node , BAD_CAST "buddy-lists"); contact->groupid = atoi((char*)res); xmlFree(res); } if(xmlHasProp(node , BAD_CAST "relation-status")){ res = xmlGetProp(node , BAD_CAST "relation-status"); contact->relationStatus = atoi((char*)res); xmlFree(res); }else{ contact->relationStatus = RELATION_STATUS_AUTHENTICATED; } xmlFreeDoc(doc); return contact; } int parse_add_buddy_verification(User* user , const char* str) { char* xml = NULL; char w[128]; int n = 0; xmlDocPtr doc; xmlNodePtr node; xmlChar *res = NULL; Verification *ver = NULL; ver = (Verification*)malloc(sizeof(Verification)); memset(ver , 0 , sizeof(sizeof(Verification))); memset(w, 0, sizeof(w)); fetion_sip_get_attr(str , "W" , w); xml = strstr(w , "algorithm=") + 11; n = strlen(xml) - strlen(strstr(xml , "\"")); ver->algorithm = (char*)malloc(n + 1); memset(ver->algorithm, 0, n + 1); strncpy(ver->algorithm , xml , n); xml = strstr(w , "type=") + 6; n = strlen(xml) - strlen(strstr(xml , "\"")); ver->type = (char*)malloc(n + 1); memset(ver->type, 0, n +1); strncpy(ver->type , xml , n); xml = strstr(str , "\r\n\r\n"); doc = xmlParseMemory(xml , strlen(xml)); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; res = xmlGetProp(node , BAD_CAST "text"); n = xmlStrlen(res) + 1; ver->text = (char*)malloc(n); memset(ver->text, 0, n); strncpy(ver->text , (char*)res , n - 1); xmlFree(res); res = xmlGetProp(node , BAD_CAST "tips"); n = xmlStrlen(res) + 1; ver->tips = (char*)malloc(n); memset(ver->tips, 0, n); strncpy(ver->tips , (char*)res , n - 1); xmlFree(res); user->verification = ver; return 0; } void fetion_contact_load(User *user, int *gcount, int *bcount) { char path[256]; char sql[4096]; sqlite3 *db; char **sqlres; int ncols, nrows, i, j, start; Contact *pos; Group *gpos; Config *config = user->config; debug_info("Load contact list"); *gcount = 0; *bcount = 0; sprintf(path , "%s/data.db" , config->userPath); if(sqlite3_open(path, &db)){ debug_error("failed to load contact list"); return; } sprintf(sql, "select * from groups order by groupid;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ sqlite3_close(db); return; } *gcount = nrows; for(i = 0; i < nrows; i++){ gpos = fetion_group_new(); for(j = 0; j < ncols; j++){ start = ncols + i * ncols; gpos->groupid = atoi(sqlres[start]); strcpy(gpos->groupname, sqlres[start+1]); } fetion_group_list_append(user->groupList, gpos); } sqlite3_free_table(sqlres); sprintf(sql, "select * from contacts_2_2_0;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ sqlite3_close(db); return; } *bcount = nrows; for(i = 0; i < nrows; i++){ pos = fetion_contact_new(); for(j = 0; j < ncols; j++){ start = ncols + i * ncols; strcpy(pos->userId, sqlres[start]); strcpy(pos->sId, sqlres[start+1]); strcpy(pos->sipuri, sqlres[start+2]); strcpy(pos->localname, sqlres[start+3]); strcpy(pos->nickname, sqlres[start+4]); strcpy(pos->impression, sqlres[start+5]); strcpy(pos->mobileno, sqlres[start+6]); strcpy(pos->devicetype, sqlres[start+7]); strcpy(pos->portraitCrc,sqlres[start+8]); strcpy(pos->birthday, sqlres[start+9]); strcpy(pos->country, sqlres[start+10]); strcpy(pos->province, sqlres[start+11]); strcpy(pos->city, sqlres[start+12]); pos->identity = atoi(sqlres[start+13]); pos->scoreLevel = atoi(sqlres[start+14]); pos->serviceStatus = atoi(sqlres[start+15]); pos->carrierStatus = atoi(sqlres[start+16]); pos->relationStatus = atoi(sqlres[start+17]); strcpy(pos->carrier, sqlres[start+18]); pos->groupid = atoi(sqlres[start+19]); pos->gender = atoi(sqlres[start+20]); strcpy(pos->groupids, sqlres[start+21]); } fetion_contact_list_append(user->contactList, pos); } sqlite3_close(db); sqlite3_free_table(sqlres); } void fetion_contact_save(User *user) { char path[256]; char sql[4096]; sqlite3 *db; Contact *pos; Group *gpos; Config *config = user->config; debug_info("Save contact list"); sprintf(path , "%s/data.db" , config->userPath); if(sqlite3_open(path, &db)){ debug_error("failed to save user list"); return; } /* begin transaction */ if(sqlite3_exec(db, "BEGIN TRANSACTION;", 0,0, NULL)){ debug_error("begin transaction :%s", sqlite3_errmsg(db)); sqlite3_close(db); return; } sprintf(sql, "delete from groups"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ sprintf(sql, "create table groups (groupid,groupname)"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table groups:%s", sqlite3_errmsg(db)); sqlite3_close(db); return; } } foreach_grouplist(user->groupList, gpos){ snprintf(sql, sizeof(sql)-1, "insert into groups " "values (%d,'%s');", gpos->groupid, gpos->groupname); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("insert group info:%s", sqlite3_errmsg(db)); continue; } } sprintf(sql, "delete from contacts_2_2_0;"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ sprintf(sql, "create table contacts_2_2_0 (userId," "sId,sipuri,localname,nickname," "impression,mobileno,devicetype," "portraitCrc,birthday,country," "province,city,identity,scoreLevel," "serviceStatus,carrierStatus," "relationStatus,carrier,groupid,gender,groupids);"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table contacts:%s", sqlite3_errmsg(db)); sqlite3_close(db); return; } } foreach_contactlist(user->contactList, pos){ snprintf(sql, sizeof(sql)-1, "insert into contacts_2_2_0 " "values ('%s','%s','%s','%s','%s','%s'," "'%s','%s','%s','%s','%s','%s','%s','%d',%d," "%d,%d,%d,'%s',%d,%d,'%s');", pos->userId, pos->sId, pos->sipuri, has_special_word(pos->localname) ? "": pos->localname, has_special_word(pos->nickname)? "": pos->nickname, has_special_word(pos->impression)?"": pos->impression, pos->mobileno, pos->devicetype, pos->portraitCrc, pos->birthday, pos->country, pos->province, pos->city, pos->identity, pos->scoreLevel, pos->serviceStatus, pos->carrierStatus, pos->relationStatus, pos->carrier, pos->groupid, pos->gender, pos->groupids); if(sqlite3_exec(db, sql, NULL, NULL, NULL)) debug_error("insert contact %s:%s\n%s", pos->userId, sqlite3_errmsg(db), sql); } /* begin transaction */ if(sqlite3_exec(db, "END TRANSACTION;", 0,0, NULL)){ debug_error("end transaction :%s", sqlite3_errmsg(db)); sqlite3_close(db); return; } sqlite3_close(db); debug_info("Save contact list successfully"); } void fetion_contact_update(User *user, Contact *contact) { char path[256]; char sql[4096]; sqlite3 *db; Config *config = user->config; debug_info("Update contact information"); sprintf(path , "%s/data.db" , config->userPath); if(sqlite3_open(path, &db)){ debug_error("failed to load user list"); return; } snprintf(sql, sizeof(sql)-1, "update contacts_2_2_0 set " "userId='%s',sId='%s',sipuri='%s'," "localname='%s',nickname='%s'," "impression='%s',mobileno='%s'," "devicetype='%s',portraitCrc='%s'," "birthday='%s',country='%s'," "province='%s',city='%s'," "identity=%d,scoreLevel=%d," "serviceStatus=%d,carrierStatus=%d," "relationStatus=%d,carrier='%s'," "groupid=%d,gender=%d,groupids='%s' where userId='%s'", contact->userId, contact->sId, contact->sipuri, contact->localname, contact->nickname, contact->impression, contact->mobileno, contact->devicetype, contact->portraitCrc, contact->birthday, contact->country, contact->province, contact->city, contact->identity, contact->scoreLevel, contact->serviceStatus, contact->carrierStatus, contact->relationStatus, contact->carrier, contact->groupid, contact->gender, contact->groupids, contact->userId); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("update contact %s:%s", contact->userId, sqlite3_errmsg(db)); sprintf(sql, "create table contacts_2_2_0 (userId," "sId,sipuri,localname,nickname," "impression,mobileno,devicetype," "portraitCrc,birthday,country," "province,city,identity,scoreLevel," "serviceStatus,carrierStatus," "relationStatus,carrier,groupid,gender,groupids);"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table contacts:%s", sqlite3_errmsg(db)); sqlite3_close(db); return; } snprintf(sql, sizeof(sql)-1, "insert into contacts_2_2_0 " "values ('%s','%s','%s','%s','%s','%s'," "'%s','%s','%s','%s','%s','%s','%s','%d',%d," "%d,%d,%d,'%s',%d,%d,'%s');", contact->userId, contact->sId, contact->sipuri, contact->localname, contact->nickname, contact->impression, contact->mobileno, contact->devicetype, contact->portraitCrc, contact->birthday, contact->country, contact->province, contact->city, contact->identity, contact->scoreLevel, contact->serviceStatus, contact->carrierStatus, contact->relationStatus, contact->carrier, contact->groupid, contact->gender, contact->groupids); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("insert contacts:%s", sqlite3_errmsg(db)); sqlite3_close(db); return; } } sqlite3_close(db); } int fetion_contact_del_localbuddy(User *user, const char *userid) { char path[256]; char sql[4096]; sqlite3 *db; Config *config = user->config; sprintf(path , "%s/data.db" , config->userPath); if(sqlite3_open(path, &db)){ debug_error("failed to delete localbuddy"); return -1; } sprintf(sql, "delete from contacts_2_2_0 where " "userid='%s';", userid); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("failed to delete localbuddy:%s",sqlite3_errmsg(db)); return -1; } return 0; } int fetion_contact_del_localgroup(User *user, const char *groupid) { char path[256]; char sql[4096]; sqlite3 *db; Config *config = user->config; sprintf(path , "%s/data.db" , config->userPath); if(sqlite3_open(path, &db)){ debug_error("failed to delete localgroup"); return -1; } sprintf(sql, "delete from groups where " "id='%s';", groupid); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("failed to delete localgroup:%s",sqlite3_errmsg(db)); return -1; } return 0; } static int has_special_word(const char *in) { int i = 0; int inlength=(int)strlen(in); for(;i< inlength; i++){ if(in[i] == '\'') return 1; } return 0; } libofetion-2.2.2/fetion_connection.h0000644000175000017500000000755211700115314016205 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef P_CONNECTION_H #define P_CONNECTION_H #define MAX_RECV_BUF_SIZE 61140 extern FetionConnection* tcp_connection_new(void); extern FetionConnection* tcp_connection_new_with_port(const int port); extern FetionConnection* tcp_connection_new_with_ip_and_port(const char* ipaddress , const int port); extern int tcp_connection_connect(FetionConnection* connection , const char* ipaddress , const int port); extern int tcp_connection_connect_with_proxy(FetionConnection* connection , const char* ipaddress , const int port , Proxy *proxy); extern int tcp_connection_send(FetionConnection* connetion , const void* buf , int len); extern int tcp_connection_recv(FetionConnection* connection , void* recv , int len); extern void tcp_connection_close(FetionConnection *connection); extern int tcp_connection_select_read(FetionConnection* connection); extern int tcp_connection_recv_dont_wait(FetionConnection* connection , void* recv , int len); extern int tcp_connection_getname(FetionConnection* connection , char **ip , int *port); extern int ssl_connection_start(FetionConnection* conn); extern char* ssl_connection_get(FetionConnection* conn , const char* buf); extern char* http_connection_get_response(FetionConnection* conn); extern int http_connection_get_body_length(const char* http); extern int http_connection_get_head_length(const char* http); extern char* http_connection_encode_url(const char* url); extern void tcp_connection_free(FetionConnection* conn); extern char* get_ip_by_name(const char* hostname); extern char *get_local_ip(); extern char *hexip_to_dotip(const char *ip); #endif libofetion-2.2.2/fetion_connection.c0000644000175000017500000003413411700115314016174 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include const char* global_ssi_uri = "https://uid.fetion.com.cn/ssiportal/SSIAppSignInV4.aspx"; int tcp_keep_alive(int socketfd) { int keepAlive = 1; #ifdef TCP_KEEPIDEL int keepIdle = 10; #endif #ifdef TCP_KEEPINTVL int keepInterval = 10; #endif #ifdef TCP_KEEPCNT int keepCount = 10; #endif if(setsockopt(socketfd , SOL_SOCKET , SO_KEEPALIVE ,(void*)&keepAlive,sizeof(keepAlive)) == -1){ debug_info("set SO_KEEPALIVE failed\n"); return -1; } #ifdef TCP_KEEPIDEL if(setsockopt(socketfd , SOL_TCP , TCP_KEEPIDLE ,(void *)&keepIdle,sizeof(keepIdle)) == -1){ debug_info("set TCP_KEEPIDEL failed\n"); return -1; } #endif #ifdef TCP_KEEPINTVL if(setsockopt(socketfd , SOL_TCP , TCP_KEEPINTVL ,(void *)&keepInterval,sizeof(keepInterval)) == -1){ debug_info("set TCP_KEEPINTVL failed\n"); return -1; } #endif #ifdef TCP_KEEPCNT if(setsockopt(socketfd , SOL_TCP , TCP_KEEPCNT ,(void *)&keepCount,sizeof(keepCount)) == -1){ debug_info("set TCP_KEEPCNT failed\n"); return -1; } #endif return 1; } FetionConnection* tcp_connection_new(void) { int sfd; sfd = socket(AF_INET , SOCK_STREAM , 0); if(sfd == -1){ return NULL; } // if(tcp_keep_alive(conn->socketfd) == -1) // return NULL; FetionConnection* conn = (FetionConnection*)malloc(sizeof(FetionConnection)); if(conn == NULL){ return NULL; } memset(conn , 0 , sizeof(FetionConnection)); conn->socketfd = sfd; conn->ssl = NULL; conn->ssl_ctx = NULL; return conn; } FetionConnection* tcp_connection_new_with_port(const int port) { struct sockaddr_in addr; int sfd = socket(AF_INET , SOCK_STREAM , 0); if(tcp_keep_alive(sfd) == -1){ return NULL; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); int ret = bind(sfd , (struct sockaddr*)(&addr) , sizeof(struct sockaddr)); if(ret == -1){ close(sfd); printf("Failed to bind"); return NULL; } FetionConnection* conn = NULL; conn = (FetionConnection*)malloc(sizeof(FetionConnection)); if(conn == NULL){ close(sfd); return NULL; } memset(conn , 0 , sizeof(FetionConnection)); conn->local_port = port; conn->socketfd = sfd; return conn; } FetionConnection* tcp_connection_new_with_ip_and_port(const char* ipaddress , const int port) { struct sockaddr_in addr; int sfd = socket(AF_INET , SOCK_STREAM , 0); if(tcp_keep_alive(sfd) == -1){ return NULL; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(ipaddress); addr.sin_port = htons(port); int ret = bind(sfd , (struct sockaddr*)(&addr) , sizeof(struct sockaddr)); if(ret == -1) { close(sfd); printf("Failed to bind"); return NULL; } FetionConnection* conn = NULL; conn = (FetionConnection*)malloc(sizeof(FetionConnection)); if(conn == NULL){ close(sfd); return NULL; } memset(conn , 0 , sizeof(FetionConnection)); conn->socketfd = sfd; strcpy(conn->local_ipaddress , ipaddress); return conn; } int tcp_connection_connect(FetionConnection *connection, const char *ipaddress, const int port) { struct sockaddr_in addr; int n; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(ipaddress); addr.sin_port = htons(port); strcpy(connection->remote_ipaddress , ipaddress); connection->remote_port = port; int sk, flags, err, ret; socklen_t len = sizeof(err); struct timeval tv; fd_set fd_write; tv.tv_sec = 7; tv.tv_usec = 0; sk = connection->socketfd; if((flags = fcntl(sk, F_GETFL, 0)) == -1) return -1; if((flags = fcntl(sk, F_SETFL, flags | O_NONBLOCK)) == -1) return -1; n = MAX_RECV_BUF_SIZE; int s = setsockopt(sk, SOL_SOCKET, SO_RCVBUF, (const char*)&n , sizeof(n)); if(s == -1) return -1; debug_info("%s:%d", ipaddress, port); if(connect(sk, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == -1) { if(errno != EINPROGRESS) return -1; FD_ZERO(&fd_write); FD_SET(sk, &fd_write); ret = select(sk + 1, (fd_set*)0, &fd_write, (fd_set*)0, &tv); if(ret > 0) { if(FD_ISSET(sk, &fd_write)) { if(getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) == -1) return -1; if (err == 0) goto success; else return -1; } else return -1; } else return -1; } success: if((flags = fcntl(sk, F_SETFL, flags)) == -1) return -1; return 0; } int tcp_connection_connect_with_proxy(FetionConnection* connection , const char* ipaddress , const int port , Proxy *proxy) { struct sockaddr_in addr; char *ip = get_ip_by_name(proxy->proxyHost); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(ip); free(ip); addr.sin_port = htons(proxy->proxyPort); strcpy(connection->remote_ipaddress , ipaddress); connection->remote_port = port; unsigned int n = MAX_RECV_BUF_SIZE; int ret = setsockopt(connection->socketfd , SOL_SOCKET , SO_RCVBUF , (const char*)&n , sizeof(n)); if(ret == -1) return -1; ret = connect(connection->socketfd , (struct sockaddr*)&addr , sizeof(struct sockaddr)); if(ret == -1) return -1; printf("%s:%d\n", ipaddress, port); char http[1024] , code[5] , *pos = NULL; unsigned char authentication[1024]; char authen[1024]; char authorization[1024]; memset(authorization, 0, sizeof(authorization)); if(strlen(proxy->proxyUser) != 0 && strlen(proxy->proxyPass) != 0) { memset(authen, 0, sizeof(authen)); sprintf(authen , "%s:%s" , proxy->proxyUser , proxy->proxyPass); EVP_EncodeBlock(authentication , (unsigned char*)authen , strlen(authen)); sprintf(authorization , "Proxy-Authorization: Basic %s\r\n" , (char*)authentication); } memset(http, 0, sizeof(http)); snprintf(http , sizeof(http)-1 , "CONNECT %s:%d HTTP/1.1\r\n" "Host: %s:%d\r\n%s" "User-Agent: OpenFetion\r\n\r\n" , ipaddress , port , ipaddress , port , authorization); tcp_connection_send(connection , http , strlen(http)); memset(http, 0, sizeof(http)); tcp_connection_recv(connection , http , sizeof(http)); pos = strstr(http , " "); if(pos == NULL){ return -1; } pos++; n = strlen(pos) - strlen(strstr(pos , " ")); memset(code, 0, sizeof(code)); strncpy(code, pos, (sizeof(code)-1 < n) ? (sizeof(code)-1) : n); code[sizeof(code)-1]='\0'; if(strcmp(code , "200") != 0) return -1; return 1; } int tcp_connection_select_read(FetionConnection* connection) { fd_set fs ; struct timeval tv ; tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO(&fs); FD_SET(connection->socketfd , &fs); return select(connection->socketfd + 1 , &fs , NULL , NULL , &tv ); } int tcp_connection_send(FetionConnection* connection , const void* buf , int len) { return send(connection->socketfd , buf , len , 0); } int tcp_connection_recv(FetionConnection* connection , void* buf , int len) { return recv(connection->socketfd , buf , len , 0); } int tcp_connection_recv_dont_wait(FetionConnection* connection , void* buf , int len) { return recv(connection->socketfd , buf , len , MSG_DONTWAIT); } int tcp_connection_getname(FetionConnection* connection , char **ip , int *port) { struct sockaddr_in addr; int ret; socklen_t len = 0; len = sizeof(struct sockaddr); ret = getsockname(connection->socketfd , (struct sockaddr*)&addr , &len); *ip = inet_ntoa(addr.sin_addr); *port = ntohs(addr.sin_port); return ret; } void tcp_connection_close(FetionConnection *connection) { close(connection->socketfd); debug_info("Close connection with %s:%d", connection->remote_ipaddress, connection->remote_port); } int ssl_connection_start(FetionConnection* conn) { int ret; SSL_load_error_strings(); SSL_library_init(); conn->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); if ( conn->ssl_ctx == NULL ){ debug_info("Init SSL CTX failed"); return -1; } conn->ssl = SSL_new(conn->ssl_ctx); if ( conn->ssl == NULL ){ debug_info("New SSL with created CTX failed"); return -1; } ret = SSL_set_fd(conn->ssl, conn->socketfd); if ( ret == 0 ){ debug_info("Add ssl to tcp socket failed"); return -1; } RAND_poll(); while ( RAND_status() == 0 ) { unsigned short rand_ret = rand() % 65536; RAND_seed(&rand_ret, sizeof(rand_ret)); } ret = SSL_connect(conn->ssl); if( ret != 1 ) { debug_info("SSL connection failed"); return -1; } return 0; } char* ssl_connection_get(FetionConnection* conn , const char* buf) { char* ret; ret = (char*)malloc(1025); if(ret == NULL){ return NULL; } memset(ret , 0 , 1025); SSL_write(conn->ssl, buf, strlen(buf)); SSL_read(conn->ssl, ret , 1024); return ret; } char *http_connection_get_response(FetionConnection *conn) { char buf[1024 * 4]; char *res = 0, *res1 = 0, *pos = 0; int c = 0, res_len = 0; while((c = tcp_connection_recv( conn, buf, sizeof(buf) - 1)) != 0) { if (!res) res_len = 0; else res_len = strlen(res); res = realloc(res, res_len + c + 1); strncpy(res + res_len, buf, c); res[res_len + c] = '\0'; } if(!(pos = strstr(res, "\r\n\r\n"))) return (char*)0; pos += 4; if(!(res1 = malloc(strlen(pos) + 1))) return (char*)0; strncpy(res1, pos, strlen(pos)); res1[strlen(pos)] = '\0'; free(res); return res1; } int http_connection_get_body_length(const char* http) { char *pos , length[10]; int len; pos = strstr(http , "Content-Length: "); if(pos == NULL) return 0; pos += 16; len = strlen(pos) - strlen(strstr(pos , "\r\n")); memset(length, 0, sizeof(length)); strncpy(length , pos , (len<9)?len:9); return atoi(length); } int http_connection_get_head_length(const char* http) { char *tmp = strstr(http , "\r\n\r\n"); if(tmp == NULL) return -1; return strlen(http) - strlen(tmp); } void tcp_connection_free(FetionConnection* conn) { if(conn->ssl != NULL && conn->ssl_ctx != NULL) { SSL_free(conn->ssl); SSL_CTX_free(conn->ssl_ctx); ERR_free_strings(); } close(conn->socketfd); free(conn); } char* get_ip_by_name(const char* hostname) { struct hostent *hst; char *name , *pos; int len; char* ip = (char*)malloc(20); memset(ip , 0 , 20); pos = strstr(hostname , "//"); if(pos != NULL) pos += 2; else pos = (char*)hostname; if(strstr(pos , "/") != NULL) len = strlen(pos) - strlen(strstr(pos , "/")); else len = strlen(pos); name = (char*)malloc(len + 1); memset(name , 0 , len + 1); strncpy(name , pos , len); reget: hst = gethostbyname(name); if(hst == NULL) goto reget; inet_ntop(AF_INET , hst->h_addr , ip , 16); free(name); return ip; } char* http_connection_encode_url(const char* url) { char pos; char* res; char tmp[2]; int i = 1; res = (char*)malloc(2048); if(res == NULL){ return NULL; } pos = url[0]; memset(res , 0 , 2048); while(pos != '\0') { if(pos == '/') strcat(res , "%2f"); else if(pos == '@') strcat(res , "%40"); else if(pos == '=') strcat(res , "%3d"); else if(pos == ':') strcat(res , "%3a"); else if(pos == ';') strcat(res , "%3b"); else if(pos == '+'){ strcat(res , "%2b"); }else{ memset(tmp, 0, sizeof(tmp)); sprintf(tmp , "%c" , pos); strcat(res , tmp); } pos = (url + (i ++))[0]; } return res; } char *get_local_ip(){ #if 0 struct ifreq req; int sock; char *ip = NULL; DEBUG_FOOTPRINT(); sock = socket(AF_INET, SOCK_DGRAM, 0); strncpy(req.ifr_name, "eth0", IFNAMSIZ); if ( ioctl(sock, SIOCGIFADDR, &req) < 0 ) { debug_error("Get local ipaddress failed"); return NULL; } ip = (char *)inet_ntoa(*(struct in_addr *) &((struct sockaddr_in *) &req.ifr_addr)->sin_addr); shutdown(sock, 2); close(sock); #endif return ""; } char *hexip_to_dotip(const char *ip){ char *out; char tmp[3]; char tmp1[4]; unsigned int i , j = 0; long res; out = (char*)malloc(18); if(out == NULL){ return NULL; } memset(out, 0, 18); memset(tmp, 0, sizeof(tmp)); for(i = 0 ; i < strlen(ip) ; i ++){ tmp[j++] = ip[i]; if(j == 2){ res = strtol(tmp , NULL , 16); memset(tmp1, 0, sizeof(tmp1)); sprintf(tmp1 , "%ld" , res); strcat(out , tmp1); if(i != 7){ strcat(out , "."); } j = 0; } } return out; } libofetion-2.2.2/fetion_config.h0000644000175000017500000001044411700115314015305 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_CONFIG_H #define FETION_CONFIG_H typedef struct { char content[256]; int phraseid; } Phrase; extern Config* fetion_config_new(); extern int fetion_config_download_configuration(User* user); extern int fetion_config_initialize(Config* config , const char* userid); extern int fetion_config_load_size(Config *config); extern int fetion_config_save_size(Config *config); extern int fetion_config_get_use_status_icon(Config *config); extern int fetion_config_set_use_status_icon(Config *config); extern int fetion_config_load(User* user); extern Proxy* fetion_config_load_proxy(); extern void fetion_config_save_proxy(Proxy *proxy); extern int fetion_config_save(User* user); extern char* fetion_config_get_city_name(const char* province , const char* city); extern char* fetion_config_get_province_name(const char* province); extern FxList* fetion_config_get_phrase(Config* config); extern void fetion_phrase_free(Phrase* phrase); extern void fetion_config_free(Config *config); /*user list*/ #define foreach_userlist(head , ul) \ for(ul = head ; (ul = ul->next) != head;) extern struct userlist* fetion_user_list_new(const char *no, const char *password , const char *userid, const char *sid, int laststate , int islastuser); extern void fetion_user_list_append(struct userlist *head , struct userlist *ul); extern void fetion_user_list_save(Config* config , struct userlist* ul); extern void fetion_user_list_set_lastuser_by_no(struct userlist *ul , const char* no); extern int fetion_user_list_remove(Config *config, const char *no); extern struct userlist* fetion_user_list_find_by_no(struct userlist* list , const char* no); extern struct userlist* fetion_user_list_load(Config* config); extern void fetion_user_list_update_userid(Config *config, const char *no, const char *userid); extern void fetion_user_list_free(struct userlist *list); extern xmlNodePtr xml_goto_node(xmlNodePtr node , const char* xml); extern char* xml_convert(xmlChar* in); void escape_sql(char *in); void unescape_sql(char *in); #endif libofetion-2.2.2/fetion_config.c0000644000175000017500000006612211700115314015304 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include #include #include static int parse_configuration_xml(User *user, const char *xml); static char* generate_configuration_body(User* user); static void save_phrase(xmlNodePtr node, User *user); Config* fetion_config_new() { char* homepath = NULL; Config* config = NULL; homepath = getenv("HOME"); config = (Config*)malloc(sizeof(Config)); memset(config , 0 , sizeof(Config)); snprintf(config->globalPath, sizeof(config->globalPath)-1, "%s/.openfetion" , homepath); config->globalPath[sizeof(config->globalPath)-1] = '\0'; int e; e = mkdir(config->globalPath, S_IRWXU|S_IRWXO|S_IRWXG); if(e && access(config->globalPath,R_OK|W_OK)){ debug_error("%s,cannot create, read or write", config->globalPath); free(config); return NULL; } config->ul = NULL; config->iconSize = 25; return config; } FxList* fetion_config_get_phrase(Config* config) { char path[256]; char sql[1024]; sqlite3 *db; char **sqlres; int ncols, nrows, i, start; FxList *list, *pos; Phrase *phrase; list = fx_list_new(NULL); snprintf(path, sizeof(path)-1, "%s/data.db" , config->userPath); if(sqlite3_open(path, &db)){ debug_error("failed to load user list"); return list; } snprintf(sql, sizeof(sql)-1, "select * from phrases order by id desc;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ debug_error("read phrases :%s", sqlite3_errmsg(db)); sqlite3_close(db); return list; } for(i = 0; i < nrows; i ++){ phrase = (Phrase*)malloc(sizeof(Phrase)); start = ncols + i * ncols; phrase->phraseid = atoi(sqlres[start]); strncpy(phrase->content, sqlres[start+1], 255); pos = fx_list_new(phrase); fx_list_append(list , pos); } sqlite3_free_table(sqlres); sqlite3_close(db); return list; } void fetion_phrase_free(Phrase* phrase) { free(phrase); } void fetion_config_free(Config *config) { if(config != NULL){ fetion_user_list_free(config->ul); free(config); } } struct userlist* fetion_user_list_new(const char *no, const char *password, const char *userid, const char *sid, int laststate , int islastuser) { struct userlist* ul; ul = (struct userlist*)malloc(sizeof(struct userlist)); memset(ul , 0 , sizeof(struct userlist)); if(no) strcpy(ul->no , no); if(password) strcpy(ul->password , password); if(userid) strcpy(ul->userid, userid); if(sid) strcpy(ul->sid, sid); ul->laststate = laststate; ul->islastuser = islastuser; ul->next = ul->pre = ul; return ul; } void fetion_user_list_append(struct userlist* head , struct userlist* ul) { head->next->pre = ul; ul->next = head->next; ul->pre = head; head->next = ul; } void fetion_user_list_save(Config* config , struct userlist* ul) { char path[256]; char sql[1024]; char password[1024]; sqlite3 *db; struct userlist *pos; memset(path , 0 , sizeof(path)); snprintf(path, sizeof(path)-1, "%s/data.db" , config->globalPath); if(sqlite3_open(path, &db)){ debug_error("failed to save user list"); return; } snprintf(sql, sizeof(sql)-1, "delete from userlist;"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("delete userlist failed:%s", sqlite3_errmsg(db)); sqlite3_close(db); return; } foreach_userlist(ul, pos){ snprintf(password, sizeof(password)-1, "%s", pos->password); escape_sql(password); snprintf(sql, sizeof(sql)-1, "insert into userlist values" "('%s','%s',%d,%d,'%s','%s')", pos->no, password, pos->laststate, pos->islastuser, pos->userid, pos->sid); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("insert no : %s failed: %s", pos->no, sqlite3_errmsg(db)); continue; } } sqlite3_close(db); } void fetion_user_list_set_lastuser_by_no(struct userlist* ul , const char* no) { struct userlist* pos; foreach_userlist(ul , pos){ if(strcmp(pos->no , no) == 0) pos->islastuser = 1; else pos->islastuser = 0; } } struct userlist* fetion_user_list_find_by_no(struct userlist* list , const char* no) { struct userlist* pos; foreach_userlist(list , pos){ if(strcmp(pos->no , no) == 0) return pos; } return NULL; } static int create_userlist_table(sqlite3 *db) { char sql[1024]; sprintf(sql, "create table userlist (no, password" ", laststate, islastuser,userid,sid);"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table userlist failed:%s", sqlite3_errmsg(db)); return 1; } return 0; } struct userlist* fetion_user_list_load(Config* config) { char path[256]; char sql[1024]; sqlite3 *db; char **sqlres; struct userlist *res = NULL , *pos; int ncols, nrows, i, start; res = fetion_user_list_new(NULL, NULL, NULL, NULL, 0, 0); snprintf(path, sizeof(path)-1, "%s/data.db" , config->globalPath); if(sqlite3_open(path, &db)){ debug_error("failed to load user list"); return res; } snprintf(sql, sizeof(sql)-1, "select sid from userlist;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ create_ul_table: if(create_userlist_table(db)){ sprintf(sql, "drop table userlist;"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ goto create_ul_table; } sqlite3_close(db); return res; } } sqlite3_free_table(sqlres); snprintf(sql, sizeof(sql), "select * from userlist order by islastuser desc;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ if(create_userlist_table(db)){ sqlite3_close(db); return res; } } if(nrows == 0 || ncols == 0){ goto list_load_re; } debug_info("Loading user list store in local data file"); for(i = 0; i < nrows; i ++){ start = ncols + i * ncols; pos = fetion_user_list_new(sqlres[start], sqlres[start + 1], sqlres[start + 4], sqlres[start + 5], atoi(sqlres[start + 2]), atoi(sqlres[start + 3])); unescape_sql(pos->password); fetion_user_list_append(res , pos); } list_load_re: sqlite3_free_table(sqlres); sqlite3_close(db); return res; } void fetion_user_list_update_userid(Config *config, const char *no, const char *userid) { char path[256]; char sql[1024]; sqlite3 *db; snprintf(path, sizeof(path), "%s/data.db" , config->globalPath); if(sqlite3_open(path, &db)){ debug_error("failed to load user list"); return; } snprintf(sql, sizeof(sql), "update userlist set userid='%s' " "where no='%s';",userid, no); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("update userlist:%s", sqlite3_errmsg(db)); } sqlite3_close(db); return; } void fetion_user_list_free(struct userlist *list) { struct userlist *cur; struct userlist *tmp; if(list == NULL) return; cur = list->next; while(cur != list){ tmp = cur; cur = cur->next; free(tmp); } } int fetion_config_download_configuration(User* user) { char http[1025] , *body , *res; FetionConnection* conn = NULL; Config *config = user->config; int ret; char uri[] = "nav.fetion.com.cn"; char* ip; ip = get_ip_by_name(uri); if(ip == NULL){ debug_error("Parse configuration uri (%s) failed!!!", uri); return -1; } conn = tcp_connection_new(); if(config->proxy != NULL && config->proxy->proxyEnabled) ret = tcp_connection_connect_with_proxy(conn , ip , 80 , config->proxy); else ret = tcp_connection_connect(conn , ip , 80); if(ret < 0) return -1; body = generate_configuration_body(user); snprintf(http, sizeof(http), "POST /nav/getsystemconfig.aspx HTTP/1.1\r\n" "User-Agent: IIC2.0/PC "PROTO_VERSION"\r\n" "Host: %s\r\n" "Connection: Close\r\n" "Content-Length: %d\r\n\r\n%s" , uri , strlen(body) , body); ret = tcp_connection_send(conn , http , strlen(http)); if(ret < 0) return -1; res = http_connection_get_response(conn); parse_configuration_xml(user, res); free(res); free(ip); free(conn); free(body); return 1; } int fetion_config_initialize(Config* config , const char* userid) { // DIR *userdir , *icondir; snprintf(config->userPath, sizeof(config->userPath), "%s/%s" , config->globalPath , userid); snprintf(config->iconPath, sizeof(config->iconPath), "%s/icons" , config->userPath ); int e; e = mkdir(config->userPath, S_IRWXU|S_IRWXO|S_IRWXG); if(e && access(config->userPath,R_OK|W_OK)){ debug_error("%s,cannot create, read or write", config->userPath); return 1; } e = mkdir(config->iconPath, S_IRWXU|S_IRWXO|S_IRWXG); if(e && access(config->iconPath,R_OK|W_OK)){ debug_error("%s,cannot create, read or write",config->iconPath); return 1; } return 0; } static int parse_configuration_xml(User *user, const char *xml) { Config* config = user->config; char sipcIP[20] , sipcPort[6]; char* pos; int n; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; xmlNodePtr cnode; memset(sipcIP, 0, sizeof(sipcIP)); memset(sipcPort, 0, sizeof(sipcPort)); doc = xmlParseMemory(xml, strlen(xml)); if(!doc){ debug_error("Can not read configuration"); return -1; } node = xmlDocGetRootElement(doc); cnode = xml_goto_node(node, "servers"); if(cnode && xmlHasProp(cnode, BAD_CAST "version")){ res = xmlGetProp(cnode, BAD_CAST "version"); strcpy(config->configServersVersion, (char*)res); xmlFree(res); } cnode = xml_goto_node(node, "parameters"); if(cnode && xmlHasProp(cnode, BAD_CAST "version")){ res = xmlGetProp(cnode, BAD_CAST "version"); strncpy(config->configParametersVersion, (char*)res, sizeof(config->configParametersVersion)); xmlFree(res); } cnode = xml_goto_node(node, "hints"); if(cnode && xmlHasProp(cnode, BAD_CAST "version")){ res = xmlGetProp(cnode, BAD_CAST "version"); strncpy(config->configHintsVersion, (char*)res, sizeof(config->configHintsVersion)); xmlFree(res); } cnode = xml_goto_node(node, "sipc-proxy"); if(cnode){ res = xmlNodeGetContent(cnode); n = strlen((char*)res) - strlen(strstr((char*)res , ":")); strncpy(config->sipcProxyIP , (char*)res , n); pos = strstr((char*)res , ":") + 1; config->sipcProxyPort = atoi(pos); xmlFree(res); } cnode = xml_goto_node(node , "get-uri"); if(cnode){ res = xmlNodeGetContent(cnode); pos = strstr((char*)res , "//") + 2; n = strlen(pos) - strlen(strstr(pos , "/")); strncpy(config->portraitServerName , pos , n); pos = strstr(pos , "/") + 1; n = strlen(pos) - strlen(strstr(pos , "/")); strncpy(config->portraitServerPath , pos , n); xmlFree(res); } save_phrase(node, user); return 1; } int fetion_config_load_size(Config *config) { char path[256]; char sql[4096]; char **sqlres; sqlite3 *db; int ncols, nrows; sprintf(path, "%s/data.db", config->globalPath); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return -1; } snprintf(sql, sizeof(sql), "select * from size;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ sqlite3_close(db); return -1; } config->window_width = atoi(sqlres[ncols]); config->window_height = atoi(sqlres[ncols+1]); config->window_pos_x = atoi(sqlres[ncols+2]); config->window_pos_y = atoi(sqlres[ncols+3]); sqlite3_free_table(sqlres); sqlite3_close(db); return 1; } int fetion_config_save_size(Config *config) { char path[256]; char sql[4096]; sqlite3 *db; snprintf(path, sizeof(path), "%s/data.db" , config->globalPath); if(sqlite3_open(path, &db)){ debug_error("failed to load user list"); return -1; } snprintf(sql, sizeof(sql), "delete from size;"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ snprintf(sql, sizeof(sql), "create table size (" "window_width,window_height," "window_pos_x,window_pos_y);"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table size:%s", sqlite3_errmsg(db)); } } snprintf(sql, sizeof(sql), "insert into size values (" "%d,%d,%d,%d);", config->window_width, config->window_height, config->window_pos_x, config->window_pos_y); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("save size:%s", sqlite3_errmsg(db)); sqlite3_close(db); return -1; } sqlite3_close(db); return 1; } int fetion_config_get_use_status_icon(Config *config) { char path[256]; char sql[4096]; char **sqlres; sqlite3 *db; int ncols, nrows; sprintf(path, "%s/data.db", config->globalPath); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return -1; } snprintf(sql, sizeof(sql), "select * from statusicon;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ sqlite3_close(db); return -1; } config->useStatusIcon = atoi(sqlres[ncols]); sqlite3_free_table(sqlres); sqlite3_close(db); return 1; } int fetion_config_set_use_status_icon(Config *config) { char path[256]; char sql[4096]; sqlite3 *db; snprintf(path, sizeof(path), "%s/data.db" , config->globalPath); if(sqlite3_open(path, &db)){ return -1; } snprintf(sql, sizeof(sql), "delete from statusicon;"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ snprintf(sql, sizeof(sql), "create table statusicon (use);"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table statusicon:%s", sqlite3_errmsg(db)); } } snprintf(sql, sizeof(sql), "insert into statusicon values (%d);", config->useStatusIcon); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("save statusicon:%s", sqlite3_errmsg(db)); sqlite3_close(db); return -1; } sqlite3_close(db); return 1; } int fetion_config_load(User *user) { char path[256]; char sql[4096]; char **sqlres; sqlite3 *db; int ncols, nrows; Config *config = user->config; sprintf(path, "%s/data.db", config->userPath); debug_info("Load configuration"); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s error.", sqlite3_errmsg(db)); return -1; } sprintf(sql, "select * from config_2_2_0;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ sqlite3_close(db); return -1; } strcpy(config->sipcProxyIP, sqlres[ncols]); config->sipcProxyPort = atoi(sqlres[ncols+1]); strcpy(config->portraitServerName, sqlres[ncols+2]); strcpy(config->portraitServerPath, sqlres[ncols+3]); config->iconSize = atoi(sqlres[ncols+4]); config->closeAlert = atoi(sqlres[ncols+5]); config->autoReply = atoi(sqlres[ncols+6]); config->isMute = atoi(sqlres[ncols+7]); strcpy(config->autoReplyMessage, sqlres[ncols+8]); config->msgAlert = atoi(sqlres[ncols+9]); config->autoPopup = atoi(sqlres[ncols+10]); config->sendMode = atoi(sqlres[ncols+11]); config->closeMode = atoi(sqlres[ncols+12]); config->canIconify = atoi(sqlres[ncols+13]); config->allHighlight = atoi(sqlres[ncols+14]); strcpy(config->configServersVersion, sqlres[ncols+15]); strcpy(config->configParametersVersion, sqlres[ncols+16]); strcpy(config->configHintsVersion, sqlres[ncols+17]); config->autoAway = atoi(sqlres[ncols+18]); config->autoAwayTimeout = atoi(sqlres[ncols+19]); config->onlineNotify = atoi(sqlres[ncols+20]); config->closeSysMsg = atoi(sqlres[ncols+21]); config->closeFetionShow = atoi(sqlres[ncols+22]); config->useStatusIcon = atoi(sqlres[ncols+23]); sqlite3_free_table(sqlres); sqlite3_close(db); fetion_config_get_use_status_icon(config); return 1; } int fetion_config_save(User *user) { char path[256]; char sql[4096]; char sql1[4096]; int count = 0; sqlite3 *db; Config *config = user->config; snprintf(path, sizeof(path), "%s/data.db" , config->userPath); debug_info("Save configuration"); if(sqlite3_open(path, &db)){ debug_error("failed to load user list"); return -1; } sprintf(sql, "delete from config_2_2_0;"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ recreate: snprintf(sql, sizeof(sql), "create table config_2_2_0 (" "sipcProxyIP,sipcProxyPort," "portraitServerName,portraitServerPath," "iconSize,closeAlert,autoReply,isMute," "autoReplyMessage,msgAlert,autoPopup," "sendMode,closeMode,canIconify,allHighlight," "serversVersion,paremetersVersion," "hintsVersion,autoAway,autoAwayTimeout," "onlineNotify,closeSysMsg,closeFetionShow,useStatusIcon);"); count ++; if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table config:%s",sqlite3_errmsg(db)); if(count == 2){ sqlite3_close(db); return -1; } } } sprintf(sql, "insert into config_2_2_0 values (" "'%s',%d,'%s','%s',%d,%d,%d," "%d,'%s',%d,%d,%d,%d,%d,%d," "'%s','%s','%s',%d,%d,%d,%d,%d,%d);", config->sipcProxyIP, config->sipcProxyPort, config->portraitServerName, config->portraitServerPath, config->iconSize, config->closeAlert, config->autoReply, config->isMute, config->autoReplyMessage, config->msgAlert, config->autoPopup, config->sendMode, config->closeMode, config->canIconify, config->allHighlight, config->configServersVersion, config->configParametersVersion, config->configHintsVersion, config->autoAway, config->autoAwayTimeout, config->onlineNotify, config->closeSysMsg, config->closeFetionShow, config->useStatusIcon); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("save config:%s", sqlite3_errmsg(db)); sprintf(sql1, "drop table config_2_2_0;"); if(sqlite3_exec(db, sql1, NULL, NULL, NULL)){ debug_error("drop table config:%s", sqlite3_errmsg(db)); } goto recreate; } sqlite3_close(db); return 1; } Proxy* fetion_config_load_proxy() { Proxy *proxy=NULL; sqlite3 *db; char **sqlres; char sql[1024]; char path[1024]; int ncols, nrows; snprintf(path, sizeof(path),"%s/.openfetion/data.db",getenv("HOME")); debug_info("Read proxy information"); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return NULL; } sprintf(sql, "select * from proxy;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ sprintf(sql, "create table proxy (" "proxyEnabled, proxyHost," "proxyPort, proxyUser, proxyPass);"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_info("create table proxy:%s", sqlite3_errmsg(db)); } goto load_proxy; } if(!nrows) goto load_proxy; proxy = (Proxy*)malloc(sizeof(Proxy)); proxy->proxyEnabled = atoi(sqlres[ncols]); strcpy(proxy->proxyHost, sqlres[ncols+1]); proxy->proxyPort = atoi(sqlres[ncols+2]); strcpy(proxy->proxyUser, sqlres[ncols+3]); strcpy(proxy->proxyPass, sqlres[ncols+4]); load_proxy: sqlite3_close(db); return proxy; } void fetion_config_save_proxy(Proxy *proxy) { sqlite3 *db; char **sqlres; char sql[1024]; char path[1024]; int ncols, nrows; snprintf(path, sizeof(path), "%s/.openfetion/data.db", getenv("HOME")); debug_info("Save proxy information"); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return; } sprintf(sql, "select * from proxy;"); if(sqlite3_get_table(db, sql, &sqlres, &nrows, &ncols, NULL)){ sprintf(sql, "create table proxy (" "proxyEnabled, proxyHost," "proxyPort, proxyUser, proxyPass);"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table proxy:%s",sqlite3_errmsg(db)); } nrows = 0; } if(nrows == 0){ snprintf(sql, sizeof(sql), "insert into proxy values(" "%d,'%s',%d,'%s','%s');", proxy->proxyEnabled, proxy->proxyHost, proxy->proxyPort, proxy->proxyUser, proxy->proxyPass); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("insert into proxy:%s",sqlite3_errmsg(db)); return; } }else{ snprintf(sql, sizeof(sql), "update proxy set proxyEnabled=%d," "proxyHost='%s',proxyPort='%d'," "proxyUser='%s',proxyPass='%s';", proxy->proxyEnabled, proxy->proxyHost, proxy->proxyPort, proxy->proxyUser, proxy->proxyPass); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("update proxy:%s", sqlite3_errmsg(db)); return; } } } static char* generate_configuration_body(User* user) { xmlChar* buf; xmlDocPtr doc; xmlNodePtr node , cnode; char body[] = ""; doc = xmlParseMemory(body , strlen(body)); node = xmlDocGetRootElement(doc); cnode = xmlNewChild(node , NULL , BAD_CAST "user" , NULL); if(user->loginType == LOGIN_TYPE_FETIONNO) xmlNewProp(cnode , BAD_CAST "sid" , BAD_CAST user->sId); else xmlNewProp(cnode , BAD_CAST "mobile-no" , BAD_CAST user->mobileno); cnode = xmlNewChild(node , NULL , BAD_CAST "client" , NULL); xmlNewProp(cnode , BAD_CAST "type" , BAD_CAST "PC"); xmlNewProp(cnode , BAD_CAST "version" , BAD_CAST PROTO_VERSION); xmlNewProp(cnode , BAD_CAST "platform" , BAD_CAST "W5.1"); cnode = xmlNewChild(node , NULL , BAD_CAST "servers" , NULL); xmlNewProp(cnode , BAD_CAST "version", BAD_CAST user->config->configServersVersion); cnode = xmlNewChild(node , NULL , BAD_CAST "parameters" , NULL); xmlNewProp(cnode , BAD_CAST "version", BAD_CAST user->config->configParametersVersion); cnode = xmlNewChild(node , NULL , BAD_CAST "hints" , NULL); xmlNewProp(cnode , BAD_CAST "version", BAD_CAST user->config->configHintsVersion); #if 0 cnode = xmlNewChild(node , NULL , BAD_CAST "service-no" , NULL); xmlNewProp(cnode , BAD_CAST "version" , BAD_CAST "0"); cnode = xmlNewChild(node , NULL , BAD_CAST "http-applications" , NULL); xmlNewProp(cnode , BAD_CAST "version" , BAD_CAST "0"); cnode = xmlNewChild(node , NULL , BAD_CAST "client-config" , NULL); xmlNewProp(cnode , BAD_CAST "version" , BAD_CAST "0"); cnode = xmlNewChild(node , NULL , BAD_CAST "services" , NULL); xmlNewProp(cnode , BAD_CAST "version" , BAD_CAST "0"); #endif xmlDocDumpMemory(doc , &buf , NULL); xmlFreeDoc(doc); return xml_convert(buf); } xmlNodePtr xml_goto_node(xmlNodePtr node , const char* name) { xmlNodePtr pos = node; xmlNodePtr tmp = NULL; while(pos != NULL) { if(strcmp(name , (char*)pos->name) == 0) return pos; tmp = pos->xmlChildrenNode; if(tmp != NULL && xmlStrcmp(tmp->name , BAD_CAST "text") != 0 &&tmp->type == XML_ELEMENT_NODE && (tmp = xml_goto_node(tmp , name)) != NULL ) return tmp; pos = pos->next; }; return NULL; } char* xml_convert(xmlChar* in) { char *res , *pos ; pos = strstr((char*)in , "?>") + 2; res = (char*)malloc(strlen(pos) + 1); memset(res , 0 , strlen(pos) + 1); memcpy(res , pos , strlen(pos)); xmlFree(in); return res; } char* fetion_config_get_city_name(const char* province , const char* city) { char path[] = RESOURCE_DIR"city.xml"; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseFile(path); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; while(node != NULL) { if(node->type != XML_ELEMENT_NODE) { node = node->next; continue; } res = xmlGetProp(node , BAD_CAST "id"); if(xmlStrcmp(res , BAD_CAST province) == 0) { node = node->xmlChildrenNode; while(node != NULL) { if(node->type != XML_ELEMENT_NODE) { node = node->next; continue; } xmlFree(res); res = xmlGetProp(node , BAD_CAST "id"); if(xmlStrcmp(res , BAD_CAST city) == 0) { xmlFree(res); return (char*)xmlNodeGetContent(node); break; } node = node->next; } break; } xmlFree(res); node = node->next; } return NULL; } char* fetion_config_get_province_name(const char* province) { char path[] = RESOURCE_DIR"province.xml"; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; doc = xmlReadFile(path , "UTF-8" , XML_PARSE_RECOVER); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; while(node != NULL) { res = xmlGetProp(node , BAD_CAST "id"); if(xmlStrcmp(res , BAD_CAST province) == 0) { return (char*)xmlNodeGetContent(node); xmlFree(res); break; } xmlFree(res); node = node->next; } xmlFreeDoc(doc); return NULL; } static void save_phrase(xmlNodePtr node, User *user) { char path[256]; char sql[4096]; sqlite3 *db; xmlChar *res, *res1; Config *config = user->config; node = xml_goto_node(node , "addbuddy-phrases"); if(!node) return; snprintf(path, sizeof(path), "%s/data.db",config->userPath); debug_info("Load user information"); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s",sqlite3_errmsg(db)); return; } snprintf(sql, sizeof(sql),"delete from phrases;"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ sprintf(sql, "create table phrases (id,content);"); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("create table phrase:%s", sqlite3_errmsg(db)); sqlite3_close(db); return; } } node = node->xmlChildrenNode; while(node){ res = xmlNodeGetContent(node); res1 = xmlGetProp(node , BAD_CAST "id"); snprintf(sql, sizeof(sql),"insert into phrases values (%s,'%s');", (char*)res1, (char*)res); xmlFree(res); xmlFree(res1); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_error("insert phrase:%s\n%s", sqlite3_errmsg(db), sql); } node = node->next; } } int fetion_user_list_remove(Config *config, const char *no) { char path[256]; char sql[4096]; sqlite3 *db; snprintf(path, sizeof(path), "%s/data.db", config->globalPath); if(sqlite3_open(path, &db)){ debug_error("open data.db:%s", sqlite3_errmsg(db)); return -1; } snprintf(sql, sizeof(sql), "delete from userlist where no='%s';", no); if(sqlite3_exec(db, sql, NULL, NULL, NULL)){ debug_info("remove user list:%s", sqlite3_errmsg(db)); sqlite3_close(db); return -1; } sqlite3_close(db); return 1; } void escape_sql(char *in) { while(*in){if(*in == '\'') *in = (char)255; in ++;} } void unescape_sql(char *inn) { char *in = inn; while(*in){if(*in == (char)255) *in = '\''; in ++;} } libofetion-2.2.2/fetion_buddylist.h0000644000175000017500000000556511700115314016053 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #ifndef FETION_BUDDYLIST_H #define FETION_BUDDYLIST_H extern int fetion_buddylist_create(User* user , const char* name); extern int fetion_buddylist_delete(User* user , int id); extern int fetion_buddylist_edit(User* user , int id , const char* name); /*private*/ extern char* generate_create_buddylist_body(const char* name); extern char* generate_delete_buddylist_body(int id); extern char* generate_edit_buddylist_body(int id , const char* name); extern int parse_create_buddylist_response(User* user , const char* sipmsg); extern void parse_delete_buddylist_response(User* user , const char* sipmsg); #endif libofetion-2.2.2/fetion_buddylist.c0000644000175000017500000001607011700115314016037 0ustar aronaron/*************************************************************************** * Copyright (C) 2010 by lwp * * levin108@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * * * OpenSSL linking exception * * -------------------------- * * If you modify this Program, or any covered work, by linking or * * combining it with the OpenSSL project's "OpenSSL" library (or a * * modified version of that library), containing parts covered by * * the terms of OpenSSL/SSLeay license, the licensors of this * * Program grant you additional permission to convey the resulting * * work. Corresponding Source for a non-source form of such a * * combination shall include the source code for the parts of the * * OpenSSL library used as well as that of the covered work. * ***************************************************************************/ #include int fetion_buddylist_create(User* user , const char* name) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; int ret; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_CREATEBUDDYLIST); fetion_sip_add_header(sip , eheader); body = generate_create_buddylist_body(name); res = fetion_sip_to_string(sip , body); free(body); tcp_connection_send(sip->tcp , res , strlen(res)); free(res) ; res = fetion_sip_get_response(sip); ret = fetion_sip_get_code(res); if(ret == 200) { ret = parse_create_buddylist_response(user , res); free(res); debug_info("Create buddy list success"); return ret; } else { free(res); debug_error("Create buddy list failed , errno :" , ret); return -1; } } int fetion_buddylist_delete(User* user , int id) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; int ret; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_DELETEBUDDYLIST); fetion_sip_add_header(sip , eheader); body = generate_delete_buddylist_body(id); res = fetion_sip_to_string(sip , body); free(body); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = fetion_sip_get_response(sip); ret = fetion_sip_get_code(res); free(res); if(ret == 200) { fetion_group_remove(user->groupList , id); debug_info("Delete buddy list success"); return 1; } else { debug_error("Delete buddy list failed , errno:%d" , ret); return -1; } } int fetion_buddylist_edit(User* user , int id , const char* name) { FetionSip* sip = user->sip; SipHeader* eheader; char *res , *body; int ret; fetion_sip_set_type(sip , SIP_SERVICE); eheader = fetion_sip_event_header_new(SIP_EVENT_SETBUDDYLISTINFO); fetion_sip_add_header(sip , eheader); body = generate_edit_buddylist_body(id , name); res = fetion_sip_to_string(sip , body); free(body); tcp_connection_send(sip->tcp , res , strlen(res)); free(res); res = fetion_sip_get_response(sip); ret = fetion_sip_get_code(res); free(res); if(ret == 200) { debug_info("Set buddy list name to %s success" , name); return 1; } else { debug_error("Set buddy list name to %s failed , errno:%d" , name , ret); return -1; } } char* generate_create_buddylist_body(const char* name) { char args[] = ""; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddy-lists" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddy-list" , NULL); xmlNewProp(node , BAD_CAST "name" , BAD_CAST name); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } char* generate_edit_buddylist_body(int id , const char* name) { char args[] = ""; char ids[128]; xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddy-lists" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddy-list" , NULL); xmlNewProp(node , BAD_CAST "name" , BAD_CAST name); memset(ids, 0, sizeof(ids)); snprintf(ids, sizeof(ids) - 1 , "%d" , id); xmlNewProp(node , BAD_CAST "id" , BAD_CAST ids); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } char* generate_delete_buddylist_body(int id) { char args[] = ""; char ida[4]; memset(ida, 0, sizeof(ida)); sprintf(ida , "%d" , id); xmlChar *res; xmlDocPtr doc; xmlNodePtr node; doc = xmlParseMemory(args , strlen(args)); node = xmlDocGetRootElement(doc); node = xmlNewChild(node , NULL , BAD_CAST "contacts" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddy-lists" , NULL); node = xmlNewChild(node , NULL , BAD_CAST "buddy-list" , NULL); xmlNewProp(node , BAD_CAST "id" , BAD_CAST ida); xmlDocDumpMemory(doc , &res , NULL); xmlFreeDoc(doc); return xml_convert(res); } int parse_create_buddylist_response(User* user , const char* sipmsg) { char *pos; Group* group; xmlChar* res; xmlDocPtr doc; xmlNodePtr node; int groupid; pos = strstr(sipmsg , "\r\n\r\n") + 4; doc = xmlParseMemory(pos , strlen(pos)); node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; res = xmlGetProp(node , BAD_CAST "version"); strcpy(user->contactVersion , (char*)res); xmlFree(res); node = node->xmlChildrenNode->xmlChildrenNode; group = fetion_group_new(); res = xmlGetProp(node , BAD_CAST "name"); strcpy(group->groupname , (char*)res); xmlFree(res); res = xmlGetProp(node , BAD_CAST "id"); group->groupid = atoi((char*)res); groupid = group->groupid; xmlFree(res); xmlFreeDoc(doc); fetion_group_list_append(user->groupList , group); return groupid; } libofetion-2.2.2/README0000644000175000017500000000221411700115314013177 0ustar aronaron README libofetion is an open source library which implements CHINA MOBILE's Fetion Protocol Version 4. CONTACT If you have problems, questions, ideas or suggestions, please contact me by email to levin108@gmail.com , or join the discussion in our mailling list: ofetion@googlegroups.com WEB SITE Visit ofetion code site: http://ofetion.googlecode.com for the latest news and downloads, also you can find useful information via the author's blog: http://basiccoder.com/openfetion/ INSTALLATION You need the following things pre-installed on your system: a) pkg-config, the package config system; b) cmake, the make system; and c) required libraries: openssl, libxml2, sqlite3 In Ubuntu system, if you want to install them, you can execute the following command: sudo apt-get install pkg-config cmake libssl-dev libxml2-dev libsqlite3-dev Then you can start to build from /path/to/your/libofetion, execute: $ mkdir build $ cd build/ $ cmake \ -DCMAKE_INSTALL_PREFIX=/path/to/dest \ -DCMAKE_BUILD_TYPE=release \ .. $ make $ sudo make install UNINSTALL ========= To uninstall, run # xargs rm < install_manifest.txt libofetion-2.2.2/License.OpenSSL0000644000175000017500000000104311700115314015105 0ustar aronaronOpenSSL linking exception -------------------------- If you modify this Program, or any covered work, by linking or combining it with the OpenSSL project's "OpenSSL" library (or a modified version of that library), containing parts covered by the terms of OpenSSL/SSLeay license, the licensors of this Program grant you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of the OpenSSL library used as well as that of the covered work. libofetion-2.2.2/LICENSE0000644000175000017500000004311011700115314013324 0ustar aronaron GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. libofetion-2.2.2/ChangeLog0000644000175000017500000001130111700115314014066 0ustar aronaron2010-12-26 YunQiang Su * 优化了 API * GTK 版增加了命令行功能,添加了一个纯命令行版 * 迁移到 cmake * 一些界面修改(新关于对话框,对话框不再相互覆盖) * 纯库函数单独版本发布 2010-11-27 YunQiang Su * 修复 aes 密码产生函数的安全问题。 2010-11-25 YunQiang Su * 在编译系统中去掉了 fx_share.c,避免 make check 失败。 2010-11-24 YunQiang Su * 修复了多个内存泄露的问题 * 修复了对话框使界面锁死的问题 * libofetion 不输出内部符号,加了版本号 * 去掉了 AC_CHECK_LIB(notify),避免 libofetion 依赖 libnotify * 将 nm 的依赖从 dbus-1 改为 dbus-glib-1,修复了禁用 notify 的时候编译失败 2010-10-24 levin * 修复了登录和运行时的崩溃问题 * 修复了群发短信时的崩溃问题 * 修复了添加好友时的崩溃问题 * 添加了数据本地化,实现了离线登录功能 * 添加了断线自动重连功能 * 添加了空闲时间自动离开功能 * 添加了关闭上线提示的功能 * 优化了登录过程,登录速度更快 * 更换了新版图标,更美观 2010-09-25 levin * 修复了旧版本登录过程中出现的各种崩溃的问题 * 修复了查看聊天记录崩溃的问题 * 修复了查看群功能使用中的崩溃问题 * 更换了图标及提示音,解决了资源文件的版权问题 * 去掉了之前的自绘主题 * 添加了离线不接收飞信信息的功能 * 添加了发送失败提示功能 * 添加了断线提示功能 * 添加了多种常用快捷键 * 对界面做了一些优化,使更美观 2010-08-14 gettextize * configure.ac (AC_CONFIG_FILES): Add po/Makefile.in. 2010-08-14 gettextize * Makefile.am (EXTRA_DIST): Add config.rpath. 2010-07-31 gettextize * Makefile.am (ACLOCAL_AMFLAGS): New variable. (EXTRA_DIST): Add m4/ChangeLog. * configure.ac (AC_CONFIG_FILES): Add po/Makefile.in. 2010-7-20 levin * 添加了联系人搜索功能 * 添加了聊天记录导出功能 * 修复了系统消息导致程序崩溃的bug * 可选择窗体不隐藏到托盘图标 * 增加了聊天窗口关闭快捷键CTRL+Q * 修复了表情提示框的bug * 更换了主题图标 * 优化了代码 2010-6-7 levin * 添加了上线提示和消息提示功能(需要libnotify支持) * 添加了不在线用户头像暗色显示功能 * 修复了头像加载时的内存泄漏,降低内存使用量 * 重写了部分重要的数据结构,加快了运行速度 * 修复了添加好友时的段错误 2010-5-24 levin * 添加了邮箱注册飞信号登录功能 * 添加了直接短信功能 * 完善了用户状态显示 * 完善了停机用户功能限制 * 优化了用户界面 * 修复了崩溃及自动退出的bug 2010-5-7 levin * 修复了因协议变动造成的登录时异常退出的bug * 添加了声音提示功能(需要gstreamer库的支持) * 添加了飞信表情功能 * 修复了用户心情短语过长时界面太宽的bug * 添加了识别用户设备功能,能识别出手机登录的用户 * 增加了窗体位置记忆功能 2010-4-15 levin * 修复了1.2中不能真正删除好友的bug * 设置用户可调整界面大小,解决了上网本界面太大不能正常使用的问题 * 修改了输入设置,解决了ibus,scim等输入发不能发送消息的问题 * 增加了HTTP代理功能 * 增加了聊天界面查看用户信息的功能 2010-4-6 levin * 修复了登录过程中出现断错误的bug * 修复了用户不能真正修改个人设置的bug * 添加了用户设置关闭按钮动作的功能 2010-3-30 levin * 将通信协议更改为飞信v4版本 * 修复了初次创建时需要手动创建.openfetion的bug * 修复了收到系统消息时的bug,屏蔽了系统消息 * 修复了将好友移动分组后好友变成未验证及分组用户数量不变的bug * 限制每次发送消息为180个字,修复了发送大信息时程序崩溃的bug * 修复了添加好友时默认名字的bug * 修改了登录认证算法,登录过程速度提高 * 修改了头像下载过程算法,头像加载速度提高 * 添加了查看任意手机号或飞信号相关信息的功能 * 添加了陌生人聊天的功能 * 添加了短信群发的功能,不限制一次发送数据 * 添加了简单的个性化设置功能 2010-2-25 levin * 程序第一次发布 libofetion-2.2.2/COPYING0000644000175000017500000000271711700115314013362 0ustar aronaron Copyright (C) 2010 levin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but is provided AS IS, WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and NON-INFRINGEMENT. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. libofetion-2.2.2/AUTHORS0000644000175000017500000000004711700115314013371 0ustar aronaronliwenpeng(levin),