IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

libofetion demo以及纯命令行飞信

basic coder 2012-03-18 23:40:59 累计浏览 2,297 次
本机暂存

之前一直有用户要求写一个libofetion的demo,再加上很多用户对于纯命令行版本飞信的强烈需求,于是我昨天简单地写了一个demo,把libofetion的API也做了一些修改,使它用起来更像是一个lib,不过对于第三方开发的话还是有很多很难理解的地方,因为最初并没有想把它当做一个lib来发布。到现在我对飞信的开发又要暂时先告一段落了,周末都在openfetion和娱乐中度过的,实验室项目和论文又要开始提上日程了,OK,先把code列出来,再做下简单地说明

/***************************************************************************
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
 
#include 
#include 
#include 
#include 
#include 
#include 
 
#define BUFLEN 1024
 
int   password_inputed = 0;
int   mobileno_inputed = 0;
int   tono_inputed = 0;
int   message_inputed = 0;
User *user;
pthread_t th;
 
static void usage(char *argv[]);
 
int fx_login(const char *mobileno, const char *password)
{
 Config           *config;
 FetionConnection *tcp;
 FetionSip        *sip;
 char             *res;
 char             *nonce;
 char             *key;
 char             *aeskey;
 char             *response;
 int               local_group_count;
 int               local_buddy_count;
 int               group_count;
 int               buddy_count;
 int               ret;
 
 /* construct a user object */
  user = fetion_user_new(mobileno, password);
 /* construct a config object */
 config = fetion_config_new();
 /* attach config to user */
 fetion_user_set_config(user, config);
 
 /* start ssi authencation,result string needs to be freed after use */
 res = ssi_auth_action(user);
 /* parse the ssi authencation result,if success,user's sipuri and userid
  * are stored in user object,orelse user->loginStatus was marked failed */
 parse_ssi_auth_response(res, user);
 free(res);
 
 /* whether needs to input a confirm code,or login failed
  * for other reason like password error */
 if(USER_AUTH_NEED_CONFIRM(user) || USER_AUTH_ERROR(user)) {
  debug_error("authencation failed");
  return 1;
 }
 
 /* initialize configuration for current user */
 if(fetion_user_init_config(user) == -1) {
  debug_error("initialize configuration");
  return 1;
 }
 
 if(fetion_config_download_configuration(user) == -1) {
  debug_error("download configuration");
  return 1;
 }
 
 /* set user's login state to be hidden */
 fetion_user_set_st(user, P_HIDDEN);
 
 /* load user information and contact list information from local host */
 fetion_user_load(user);
 fetion_contact_load(user, &local_group_count, &local_buddy_count);
 
 /* construct a tcp object and connect to the sipc proxy server */
 tcp = tcp_connection_new();
 if((ret = tcp_connection_connect(tcp, config->sipcProxyIP, config->sipcProxyPort)) == -1) {
  debug_error("connect sipc server %s:%d\n", config->sipcProxyIP, config->sipcProxyPort);
  return 1;
 }
 
 /* construct a sip object with the tcp object and attach it to user object */
 sip = fetion_sip_new(tcp, user->sId);
 fetion_user_set_sip(user, sip);
 
 /* register to sipc server */
 if(!(res = sipc_reg_action(user))) {
  debug_error("register to sipc server");
  return 1;
 }
 
 parse_sipc_reg_response(res, &nonce, &key);
 free(res);
 aeskey = generate_aes_key();
 
 response = generate_response(nonce, user->userId, user->password, key, aeskey);
 free(nonce);
 free(key);
 free(aeskey);
 
 /* sipc authencation,you can printf res to see what you received */
 if(!(res = sipc_aut_action(user, response))) {
  debug_error("sipc authencation");
  return 1;
 }
 
 if(parse_sipc_auth_response(res, user, &group_count, &buddy_count) == -1) {
  debug_error("authencation failed");
  return 1;
 }
 
 free(res);
 free(response);
 
 if(USER_AUTH_ERROR(user) || USER_AUTH_NEED_CONFIRM(user)) {
  debug_error("login failed");
  return 1;
 }
 
 /* save the user information and contact list information back to the local database */
 fetion_user_save(user);
 fetion_contact_save(user);
 
 /* these... fuck the fetion protocol */
 struct timeval tv;
 tv.tv_sec = 1;
 tv.tv_usec = 0;
 char buf[1024];
 if(setsockopt(user->sip->tcp->socketfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
  debug_error("settimeout");
  return 1;
 }
 tcp_connection_recv(user->sip->tcp, buf, sizeof(buf));
 
 return 0;
}
 
int send_message(const char *mobileno, const char *receiveno, const char *message)
{
 Conversation *conv;
 Contact      *contact;
 Contact      *contact_cur;
 Contact      *target_contact = NULL;
 int           daycount;
 int           monthcount;
 
 /* send this message to yourself */
 if(*receiveno == '\0' || strcmp(receiveno, mobileno) == 0) {
  /* construct a conversation object with the sipuri to set NULL
   * to send a message to yourself  */
  conv = fetion_conversation_new(user, NULL, NULL);
  if(fetion_conversation_send_sms_to_myself_with_reply(conv, message) == -1) {
   debug_error("send message \"%s\" to %s", message, user->mobileno);
   return 1;
  }
 }else{
  /* get the contact detail information by mobile number,
   * note that the result doesn't contain sipuri */
  contact = fetion_contact_get_contact_info_by_no(user, receiveno, MOBILE_NO);
  if(!contact) {
   debug_error("get contact information of %s", receiveno);
   return 1;
  }
 
  /* find the sipuri of the target user */
  foreach_contactlist(user->contactList, contact_cur) {
   if(strcmp(contact_cur->userId, contact->userId) == 0) {
    target_contact = contact_cur;
    break;
   }
  }
 
  if(!target_contact) {
   debug_error("sorry,maybe %s isn't in your contact list");
   return 1;
  }
 
  /* do what the function name says */
  conv = fetion_conversation_new(user, target_contact->sipuri, NULL);
  if(fetion_conversation_send_sms_to_phone_with_reply(conv, message, &daycount, &monthcount) == -1) {
   debug_error("send sms to %s", receiveno);
   return 1;
  }else{
   debug_info("successfully send sms to %s\nyou have sent %d messages today, %d messages this monthcount",
     receiveno, daycount, monthcount);
   return 0;
  }
 }
 return 0;
}
 
int main(int argc, char *argv[])
{
 int ch;
 char mobileno[BUFLEN];
 char password[BUFLEN];
 char receiveno[BUFLEN];
 char message[BUFLEN];
 
 memset(mobileno, 0, sizeof(mobileno));
 memset(password, 0, sizeof(password));
 memset(receiveno, 0, sizeof(receiveno));
 memset(message, 0, sizeof(message));
 
 while((ch = getopt(argc, argv, "f:p:t:d:")) != -1) {
  switch(ch) {
   case 'f':
    mobileno_inputed = 1;
    strncpy(mobileno, optarg, sizeof(mobileno) - 1); 
    break;
   case 'p':
    password_inputed = 1;
    strncpy(password, optarg, sizeof(password) - 1);
    break;
   case 't':
    tono_inputed = 1;
    strncpy(receiveno, optarg, sizeof(receiveno) - 1);
    break;
   case 'd':
    message_inputed = 1;
    strncpy(message, optarg, sizeof(message) - 1);
    break;
   default:
    break;
  }
 }
 
 if(!mobileno_inputed || !password_inputed || !message_inputed) {
  usage(argv);
  return 1;
 }
 
 if(fx_login(mobileno, password))
  return 1;
 
 if(send_message(mobileno, receiveno, message))
  return 1;
 
 fetion_user_free(user);
 return 0;
 
}
 
static void usage(char *argv[])
{
 fprintf(stderr, "Usage:%s -f mobileno -p password -t receive_mobileno -d message\n", argv[0]);
}

    首先需要libofetion的支持,因为用到了最新的API,所以需要从hg中clone最新版本编译安装后才可编译该程序:

hg clone https://ofetion.googlecode.com/hg/ ofetion

    编译方法如下:

gcc -o cli cli.c `pkg-config --cflags --libs ofetion`

    有一个地方需要说明,请大家找到/* these… fuck the fetion protocol */这个句注释,它下面的几句话的作用是这样的,飞信在用户完成身份验证之后订阅相关信息之前会推送过来一条信令:

BN 406472150 SIP-C/4.0
N: SyncUserInfoV4
I: 2
Q: 1 BN
L: 124
 

    用它来更新用户的积分等级之类的玩意,像这种浮云般的信令都被我直接忽略掉了,但在这种命令行模式纯粹为了发短信的情况下,不需要新建线程监听服务器推送过来的信息,但这条推送过来的信令就有可能影响其它信令的交互,而且更让人蛋疼的是并不是每次登录都会推送这条信令,有时候有,有时候没有,所以就加了在登录完成之后加了一个recv,设定了1s的超时,来处理这句信令,如果在网络情况不好的情况下,大家可以自己把超时时间设长一些,这样也就意味着在发送一条短信时在recv那里要停留几秒钟,否则就有可能导致信息发送失败。

    下载地址:fetion-demo

同分类推荐文章

  1. 科技爱好者周刊(第 401 期):如何赚到10亿美元 (2026-06-26 08:05:38)
  2. 如何做决策 - 从 Go 的一个 issue 说起 (2026-06-26 08:00:00)
  3. Seven Player:Windows上播放115网盘视频的增强工具 (2026-06-09 00:06:47)

查看更多 开发者 文章 →

建议继续学习

  1. POST与GET的区别及RESTful (累计阅读 7,862)
  2. Google短网址的API (累计阅读 6,522)
  3. C的那些事儿 (累计阅读 6,402)
  4. 理解JSON:3分钟课程 (累计阅读 5,791)
  5. 5分钟搞定你的Rest Server (累计阅读 5,742)
  6. SteveY对Amazon和Google平台的长篇大论 (累计阅读 5,056)
  7. 在wordpress中使用Google Reader “Send To” (累计阅读 5,027)
  8. ZooKeeper解惑 (累计阅读 4,736)
  9. 开源网站分析软件Piwik的数据库表结构 (累计阅读 4,715)
  10. 在sae中利用SaeFetchurl进行豆瓣的OAuth授权 (累计阅读 4,592)