Przeglądaj źródła

Submit chat client

heavyrain lee 6 lat temu
commit
d28e11fd0c
100 zmienionych plików z 8896 dodań i 0 usunięć
  1. 5 0
      .gitignore
  2. 21 0
      LICENSE
  3. 18 0
      README.md
  4. 8 0
      wfclient/.gitignore
  5. 878 0
      wfclient/WFChatClient.xcodeproj/project.pbxproj
  6. 7 0
      wfclient/WFChatClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  7. 80 0
      wfclient/WFChatClient.xcodeproj/xcshareddata/xcschemes/WFChatClient.xcscheme
  8. 76 0
      wfclient/WFChatClient/Client/Common.h
  9. 995 0
      wfclient/WFChatClient/Client/WFCCIMService.h
  10. 1460 0
      wfclient/WFChatClient/Client/WFCCIMService.mm
  11. 215 0
      wfclient/WFChatClient/Client/WFCCNetworkService.h
  12. 700 0
      wfclient/WFChatClient/Client/WFCCNetworkService.mm
  13. 29 0
      wfclient/WFChatClient/Client/WFCCNetworkStatus.h
  14. 102 0
      wfclient/WFChatClient/Client/WFCCNetworkStatus.m
  15. 51 0
      wfclient/WFChatClient/Client/app_callback.h
  16. 126 0
      wfclient/WFChatClient/Client/app_callback.mm
  17. 24 0
      wfclient/WFChatClient/Info.plist
  18. 26 0
      wfclient/WFChatClient/Messages/WFCCAddGroupeMemberNotificationContent.h
  19. 92 0
      wfclient/WFChatClient/Messages/WFCCAddGroupeMemberNotificationContent.m
  20. 52 0
      wfclient/WFChatClient/Messages/WFCCCallStartMessageContent.h
  21. 74 0
      wfclient/WFChatClient/Messages/WFCCCallStartMessageContent.m
  22. 26 0
      wfclient/WFChatClient/Messages/WFCCChangeGroupNameNotificationContent.h
  23. 84 0
      wfclient/WFChatClient/Messages/WFCCChangeGroupNameNotificationContent.m
  24. 21 0
      wfclient/WFChatClient/Messages/WFCCChangeGroupPortraitNotificationContent.h
  25. 75 0
      wfclient/WFChatClient/Messages/WFCCChangeGroupPortraitNotificationContent.m
  26. 26 0
      wfclient/WFChatClient/Messages/WFCCCreateGroupNotificationContent.h
  27. 75 0
      wfclient/WFChatClient/Messages/WFCCCreateGroupNotificationContent.m
  28. 21 0
      wfclient/WFChatClient/Messages/WFCCDismissGroupNotificationContent.h
  29. 76 0
      wfclient/WFChatClient/Messages/WFCCDismissGroupNotificationContent.m
  30. 33 0
      wfclient/WFChatClient/Messages/WFCCFileMessageContent.h
  31. 64 0
      wfclient/WFChatClient/Messages/WFCCFileMessageContent.m
  32. 30 0
      wfclient/WFChatClient/Messages/WFCCImageMessageContent.h
  33. 79 0
      wfclient/WFChatClient/Messages/WFCCImageMessageContent.m
  34. 26 0
      wfclient/WFChatClient/Messages/WFCCKickoffGroupMemberNotificaionContent.h
  35. 93 0
      wfclient/WFChatClient/Messages/WFCCKickoffGroupMemberNotificaionContent.m
  36. 45 0
      wfclient/WFChatClient/Messages/WFCCLocationMessageContent.h
  37. 70 0
      wfclient/WFChatClient/Messages/WFCCLocationMessageContent.m
  38. 25 0
      wfclient/WFChatClient/Messages/WFCCMediaMessageContent.h
  39. 19 0
      wfclient/WFChatClient/Messages/WFCCMediaMessageContent.m
  40. 95 0
      wfclient/WFChatClient/Messages/WFCCMessage.h
  41. 15 0
      wfclient/WFChatClient/Messages/WFCCMessage.m
  42. 164 0
      wfclient/WFChatClient/Messages/WFCCMessageContent.h
  43. 37 0
      wfclient/WFChatClient/Messages/WFCCMessageContent.m
  44. 26 0
      wfclient/WFChatClient/Messages/WFCCModifyGroupAliasNotificationContent.h
  45. 79 0
      wfclient/WFChatClient/Messages/WFCCModifyGroupAliasNotificationContent.m
  46. 30 0
      wfclient/WFChatClient/Messages/WFCCNotificationMessageContent.h
  47. 18 0
      wfclient/WFChatClient/Messages/WFCCNotificationMessageContent.m
  48. 20 0
      wfclient/WFChatClient/Messages/WFCCQuitGroupNotificationContent.h
  49. 75 0
      wfclient/WFChatClient/Messages/WFCCQuitGroupNotificationContent.m
  50. 25 0
      wfclient/WFChatClient/Messages/WFCCRecallMessageContent.h
  51. 59 0
      wfclient/WFChatClient/Messages/WFCCRecallMessageContent.m
  52. 44 0
      wfclient/WFChatClient/Messages/WFCCSoundMessageContent.h
  53. 94 0
      wfclient/WFChatClient/Messages/WFCCSoundMessageContent.m
  54. 26 0
      wfclient/WFChatClient/Messages/WFCCStickerMessageContent.h
  55. 77 0
      wfclient/WFChatClient/Messages/WFCCStickerMessageContent.m
  56. 39 0
      wfclient/WFChatClient/Messages/WFCCTextMessageContent.h
  57. 52 0
      wfclient/WFChatClient/Messages/WFCCTextMessageContent.m
  58. 20 0
      wfclient/WFChatClient/Messages/WFCCTipNotificationMessageContent.h
  59. 48 0
      wfclient/WFChatClient/Messages/WFCCTipNotificationMessageContent.m
  60. 26 0
      wfclient/WFChatClient/Messages/WFCCTransferGroupOwnerNotificationContent.h
  61. 95 0
      wfclient/WFChatClient/Messages/WFCCTransferGroupOwnerNotificationContent.m
  62. 46 0
      wfclient/WFChatClient/Messages/WFCCTypingMessageContent.h
  63. 48 0
      wfclient/WFChatClient/Messages/WFCCTypingMessageContent.m
  64. 21 0
      wfclient/WFChatClient/Messages/WFCCUnknownMessageContent.h
  65. 36 0
      wfclient/WFChatClient/Messages/WFCCUnknownMessageContent.m
  66. 30 0
      wfclient/WFChatClient/Messages/WFCCVideoMessageContent.h
  67. 62 0
      wfclient/WFChatClient/Messages/WFCCVideoMessageContent.m
  68. 24 0
      wfclient/WFChatClient/Model/WFCCChannelInfo.h
  69. 15 0
      wfclient/WFChatClient/Model/WFCCChannelInfo.m
  70. 23 0
      wfclient/WFChatClient/Model/WFCCChatroomInfo.h
  71. 15 0
      wfclient/WFChatClient/Model/WFCCChatroomInfo.m
  72. 14 0
      wfclient/WFChatClient/Model/WFCCChatroomMemberInfo.h
  73. 15 0
      wfclient/WFChatClient/Model/WFCCChatroomMemberInfo.m
  74. 57 0
      wfclient/WFChatClient/Model/WFCCConversation.h
  75. 28 0
      wfclient/WFChatClient/Model/WFCCConversation.m
  76. 56 0
      wfclient/WFChatClient/Model/WFCCConversationInfo.h
  77. 14 0
      wfclient/WFChatClient/Model/WFCCConversationInfo.m
  78. 37 0
      wfclient/WFChatClient/Model/WFCCConversationSearchInfo.h
  79. 13 0
      wfclient/WFChatClient/Model/WFCCConversationSearchInfo.m
  80. 46 0
      wfclient/WFChatClient/Model/WFCCFriendRequest.h
  81. 13 0
      wfclient/WFChatClient/Model/WFCCFriendRequest.m
  82. 64 0
      wfclient/WFChatClient/Model/WFCCGroupInfo.h
  83. 13 0
      wfclient/WFChatClient/Model/WFCCGroupInfo.m
  84. 49 0
      wfclient/WFChatClient/Model/WFCCGroupMember.h
  85. 13 0
      wfclient/WFChatClient/Model/WFCCGroupMember.m
  86. 37 0
      wfclient/WFChatClient/Model/WFCCGroupSearchInfo.h
  87. 13 0
      wfclient/WFChatClient/Model/WFCCGroupSearchInfo.m
  88. 20 0
      wfclient/WFChatClient/Model/WFCCUnreadCount.h
  89. 19 0
      wfclient/WFChatClient/Model/WFCCUnreadCount.m
  90. 78 0
      wfclient/WFChatClient/Model/WFCCUserInfo.h
  91. 27 0
      wfclient/WFChatClient/Model/WFCCUserInfo.m
  92. 76 0
      wfclient/WFChatClient/Proto/mars.framework/Headers/app/app.h
  93. 53 0
      wfclient/WFChatClient/Proto/mars.framework/Headers/app/app_logic.h
  94. 37 0
      wfclient/WFChatClient/Proto/mars.framework/Headers/baseevent/base_logic.h
  95. 36 0
      wfclient/WFChatClient/Proto/mars.framework/Headers/comm/ThreadOperationQueue.h
  96. 135 0
      wfclient/WFChatClient/Proto/mars.framework/Headers/comm/autobuffer.h
  97. 60 0
      wfclient/WFChatClient/Proto/mars.framework/Headers/comm/comm_data.h
  98. 55 0
      wfclient/WFChatClient/Proto/mars.framework/Headers/comm/has_member.h
  99. 356 0
      wfclient/WFChatClient/Proto/mars.framework/Headers/comm/http.h
  100. 51 0
      wfclient/WFChatClient/Proto/mars.framework/Headers/comm/local_ipstack.h

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+ios-chat.xcworkspace/xcuserdata
+wfuikit/bin
+wfuikit/bin_tmp
+wfuikit/Frameworks
+wfuikit/WFChatUIKit.xcodeproj/xcuserdata

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 wildfirechat
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 18 - 0
README.md

@@ -0,0 +1,18 @@
+## 说明
+本系统有4部分组成,服务器部分/iOS部分(ios-chat)/Android部分(android-chat)/协议栈部分(mars)。其中iso和android都依赖于协议栈部分。本工程为iOS部分
+
+
+### 编译
+
+下载之后要先编译一遍协议栈,编译方法参考协议栈文档。然后打开ios-chat.xcworkspace工程,对每个项目进行编译。
+
+### 工程说明
+
+工程中有3个项目,1个应用和2个库。chatclient库是IM的通讯能力,是最底层的库,chatuikit是IM的UI控件库,依赖于chatclient。chat是IM的demo,依赖于这两个库,chat需要正确配置服务器地址。
+
+### 配置
+
+在项目的Config.m文件中,修改IM服务器地址配置。如果为了体验,把```USE_EMBED_APP```改成```YES```, 然后```IM_SERVER_HOST```和```IM_SERVER_PORT```设置成火信的地址和端口。如果生产使用,请使用独立应用服务器。
+
+### 登陆
+根据服务器说明,使用注册脚本注册的用户

+ 8 - 0
wfclient/.gitignore

@@ -0,0 +1,8 @@
+WFChatClient_Products
+WFChatClient.xcodeproj/project.xcworkspace/xcuserdata
+DerivedData
+WFChatClient.xcodeproj/xcuserdata
+.DS_Store
+bin
+bin_tmp
+WFChatClient/Frameworks

+ 878 - 0
wfclient/WFChatClient.xcodeproj/project.pbxproj

@@ -0,0 +1,878 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 48;
+	objects = {
+
+/* Begin PBXAggregateTarget section */
+		2E66FBCD1FAFE9220025B5A9 /* Release */ = {
+			isa = PBXAggregateTarget;
+			buildConfigurationList = 2E66FBCE1FAFE9220025B5A9 /* Build configuration list for PBXAggregateTarget "Release" */;
+			buildPhases = (
+				2E66FBD11FAFE92B0025B5A9 /* ShellScript */,
+			);
+			dependencies = (
+			);
+			name = Release;
+			productName = Release;
+		};
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+		2E6B50A01FAE98E6006B6E31 /* WFCChatClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B509E1FAE98E6006B6E31 /* WFCChatClient.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B50B01FAE990D006B6E31 /* interf_dec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50A71FAE990D006B6E31 /* interf_dec.h */; };
+		2E6B50B11FAE990D006B6E31 /* interf_enc.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50A81FAE990D006B6E31 /* interf_enc.h */; };
+		2E6B50B21FAE990D006B6E31 /* libopencore-amrnb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E6B50A91FAE990D006B6E31 /* libopencore-amrnb.a */; };
+		2E6B50B31FAE990D006B6E31 /* wav_amr.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50AA1FAE990D006B6E31 /* wav_amr.h */; };
+		2E6B50B41FAE990D006B6E31 /* wav_amr.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50AB1FAE990D006B6E31 /* wav_amr.mm */; };
+		2E6B50B51FAE990D006B6E31 /* wavreader.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50AC1FAE990D006B6E31 /* wavreader.c */; };
+		2E6B50B61FAE990D006B6E31 /* wavreader.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50AD1FAE990D006B6E31 /* wavreader.h */; };
+		2E6B50B71FAE990D006B6E31 /* wavwriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50AE1FAE990D006B6E31 /* wavwriter.h */; };
+		2E6B50B81FAE990D006B6E31 /* wavwriter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50AF1FAE990D006B6E31 /* wavwriter.mm */; };
+		2E6B50C21FAE9B08006B6E31 /* app_callback.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50BA1FAE9B08006B6E31 /* app_callback.h */; };
+		2E6B50C31FAE9B08006B6E31 /* app_callback.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50BB1FAE9B08006B6E31 /* app_callback.mm */; };
+		2E6B50C41FAE9B08006B6E31 /* WFCCIMService.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50BC1FAE9B08006B6E31 /* WFCCIMService.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B50C51FAE9B08006B6E31 /* WFCCIMService.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50BD1FAE9B08006B6E31 /* WFCCIMService.mm */; };
+		2E6B50C61FAE9B08006B6E31 /* WFCCNetworkService.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50BE1FAE9B08006B6E31 /* WFCCNetworkService.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B50C71FAE9B08006B6E31 /* WFCCNetworkService.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50BF1FAE9B08006B6E31 /* WFCCNetworkService.mm */; };
+		2E6B50C81FAE9B08006B6E31 /* WFCCNetworkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50C01FAE9B08006B6E31 /* WFCCNetworkStatus.h */; };
+		2E6B50C91FAE9B08006B6E31 /* WFCCNetworkStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50C11FAE9B08006B6E31 /* WFCCNetworkStatus.m */; };
+		2E6B50F71FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50CB1FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B50F81FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50CC1FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.m */; };
+		2E6B50F91FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50CD1FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B50FA1FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50CE1FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.m */; };
+		2E6B50FB1FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50CF1FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B50FC1FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50D01FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.m */; };
+		2E6B50FD1FAE9B10006B6E31 /* WFCCImageMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50D11FAE9B10006B6E31 /* WFCCImageMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B50FE1FAE9B10006B6E31 /* WFCCImageMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50D21FAE9B10006B6E31 /* WFCCImageMessageContent.m */; };
+		2E6B50FF1FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50D31FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51001FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50D41FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.m */; };
+		2E6B51011FAE9B10006B6E31 /* WFCCMediaMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50D51FAE9B10006B6E31 /* WFCCMediaMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51021FAE9B10006B6E31 /* WFCCMediaMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50D61FAE9B10006B6E31 /* WFCCMediaMessageContent.m */; };
+		2E6B51031FAE9B10006B6E31 /* WFCCMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50D71FAE9B10006B6E31 /* WFCCMessage.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51041FAE9B10006B6E31 /* WFCCMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50D81FAE9B10006B6E31 /* WFCCMessage.m */; };
+		2E6B51051FAE9B10006B6E31 /* WFCCMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50D91FAE9B10006B6E31 /* WFCCMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51061FAE9B10006B6E31 /* WFCCMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50DA1FAE9B10006B6E31 /* WFCCMessageContent.m */; };
+		2E6B51071FAE9B10006B6E31 /* WFCCNotificationMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50DB1FAE9B10006B6E31 /* WFCCNotificationMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51081FAE9B10006B6E31 /* WFCCNotificationMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50DC1FAE9B10006B6E31 /* WFCCNotificationMessageContent.m */; };
+		2E6B51091FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50DD1FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B510A1FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50DE1FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.m */; };
+		2E6B510B1FAE9B10006B6E31 /* WFCCSoundMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50DF1FAE9B10006B6E31 /* WFCCSoundMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B510C1FAE9B10006B6E31 /* WFCCSoundMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50E01FAE9B10006B6E31 /* WFCCSoundMessageContent.m */; };
+		2E6B510D1FAE9B10006B6E31 /* WFCCTextMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50E11FAE9B10006B6E31 /* WFCCTextMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B510E1FAE9B10006B6E31 /* WFCCTextMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50E21FAE9B10006B6E31 /* WFCCTextMessageContent.m */; };
+		2E6B510F1FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50E31FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51101FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50E41FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.m */; };
+		2E6B51111FAE9B10006B6E31 /* WFCCUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50E61FAE9B10006B6E31 /* WFCCUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51121FAE9B10006B6E31 /* WFCCUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50E71FAE9B10006B6E31 /* WFCCUtilities.m */; };
+		2E6B51131FAE9B10006B6E31 /* WFCCConversation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50E91FAE9B10006B6E31 /* WFCCConversation.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51141FAE9B10006B6E31 /* WFCCConversation.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50EA1FAE9B10006B6E31 /* WFCCConversation.m */; };
+		2E6B51151FAE9B10006B6E31 /* WFCCConversationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50EB1FAE9B10006B6E31 /* WFCCConversationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51161FAE9B10006B6E31 /* WFCCConversationInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50EC1FAE9B10006B6E31 /* WFCCConversationInfo.m */; };
+		2E6B51171FAE9B10006B6E31 /* WFCCConversationSearchInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50ED1FAE9B10006B6E31 /* WFCCConversationSearchInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51181FAE9B10006B6E31 /* WFCCConversationSearchInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50EE1FAE9B10006B6E31 /* WFCCConversationSearchInfo.m */; };
+		2E6B51191FAE9B10006B6E31 /* WFCCFriendRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50EF1FAE9B10006B6E31 /* WFCCFriendRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B511A1FAE9B10006B6E31 /* WFCCFriendRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50F01FAE9B10006B6E31 /* WFCCFriendRequest.m */; };
+		2E6B511B1FAE9B10006B6E31 /* WFCCGroupInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50F11FAE9B10006B6E31 /* WFCCGroupInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B511C1FAE9B10006B6E31 /* WFCCGroupInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50F21FAE9B10006B6E31 /* WFCCGroupInfo.m */; };
+		2E6B511D1FAE9B10006B6E31 /* WFCCGroupMember.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50F31FAE9B10006B6E31 /* WFCCGroupMember.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B511E1FAE9B10006B6E31 /* WFCCGroupMember.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50F41FAE9B10006B6E31 /* WFCCGroupMember.m */; };
+		2E6B511F1FAE9B10006B6E31 /* WFCCUserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E6B50F51FAE9B10006B6E31 /* WFCCUserInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2E6B51201FAE9B10006B6E31 /* WFCCUserInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E6B50F61FAE9B10006B6E31 /* WFCCUserInfo.m */; };
+		2EE6A4881FB290FC007953BC /* Common.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EE6A4871FB290FC007953BC /* Common.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2F1A931A21B250F5006625CD /* WFCCTypingMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F1A931821B250F5006625CD /* WFCCTypingMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2F1A931B21B250F5006625CD /* WFCCTypingMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F1A931921B250F5006625CD /* WFCCTypingMessageContent.m */; };
+		2F3223D52144C5FB0016A2C4 /* WFCCVideoMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F3223D32144C5FB0016A2C4 /* WFCCVideoMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2F3223D62144C5FB0016A2C4 /* WFCCVideoMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F3223D42144C5FB0016A2C4 /* WFCCVideoMessageContent.m */; };
+		2F48C9C5214D16250092B167 /* WFCCRecallMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F48C9C3214D16240092B167 /* WFCCRecallMessageContent.m */; };
+		2F48C9C6214D16250092B167 /* WFCCRecallMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F48C9C4214D16240092B167 /* WFCCRecallMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2F8742DB219C4FED00F65EBA /* WFCCChatroomInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F8742D5219C4FEC00F65EBA /* WFCCChatroomInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2F8742DC219C4FED00F65EBA /* WFCCUnreadCount.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F8742D6219C4FEC00F65EBA /* WFCCUnreadCount.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2F8742DD219C4FED00F65EBA /* WFCCUnreadCount.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F8742D7219C4FED00F65EBA /* WFCCUnreadCount.m */; };
+		2F8742DE219C4FED00F65EBA /* WFCCChatroomMemberInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F8742D8219C4FED00F65EBA /* WFCCChatroomMemberInfo.m */; };
+		2F8742DF219C4FED00F65EBA /* WFCCChatroomMemberInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F8742D9219C4FED00F65EBA /* WFCCChatroomMemberInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2F8742E0219C4FED00F65EBA /* WFCCChatroomInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F8742DA219C4FED00F65EBA /* WFCCChatroomInfo.m */; };
+		2FEF332621BE93980087B6C2 /* WFCCChannelInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FEF332421BE93980087B6C2 /* WFCCChannelInfo.m */; };
+		2FEF332721BE93980087B6C2 /* WFCCChannelInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FEF332521BE93980087B6C2 /* WFCCChannelInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		6E6C69A720B959F100006628 /* WFCCGroupSearchInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E6C69A520B959F100006628 /* WFCCGroupSearchInfo.m */; };
+		6E6C69A820B959F100006628 /* WFCCGroupSearchInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E6C69A620B959F100006628 /* WFCCGroupSearchInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		6ECFB2C720A84C88001F91CB /* WFCCFileMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 6ECFB2C520A84C88001F91CB /* WFCCFileMessageContent.m */; };
+		6ECFB2C820A84C88001F91CB /* WFCCFileMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ECFB2C620A84C88001F91CB /* WFCCFileMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		6ED103DB20AE5C9700D4A59C /* WFCCTipNotificationMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 6ED103D920AE5C9600D4A59C /* WFCCTipNotificationMessageContent.m */; };
+		6ED103DC20AE5C9700D4A59C /* WFCCTipNotificationMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ED103DA20AE5C9600D4A59C /* WFCCTipNotificationMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		901E270E21F1543D00A163CB /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 901E270D21F1543D00A163CB /* CoreTelephony.framework */; };
+		901E271021F1545000A163CB /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 901E270F21F1545000A163CB /* libresolv.tbd */; };
+		901E271221F1545900A163CB /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 901E271121F1545900A163CB /* libc++.tbd */; };
+		901E271421F1546100A163CB /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 901E271321F1546100A163CB /* libz.tbd */; };
+		901E271521F1546A00A163CB /* mars.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 901E270A21F153D800A163CB /* mars.framework */; };
+		903EBB8B21357DDF00312C16 /* WFCCStickerMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 903EBB8921357DDF00312C16 /* WFCCStickerMessageContent.m */; };
+		903EBB8C21357DDF00312C16 /* WFCCStickerMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 903EBB8A21357DDF00312C16 /* WFCCStickerMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		90B044461FEFD6BA00AFE79B /* WFCCUnknownMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 90B044441FEFD6BA00AFE79B /* WFCCUnknownMessageContent.m */; };
+		90B044471FEFD6BA00AFE79B /* WFCCUnknownMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 90B044451FEFD6BA00AFE79B /* WFCCUnknownMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		90B0444A1FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 90B044481FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		90B0444B1FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 90B044491FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.m */; };
+		90B0444E1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 90B0444C1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		90B0444F1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 90B0444D1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.m */; };
+		90D1F596208D65B500C2A9CA /* WFCCCallStartMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 90D1F594208D65B500C2A9CA /* WFCCCallStartMessageContent.m */; };
+		90D1F597208D65B500C2A9CA /* WFCCCallStartMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D1F595208D65B500C2A9CA /* WFCCCallStartMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		90E4D1DF1FFB0AE200B9A4E4 /* WFCCLocationMessageContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 90E4D1DD1FFB0AE200B9A4E4 /* WFCCLocationMessageContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		90E4D1E01FFB0AE200B9A4E4 /* WFCCLocationMessageContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 90E4D1DE1FFB0AE200B9A4E4 /* WFCCLocationMessageContent.m */; };
+		90F584991FFDB39800F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 90F584971FFDB39700F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		90F5849A1FFDB39800F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 90F584981FFDB39800F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		2E6B509B1FAE98E6006B6E31 /* WFChatClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WFChatClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		2E6B509E1FAE98E6006B6E31 /* WFCChatClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WFCChatClient.h; sourceTree = "<group>"; };
+		2E6B509F1FAE98E6006B6E31 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		2E6B50A71FAE990D006B6E31 /* interf_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interf_dec.h; sourceTree = "<group>"; };
+		2E6B50A81FAE990D006B6E31 /* interf_enc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interf_enc.h; sourceTree = "<group>"; };
+		2E6B50A91FAE990D006B6E31 /* libopencore-amrnb.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopencore-amrnb.a"; sourceTree = "<group>"; };
+		2E6B50AA1FAE990D006B6E31 /* wav_amr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wav_amr.h; sourceTree = "<group>"; };
+		2E6B50AB1FAE990D006B6E31 /* wav_amr.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = wav_amr.mm; sourceTree = "<group>"; };
+		2E6B50AC1FAE990D006B6E31 /* wavreader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wavreader.c; sourceTree = "<group>"; };
+		2E6B50AD1FAE990D006B6E31 /* wavreader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wavreader.h; sourceTree = "<group>"; };
+		2E6B50AE1FAE990D006B6E31 /* wavwriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wavwriter.h; sourceTree = "<group>"; };
+		2E6B50AF1FAE990D006B6E31 /* wavwriter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = wavwriter.mm; sourceTree = "<group>"; };
+		2E6B50BA1FAE9B08006B6E31 /* app_callback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = app_callback.h; sourceTree = "<group>"; };
+		2E6B50BB1FAE9B08006B6E31 /* app_callback.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = app_callback.mm; sourceTree = "<group>"; };
+		2E6B50BC1FAE9B08006B6E31 /* WFCCIMService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCIMService.h; sourceTree = "<group>"; };
+		2E6B50BD1FAE9B08006B6E31 /* WFCCIMService.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WFCCIMService.mm; sourceTree = "<group>"; };
+		2E6B50BE1FAE9B08006B6E31 /* WFCCNetworkService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCNetworkService.h; sourceTree = "<group>"; };
+		2E6B50BF1FAE9B08006B6E31 /* WFCCNetworkService.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WFCCNetworkService.mm; sourceTree = "<group>"; };
+		2E6B50C01FAE9B08006B6E31 /* WFCCNetworkStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCNetworkStatus.h; sourceTree = "<group>"; };
+		2E6B50C11FAE9B08006B6E31 /* WFCCNetworkStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCNetworkStatus.m; sourceTree = "<group>"; };
+		2E6B50CB1FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCAddGroupeMemberNotificationContent.h; sourceTree = "<group>"; };
+		2E6B50CC1FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCAddGroupeMemberNotificationContent.m; sourceTree = "<group>"; };
+		2E6B50CD1FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCCreateGroupNotificationContent.h; sourceTree = "<group>"; };
+		2E6B50CE1FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCCreateGroupNotificationContent.m; sourceTree = "<group>"; };
+		2E6B50CF1FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCDismissGroupNotificationContent.h; sourceTree = "<group>"; };
+		2E6B50D01FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCDismissGroupNotificationContent.m; sourceTree = "<group>"; };
+		2E6B50D11FAE9B10006B6E31 /* WFCCImageMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCImageMessageContent.h; sourceTree = "<group>"; };
+		2E6B50D21FAE9B10006B6E31 /* WFCCImageMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCImageMessageContent.m; sourceTree = "<group>"; };
+		2E6B50D31FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCKickoffGroupMemberNotificaionContent.h; sourceTree = "<group>"; };
+		2E6B50D41FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCKickoffGroupMemberNotificaionContent.m; sourceTree = "<group>"; };
+		2E6B50D51FAE9B10006B6E31 /* WFCCMediaMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCMediaMessageContent.h; sourceTree = "<group>"; };
+		2E6B50D61FAE9B10006B6E31 /* WFCCMediaMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCMediaMessageContent.m; sourceTree = "<group>"; };
+		2E6B50D71FAE9B10006B6E31 /* WFCCMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCMessage.h; sourceTree = "<group>"; };
+		2E6B50D81FAE9B10006B6E31 /* WFCCMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCMessage.m; sourceTree = "<group>"; };
+		2E6B50D91FAE9B10006B6E31 /* WFCCMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCMessageContent.h; sourceTree = "<group>"; };
+		2E6B50DA1FAE9B10006B6E31 /* WFCCMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCMessageContent.m; sourceTree = "<group>"; };
+		2E6B50DB1FAE9B10006B6E31 /* WFCCNotificationMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCNotificationMessageContent.h; sourceTree = "<group>"; };
+		2E6B50DC1FAE9B10006B6E31 /* WFCCNotificationMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCNotificationMessageContent.m; sourceTree = "<group>"; };
+		2E6B50DD1FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCQuitGroupNotificationContent.h; sourceTree = "<group>"; };
+		2E6B50DE1FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCQuitGroupNotificationContent.m; sourceTree = "<group>"; };
+		2E6B50DF1FAE9B10006B6E31 /* WFCCSoundMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCSoundMessageContent.h; sourceTree = "<group>"; };
+		2E6B50E01FAE9B10006B6E31 /* WFCCSoundMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCSoundMessageContent.m; sourceTree = "<group>"; };
+		2E6B50E11FAE9B10006B6E31 /* WFCCTextMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCTextMessageContent.h; sourceTree = "<group>"; };
+		2E6B50E21FAE9B10006B6E31 /* WFCCTextMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCTextMessageContent.m; sourceTree = "<group>"; };
+		2E6B50E31FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCTransferGroupOwnerNotificationContent.h; sourceTree = "<group>"; };
+		2E6B50E41FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCTransferGroupOwnerNotificationContent.m; sourceTree = "<group>"; };
+		2E6B50E61FAE9B10006B6E31 /* WFCCUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCUtilities.h; sourceTree = "<group>"; };
+		2E6B50E71FAE9B10006B6E31 /* WFCCUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCUtilities.m; sourceTree = "<group>"; };
+		2E6B50E91FAE9B10006B6E31 /* WFCCConversation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCConversation.h; sourceTree = "<group>"; };
+		2E6B50EA1FAE9B10006B6E31 /* WFCCConversation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCConversation.m; sourceTree = "<group>"; };
+		2E6B50EB1FAE9B10006B6E31 /* WFCCConversationInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCConversationInfo.h; sourceTree = "<group>"; };
+		2E6B50EC1FAE9B10006B6E31 /* WFCCConversationInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCConversationInfo.m; sourceTree = "<group>"; };
+		2E6B50ED1FAE9B10006B6E31 /* WFCCConversationSearchInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCConversationSearchInfo.h; sourceTree = "<group>"; };
+		2E6B50EE1FAE9B10006B6E31 /* WFCCConversationSearchInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCConversationSearchInfo.m; sourceTree = "<group>"; };
+		2E6B50EF1FAE9B10006B6E31 /* WFCCFriendRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCFriendRequest.h; sourceTree = "<group>"; };
+		2E6B50F01FAE9B10006B6E31 /* WFCCFriendRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCFriendRequest.m; sourceTree = "<group>"; };
+		2E6B50F11FAE9B10006B6E31 /* WFCCGroupInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCGroupInfo.h; sourceTree = "<group>"; };
+		2E6B50F21FAE9B10006B6E31 /* WFCCGroupInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCGroupInfo.m; sourceTree = "<group>"; };
+		2E6B50F31FAE9B10006B6E31 /* WFCCGroupMember.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCGroupMember.h; sourceTree = "<group>"; };
+		2E6B50F41FAE9B10006B6E31 /* WFCCGroupMember.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCGroupMember.m; sourceTree = "<group>"; };
+		2E6B50F51FAE9B10006B6E31 /* WFCCUserInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCUserInfo.h; sourceTree = "<group>"; };
+		2E6B50F61FAE9B10006B6E31 /* WFCCUserInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCUserInfo.m; sourceTree = "<group>"; };
+		2EE6A4871FB290FC007953BC /* Common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Common.h; sourceTree = "<group>"; };
+		2F1A931821B250F5006625CD /* WFCCTypingMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCTypingMessageContent.h; sourceTree = "<group>"; };
+		2F1A931921B250F5006625CD /* WFCCTypingMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCTypingMessageContent.m; sourceTree = "<group>"; };
+		2F3223D32144C5FB0016A2C4 /* WFCCVideoMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCVideoMessageContent.h; sourceTree = "<group>"; };
+		2F3223D42144C5FB0016A2C4 /* WFCCVideoMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCVideoMessageContent.m; sourceTree = "<group>"; };
+		2F48C9C3214D16240092B167 /* WFCCRecallMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCRecallMessageContent.m; sourceTree = "<group>"; };
+		2F48C9C4214D16240092B167 /* WFCCRecallMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCRecallMessageContent.h; sourceTree = "<group>"; };
+		2F8742D5219C4FEC00F65EBA /* WFCCChatroomInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCChatroomInfo.h; sourceTree = "<group>"; };
+		2F8742D6219C4FEC00F65EBA /* WFCCUnreadCount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCUnreadCount.h; sourceTree = "<group>"; };
+		2F8742D7219C4FED00F65EBA /* WFCCUnreadCount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCUnreadCount.m; sourceTree = "<group>"; };
+		2F8742D8219C4FED00F65EBA /* WFCCChatroomMemberInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCChatroomMemberInfo.m; sourceTree = "<group>"; };
+		2F8742D9219C4FED00F65EBA /* WFCCChatroomMemberInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCChatroomMemberInfo.h; sourceTree = "<group>"; };
+		2F8742DA219C4FED00F65EBA /* WFCCChatroomInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCChatroomInfo.m; sourceTree = "<group>"; };
+		2FEF332421BE93980087B6C2 /* WFCCChannelInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCChannelInfo.m; sourceTree = "<group>"; };
+		2FEF332521BE93980087B6C2 /* WFCCChannelInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCChannelInfo.h; sourceTree = "<group>"; };
+		6E6C69A520B959F100006628 /* WFCCGroupSearchInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCGroupSearchInfo.m; sourceTree = "<group>"; };
+		6E6C69A620B959F100006628 /* WFCCGroupSearchInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCGroupSearchInfo.h; sourceTree = "<group>"; };
+		6ECFB2C520A84C88001F91CB /* WFCCFileMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCFileMessageContent.m; sourceTree = "<group>"; };
+		6ECFB2C620A84C88001F91CB /* WFCCFileMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCFileMessageContent.h; sourceTree = "<group>"; };
+		6ED103D920AE5C9600D4A59C /* WFCCTipNotificationMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCTipNotificationMessageContent.m; sourceTree = "<group>"; };
+		6ED103DA20AE5C9600D4A59C /* WFCCTipNotificationMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCTipNotificationMessageContent.h; sourceTree = "<group>"; };
+		901E270A21F153D800A163CB /* mars.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = mars.framework; sourceTree = "<group>"; };
+		901E270D21F1543D00A163CB /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
+		901E270F21F1545000A163CB /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
+		901E271121F1545900A163CB /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
+		901E271321F1546100A163CB /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
+		903EBB8921357DDF00312C16 /* WFCCStickerMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCStickerMessageContent.m; sourceTree = "<group>"; };
+		903EBB8A21357DDF00312C16 /* WFCCStickerMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCStickerMessageContent.h; sourceTree = "<group>"; };
+		90B044441FEFD6BA00AFE79B /* WFCCUnknownMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCUnknownMessageContent.m; sourceTree = "<group>"; };
+		90B044451FEFD6BA00AFE79B /* WFCCUnknownMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCUnknownMessageContent.h; sourceTree = "<group>"; };
+		90B044481FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCChangeGroupNameNotificationContent.h; sourceTree = "<group>"; };
+		90B044491FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCChangeGroupNameNotificationContent.m; sourceTree = "<group>"; };
+		90B0444C1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCModifyGroupAliasNotificationContent.h; sourceTree = "<group>"; };
+		90B0444D1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCModifyGroupAliasNotificationContent.m; sourceTree = "<group>"; };
+		90D1F594208D65B500C2A9CA /* WFCCCallStartMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCCallStartMessageContent.m; sourceTree = "<group>"; };
+		90D1F595208D65B500C2A9CA /* WFCCCallStartMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCCallStartMessageContent.h; sourceTree = "<group>"; };
+		90E4D1DD1FFB0AE200B9A4E4 /* WFCCLocationMessageContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCLocationMessageContent.h; sourceTree = "<group>"; };
+		90E4D1DE1FFB0AE200B9A4E4 /* WFCCLocationMessageContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCLocationMessageContent.m; sourceTree = "<group>"; };
+		90F584971FFDB39700F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WFCCChangeGroupPortraitNotificationContent.h; sourceTree = "<group>"; };
+		90F584981FFDB39800F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WFCCChangeGroupPortraitNotificationContent.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		2E6B50971FAE98E6006B6E31 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				901E271521F1546A00A163CB /* mars.framework in Frameworks */,
+				901E271421F1546100A163CB /* libz.tbd in Frameworks */,
+				901E271221F1545900A163CB /* libc++.tbd in Frameworks */,
+				901E271021F1545000A163CB /* libresolv.tbd in Frameworks */,
+				901E270E21F1543D00A163CB /* CoreTelephony.framework in Frameworks */,
+				2E6B50B21FAE990D006B6E31 /* libopencore-amrnb.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		2E6B50911FAE98E5006B6E31 = {
+			isa = PBXGroup;
+			children = (
+				2E6B509D1FAE98E6006B6E31 /* WFChatClient */,
+				2E6B509C1FAE98E6006B6E31 /* Products */,
+				901E270C21F1543C00A163CB /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		2E6B509C1FAE98E6006B6E31 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				2E6B509B1FAE98E6006B6E31 /* WFChatClient.framework */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		2E6B509D1FAE98E6006B6E31 /* WFChatClient */ = {
+			isa = PBXGroup;
+			children = (
+				901E270921F153D800A163CB /* Proto */,
+				2E6B50CA1FAE9B10006B6E31 /* Messages */,
+				2E6B50E81FAE9B10006B6E31 /* Model */,
+				2E6B50E51FAE9B10006B6E31 /* Utility */,
+				2E6B50B91FAE9B08006B6E31 /* Client */,
+				2E6B50A61FAE990D006B6E31 /* amr */,
+				2E6B509E1FAE98E6006B6E31 /* WFCChatClient.h */,
+				2E6B509F1FAE98E6006B6E31 /* Info.plist */,
+			);
+			path = WFChatClient;
+			sourceTree = "<group>";
+		};
+		2E6B50A61FAE990D006B6E31 /* amr */ = {
+			isa = PBXGroup;
+			children = (
+				2E6B50A71FAE990D006B6E31 /* interf_dec.h */,
+				2E6B50A81FAE990D006B6E31 /* interf_enc.h */,
+				2E6B50A91FAE990D006B6E31 /* libopencore-amrnb.a */,
+				2E6B50AA1FAE990D006B6E31 /* wav_amr.h */,
+				2E6B50AB1FAE990D006B6E31 /* wav_amr.mm */,
+				2E6B50AC1FAE990D006B6E31 /* wavreader.c */,
+				2E6B50AD1FAE990D006B6E31 /* wavreader.h */,
+				2E6B50AE1FAE990D006B6E31 /* wavwriter.h */,
+				2E6B50AF1FAE990D006B6E31 /* wavwriter.mm */,
+			);
+			path = amr;
+			sourceTree = "<group>";
+		};
+		2E6B50B91FAE9B08006B6E31 /* Client */ = {
+			isa = PBXGroup;
+			children = (
+				2E6B50BA1FAE9B08006B6E31 /* app_callback.h */,
+				2E6B50BB1FAE9B08006B6E31 /* app_callback.mm */,
+				2E6B50BC1FAE9B08006B6E31 /* WFCCIMService.h */,
+				2E6B50BD1FAE9B08006B6E31 /* WFCCIMService.mm */,
+				2E6B50BE1FAE9B08006B6E31 /* WFCCNetworkService.h */,
+				2E6B50BF1FAE9B08006B6E31 /* WFCCNetworkService.mm */,
+				2E6B50C01FAE9B08006B6E31 /* WFCCNetworkStatus.h */,
+				2E6B50C11FAE9B08006B6E31 /* WFCCNetworkStatus.m */,
+				2EE6A4871FB290FC007953BC /* Common.h */,
+			);
+			path = Client;
+			sourceTree = "<group>";
+		};
+		2E6B50CA1FAE9B10006B6E31 /* Messages */ = {
+			isa = PBXGroup;
+			children = (
+				90D1F595208D65B500C2A9CA /* WFCCCallStartMessageContent.h */,
+				90D1F594208D65B500C2A9CA /* WFCCCallStartMessageContent.m */,
+				2E6B50CB1FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.h */,
+				2E6B50CC1FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.m */,
+				2E6B50CD1FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.h */,
+				2E6B50CE1FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.m */,
+				2E6B50CF1FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.h */,
+				2E6B50D01FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.m */,
+				2E6B50D11FAE9B10006B6E31 /* WFCCImageMessageContent.h */,
+				2E6B50D21FAE9B10006B6E31 /* WFCCImageMessageContent.m */,
+				2F3223D32144C5FB0016A2C4 /* WFCCVideoMessageContent.h */,
+				2F3223D42144C5FB0016A2C4 /* WFCCVideoMessageContent.m */,
+				903EBB8A21357DDF00312C16 /* WFCCStickerMessageContent.h */,
+				903EBB8921357DDF00312C16 /* WFCCStickerMessageContent.m */,
+				2E6B50D31FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.h */,
+				2E6B50D41FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.m */,
+				2E6B50D51FAE9B10006B6E31 /* WFCCMediaMessageContent.h */,
+				2E6B50D61FAE9B10006B6E31 /* WFCCMediaMessageContent.m */,
+				2E6B50D71FAE9B10006B6E31 /* WFCCMessage.h */,
+				2E6B50D81FAE9B10006B6E31 /* WFCCMessage.m */,
+				2E6B50D91FAE9B10006B6E31 /* WFCCMessageContent.h */,
+				2E6B50DA1FAE9B10006B6E31 /* WFCCMessageContent.m */,
+				2E6B50DB1FAE9B10006B6E31 /* WFCCNotificationMessageContent.h */,
+				2E6B50DC1FAE9B10006B6E31 /* WFCCNotificationMessageContent.m */,
+				6ED103DA20AE5C9600D4A59C /* WFCCTipNotificationMessageContent.h */,
+				6ED103D920AE5C9600D4A59C /* WFCCTipNotificationMessageContent.m */,
+				2E6B50DD1FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.h */,
+				2E6B50DE1FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.m */,
+				2E6B50DF1FAE9B10006B6E31 /* WFCCSoundMessageContent.h */,
+				2E6B50E01FAE9B10006B6E31 /* WFCCSoundMessageContent.m */,
+				6ECFB2C620A84C88001F91CB /* WFCCFileMessageContent.h */,
+				6ECFB2C520A84C88001F91CB /* WFCCFileMessageContent.m */,
+				2E6B50E11FAE9B10006B6E31 /* WFCCTextMessageContent.h */,
+				2E6B50E21FAE9B10006B6E31 /* WFCCTextMessageContent.m */,
+				2F1A931821B250F5006625CD /* WFCCTypingMessageContent.h */,
+				2F1A931921B250F5006625CD /* WFCCTypingMessageContent.m */,
+				2F48C9C4214D16240092B167 /* WFCCRecallMessageContent.h */,
+				2F48C9C3214D16240092B167 /* WFCCRecallMessageContent.m */,
+				90E4D1DD1FFB0AE200B9A4E4 /* WFCCLocationMessageContent.h */,
+				90E4D1DE1FFB0AE200B9A4E4 /* WFCCLocationMessageContent.m */,
+				2E6B50E31FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.h */,
+				2E6B50E41FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.m */,
+				90B044451FEFD6BA00AFE79B /* WFCCUnknownMessageContent.h */,
+				90B044441FEFD6BA00AFE79B /* WFCCUnknownMessageContent.m */,
+				90B044481FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.h */,
+				90B044491FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.m */,
+				90F584971FFDB39700F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.h */,
+				90F584981FFDB39800F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.m */,
+				90B0444C1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.h */,
+				90B0444D1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.m */,
+			);
+			path = Messages;
+			sourceTree = "<group>";
+		};
+		2E6B50E51FAE9B10006B6E31 /* Utility */ = {
+			isa = PBXGroup;
+			children = (
+				2E6B50E61FAE9B10006B6E31 /* WFCCUtilities.h */,
+				2E6B50E71FAE9B10006B6E31 /* WFCCUtilities.m */,
+			);
+			path = Utility;
+			sourceTree = "<group>";
+		};
+		2E6B50E81FAE9B10006B6E31 /* Model */ = {
+			isa = PBXGroup;
+			children = (
+				2E6B50E91FAE9B10006B6E31 /* WFCCConversation.h */,
+				2E6B50EA1FAE9B10006B6E31 /* WFCCConversation.m */,
+				2E6B50EB1FAE9B10006B6E31 /* WFCCConversationInfo.h */,
+				2E6B50EC1FAE9B10006B6E31 /* WFCCConversationInfo.m */,
+				2E6B50ED1FAE9B10006B6E31 /* WFCCConversationSearchInfo.h */,
+				2E6B50EE1FAE9B10006B6E31 /* WFCCConversationSearchInfo.m */,
+				6E6C69A620B959F100006628 /* WFCCGroupSearchInfo.h */,
+				6E6C69A520B959F100006628 /* WFCCGroupSearchInfo.m */,
+				2E6B50EF1FAE9B10006B6E31 /* WFCCFriendRequest.h */,
+				2E6B50F01FAE9B10006B6E31 /* WFCCFriendRequest.m */,
+				2E6B50F11FAE9B10006B6E31 /* WFCCGroupInfo.h */,
+				2E6B50F21FAE9B10006B6E31 /* WFCCGroupInfo.m */,
+				2E6B50F31FAE9B10006B6E31 /* WFCCGroupMember.h */,
+				2E6B50F41FAE9B10006B6E31 /* WFCCGroupMember.m */,
+				2E6B50F51FAE9B10006B6E31 /* WFCCUserInfo.h */,
+				2E6B50F61FAE9B10006B6E31 /* WFCCUserInfo.m */,
+				2F8742D5219C4FEC00F65EBA /* WFCCChatroomInfo.h */,
+				2F8742DA219C4FED00F65EBA /* WFCCChatroomInfo.m */,
+				2F8742D9219C4FED00F65EBA /* WFCCChatroomMemberInfo.h */,
+				2F8742D8219C4FED00F65EBA /* WFCCChatroomMemberInfo.m */,
+				2F8742D6219C4FEC00F65EBA /* WFCCUnreadCount.h */,
+				2F8742D7219C4FED00F65EBA /* WFCCUnreadCount.m */,
+				2FEF332521BE93980087B6C2 /* WFCCChannelInfo.h */,
+				2FEF332421BE93980087B6C2 /* WFCCChannelInfo.m */,
+			);
+			path = Model;
+			sourceTree = "<group>";
+		};
+		901E270921F153D800A163CB /* Proto */ = {
+			isa = PBXGroup;
+			children = (
+				901E270A21F153D800A163CB /* mars.framework */,
+			);
+			path = Proto;
+			sourceTree = "<group>";
+		};
+		901E270C21F1543C00A163CB /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				901E271321F1546100A163CB /* libz.tbd */,
+				901E271121F1545900A163CB /* libc++.tbd */,
+				901E270F21F1545000A163CB /* libresolv.tbd */,
+				901E270D21F1543D00A163CB /* CoreTelephony.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		2E6B50981FAE98E6006B6E31 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				90D1F597208D65B500C2A9CA /* WFCCCallStartMessageContent.h in Headers */,
+				2E6B51131FAE9B10006B6E31 /* WFCCConversation.h in Headers */,
+				903EBB8C21357DDF00312C16 /* WFCCStickerMessageContent.h in Headers */,
+				2F1A931A21B250F5006625CD /* WFCCTypingMessageContent.h in Headers */,
+				2F3223D52144C5FB0016A2C4 /* WFCCVideoMessageContent.h in Headers */,
+				2E6B51151FAE9B10006B6E31 /* WFCCConversationInfo.h in Headers */,
+				2E6B50F71FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.h in Headers */,
+				2E6B50F91FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.h in Headers */,
+				6ED103DC20AE5C9700D4A59C /* WFCCTipNotificationMessageContent.h in Headers */,
+				2E6B50FD1FAE9B10006B6E31 /* WFCCImageMessageContent.h in Headers */,
+				2F8742DC219C4FED00F65EBA /* WFCCUnreadCount.h in Headers */,
+				2F8742DF219C4FED00F65EBA /* WFCCChatroomMemberInfo.h in Headers */,
+				2FEF332721BE93980087B6C2 /* WFCCChannelInfo.h in Headers */,
+				2F8742DB219C4FED00F65EBA /* WFCCChatroomInfo.h in Headers */,
+				2F48C9C6214D16250092B167 /* WFCCRecallMessageContent.h in Headers */,
+				6E6C69A820B959F100006628 /* WFCCGroupSearchInfo.h in Headers */,
+				2E6B50FB1FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.h in Headers */,
+				2E6B51191FAE9B10006B6E31 /* WFCCFriendRequest.h in Headers */,
+				6ECFB2C820A84C88001F91CB /* WFCCFileMessageContent.h in Headers */,
+				90E4D1DF1FFB0AE200B9A4E4 /* WFCCLocationMessageContent.h in Headers */,
+				2E6B511B1FAE9B10006B6E31 /* WFCCGroupInfo.h in Headers */,
+				90F584991FFDB39800F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.h in Headers */,
+				2E6B51031FAE9B10006B6E31 /* WFCCMessage.h in Headers */,
+				2E6B51011FAE9B10006B6E31 /* WFCCMediaMessageContent.h in Headers */,
+				2E6B51051FAE9B10006B6E31 /* WFCCMessageContent.h in Headers */,
+				2E6B51071FAE9B10006B6E31 /* WFCCNotificationMessageContent.h in Headers */,
+				90B0444A1FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.h in Headers */,
+				90B044471FEFD6BA00AFE79B /* WFCCUnknownMessageContent.h in Headers */,
+				90B0444E1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.h in Headers */,
+				2E6B50FF1FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.h in Headers */,
+				2E6B510B1FAE9B10006B6E31 /* WFCCSoundMessageContent.h in Headers */,
+				2EE6A4881FB290FC007953BC /* Common.h in Headers */,
+				2E6B510D1FAE9B10006B6E31 /* WFCCTextMessageContent.h in Headers */,
+				2E6B51091FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.h in Headers */,
+				2E6B511F1FAE9B10006B6E31 /* WFCCUserInfo.h in Headers */,
+				2E6B511D1FAE9B10006B6E31 /* WFCCGroupMember.h in Headers */,
+				2E6B510F1FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.h in Headers */,
+				2E6B51171FAE9B10006B6E31 /* WFCCConversationSearchInfo.h in Headers */,
+				2E6B51111FAE9B10006B6E31 /* WFCCUtilities.h in Headers */,
+				2E6B50C61FAE9B08006B6E31 /* WFCCNetworkService.h in Headers */,
+				2E6B50C41FAE9B08006B6E31 /* WFCCIMService.h in Headers */,
+				2E6B50B31FAE990D006B6E31 /* wav_amr.h in Headers */,
+				2E6B50C21FAE9B08006B6E31 /* app_callback.h in Headers */,
+				2E6B50B11FAE990D006B6E31 /* interf_enc.h in Headers */,
+				2E6B50C81FAE9B08006B6E31 /* WFCCNetworkStatus.h in Headers */,
+				2E6B50B71FAE990D006B6E31 /* wavwriter.h in Headers */,
+				2E6B50B61FAE990D006B6E31 /* wavreader.h in Headers */,
+				2E6B50A01FAE98E6006B6E31 /* WFCChatClient.h in Headers */,
+				2E6B50B01FAE990D006B6E31 /* interf_dec.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+		2E6B509A1FAE98E6006B6E31 /* WFChatClient */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 2E6B50A31FAE98E6006B6E31 /* Build configuration list for PBXNativeTarget "WFChatClient" */;
+			buildPhases = (
+				2E6B50961FAE98E6006B6E31 /* Sources */,
+				2E6B50971FAE98E6006B6E31 /* Frameworks */,
+				2E6B50981FAE98E6006B6E31 /* Headers */,
+				2E6B50991FAE98E6006B6E31 /* Resources */,
+				F89D8F2820538E36005A6CD1 /* ShellScript */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = WFChatClient;
+			productName = WFChatClient;
+			productReference = 2E6B509B1FAE98E6006B6E31 /* WFChatClient.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		2E6B50921FAE98E5006B6E31 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 1010;
+				ORGANIZATIONNAME = WildFireChat;
+				TargetAttributes = {
+					2E66FBCD1FAFE9220025B5A9 = {
+						CreatedOnToolsVersion = 9.1;
+						ProvisioningStyle = Automatic;
+					};
+					2E6B509A1FAE98E6006B6E31 = {
+						CreatedOnToolsVersion = 9.1;
+						ProvisioningStyle = Automatic;
+					};
+				};
+			};
+			buildConfigurationList = 2E6B50951FAE98E5006B6E31 /* Build configuration list for PBXProject "WFChatClient" */;
+			compatibilityVersion = "Xcode 8.0";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 2E6B50911FAE98E5006B6E31;
+			productRefGroup = 2E6B509C1FAE98E6006B6E31 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				2E6B509A1FAE98E6006B6E31 /* WFChatClient */,
+				2E66FBCD1FAFE9220025B5A9 /* Release */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		2E6B50991FAE98E6006B6E31 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		2E66FBD11FAFE92B0025B5A9 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "sh build.sh WFChatClient\n";
+		};
+		F89D8F2820538E36005A6CD1 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 12;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "bash xcodescript.sh\n";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		2E6B50961FAE98E6006B6E31 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2E6B50FE1FAE9B10006B6E31 /* WFCCImageMessageContent.m in Sources */,
+				2E6B51001FAE9B10006B6E31 /* WFCCKickoffGroupMemberNotificaionContent.m in Sources */,
+				2E6B50C91FAE9B08006B6E31 /* WFCCNetworkStatus.m in Sources */,
+				2E6B511A1FAE9B10006B6E31 /* WFCCFriendRequest.m in Sources */,
+				2E6B510C1FAE9B10006B6E31 /* WFCCSoundMessageContent.m in Sources */,
+				90B044461FEFD6BA00AFE79B /* WFCCUnknownMessageContent.m in Sources */,
+				903EBB8B21357DDF00312C16 /* WFCCStickerMessageContent.m in Sources */,
+				2E6B51141FAE9B10006B6E31 /* WFCCConversation.m in Sources */,
+				2FEF332621BE93980087B6C2 /* WFCCChannelInfo.m in Sources */,
+				2E6B51121FAE9B10006B6E31 /* WFCCUtilities.m in Sources */,
+				2E6B51041FAE9B10006B6E31 /* WFCCMessage.m in Sources */,
+				2E6B50FC1FAE9B10006B6E31 /* WFCCDismissGroupNotificationContent.m in Sources */,
+				2F3223D62144C5FB0016A2C4 /* WFCCVideoMessageContent.m in Sources */,
+				2E6B51181FAE9B10006B6E31 /* WFCCConversationSearchInfo.m in Sources */,
+				2E6B50C31FAE9B08006B6E31 /* app_callback.mm in Sources */,
+				6ECFB2C720A84C88001F91CB /* WFCCFileMessageContent.m in Sources */,
+				2F1A931B21B250F5006625CD /* WFCCTypingMessageContent.m in Sources */,
+				2E6B50B81FAE990D006B6E31 /* wavwriter.mm in Sources */,
+				2E6B50C71FAE9B08006B6E31 /* WFCCNetworkService.mm in Sources */,
+				2E6B510A1FAE9B10006B6E31 /* WFCCQuitGroupNotificationContent.m in Sources */,
+				2E6B51061FAE9B10006B6E31 /* WFCCMessageContent.m in Sources */,
+				2E6B50FA1FAE9B10006B6E31 /* WFCCCreateGroupNotificationContent.m in Sources */,
+				2E6B50F81FAE9B10006B6E31 /* WFCCAddGroupeMemberNotificationContent.m in Sources */,
+				2E6B511E1FAE9B10006B6E31 /* WFCCGroupMember.m in Sources */,
+				2F8742DE219C4FED00F65EBA /* WFCCChatroomMemberInfo.m in Sources */,
+				90D1F596208D65B500C2A9CA /* WFCCCallStartMessageContent.m in Sources */,
+				6ED103DB20AE5C9700D4A59C /* WFCCTipNotificationMessageContent.m in Sources */,
+				90E4D1E01FFB0AE200B9A4E4 /* WFCCLocationMessageContent.m in Sources */,
+				2E6B51101FAE9B10006B6E31 /* WFCCTransferGroupOwnerNotificationContent.m in Sources */,
+				2E6B50C51FAE9B08006B6E31 /* WFCCIMService.mm in Sources */,
+				2E6B51201FAE9B10006B6E31 /* WFCCUserInfo.m in Sources */,
+				2E6B511C1FAE9B10006B6E31 /* WFCCGroupInfo.m in Sources */,
+				2E6B51161FAE9B10006B6E31 /* WFCCConversationInfo.m in Sources */,
+				6E6C69A720B959F100006628 /* WFCCGroupSearchInfo.m in Sources */,
+				2E6B50B41FAE990D006B6E31 /* wav_amr.mm in Sources */,
+				2F48C9C5214D16250092B167 /* WFCCRecallMessageContent.m in Sources */,
+				2F8742E0219C4FED00F65EBA /* WFCCChatroomInfo.m in Sources */,
+				2E6B50B51FAE990D006B6E31 /* wavreader.c in Sources */,
+				2E6B510E1FAE9B10006B6E31 /* WFCCTextMessageContent.m in Sources */,
+				2E6B51081FAE9B10006B6E31 /* WFCCNotificationMessageContent.m in Sources */,
+				90F5849A1FFDB39800F7FFA8 /* WFCCChangeGroupPortraitNotificationContent.m in Sources */,
+				90B0444B1FEFDC1A00AFE79B /* WFCCChangeGroupNameNotificationContent.m in Sources */,
+				90B0444F1FEFDC4D00AFE79B /* WFCCModifyGroupAliasNotificationContent.m in Sources */,
+				2E6B51021FAE9B10006B6E31 /* WFCCMediaMessageContent.m in Sources */,
+				2F8742DD219C4FED00F65EBA /* WFCCUnreadCount.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		2E66FBCF1FAFE9220025B5A9 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				VALID_ARCHS = "arm64 armv7 x86_64";
+			};
+			name = Debug;
+		};
+		2E66FBD01FAFE9220025B5A9 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				VALID_ARCHS = "arm64 armv7 x86_64";
+			};
+			name = Release;
+		};
+		2E6B50A11FAE98E6006B6E31 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		2E6B50A21FAE98E6006B6E31 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				VALIDATE_PRODUCT = YES;
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+		2E6B50A41FAE98E6006B6E31 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				APPLICATION_EXTENSION_API_ONLY = NO;
+				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO;
+				CODE_SIGN_IDENTITY = "";
+				CODE_SIGN_STYLE = Automatic;
+				DEFINES_MODULE = NO;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/WFChatClient/Frameworks",
+					"$(PROJECT_DIR)/Frameworks",
+					"$(PROJECT_DIR)/WFChatClient/Proto",
+				);
+				INFOPLIST_FILE = WFChatClient/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/WFChatClient/amr",
+				);
+				MACH_O_TYPE = mh_dylib;
+				PRODUCT_BUNDLE_IDENTIFIER = cn.wildfirechat.WFChatClient;
+				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALID_ARCHS = "arm64 armv7 x86_64";
+				WARNING_CFLAGS = "";
+			};
+			name = Debug;
+		};
+		2E6B50A51FAE98E6006B6E31 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				APPLICATION_EXTENSION_API_ONLY = NO;
+				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO;
+				CODE_SIGN_IDENTITY = "";
+				CODE_SIGN_STYLE = Automatic;
+				DEFINES_MODULE = NO;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/WFChatClient/Frameworks",
+					"$(PROJECT_DIR)/Frameworks",
+					"$(PROJECT_DIR)/WFChatClient/Proto",
+				);
+				INFOPLIST_FILE = WFChatClient/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/WFChatClient/amr",
+				);
+				MACH_O_TYPE = mh_dylib;
+				PRODUCT_BUNDLE_IDENTIFIER = cn.wildfirechat.WFChatClient;
+				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALID_ARCHS = "arm64 armv7 x86_64";
+				WARNING_CFLAGS = "";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		2E66FBCE1FAFE9220025B5A9 /* Build configuration list for PBXAggregateTarget "Release" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2E66FBCF1FAFE9220025B5A9 /* Debug */,
+				2E66FBD01FAFE9220025B5A9 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		2E6B50951FAE98E5006B6E31 /* Build configuration list for PBXProject "WFChatClient" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2E6B50A11FAE98E6006B6E31 /* Debug */,
+				2E6B50A21FAE98E6006B6E31 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		2E6B50A31FAE98E6006B6E31 /* Build configuration list for PBXNativeTarget "WFChatClient" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2E6B50A41FAE98E6006B6E31 /* Debug */,
+				2E6B50A51FAE98E6006B6E31 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 2E6B50921FAE98E5006B6E31 /* Project object */;
+}

+ 7 - 0
wfclient/WFChatClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:WFChatClient.xcodeproj">
+   </FileRef>
+</Workspace>

+ 80 - 0
wfclient/WFChatClient.xcodeproj/xcshareddata/xcschemes/WFChatClient.xcscheme

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1010"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "2E6B509A1FAE98E6006B6E31"
+               BuildableName = "WFChatClient.framework"
+               BlueprintName = "WFChatClient"
+               ReferencedContainer = "container:WFChatClient.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "2E6B509A1FAE98E6006B6E31"
+            BuildableName = "WFChatClient.framework"
+            BlueprintName = "WFChatClient"
+            ReferencedContainer = "container:WFChatClient.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "2E6B509A1FAE98E6006B6E31"
+            BuildableName = "WFChatClient.framework"
+            BlueprintName = "WFChatClient"
+            ReferencedContainer = "container:WFChatClient.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 76 - 0
wfclient/WFChatClient/Client/Common.h

@@ -0,0 +1,76 @@
+//
+//  Common.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/11/8.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#ifndef Common_h
+#define Common_h
+
+
+/*
+ * 说明:1000以下为系统保留类型,自定义消息请使用1000以上数值。
+ * 系统消息类型中100以下为常用基本类型消息。100-199位群组消息类型。400-499为VoIP消息类型.
+ */
+//基本消息类型
+//未知类型的消息
+#define MESSAGE_CONTENT_TYPE_UNKNOWN 0
+//文本消息
+#define MESSAGE_CONTENT_TYPE_TEXT 1
+//语音消息
+#define MESSAGE_CONTENT_TYPE_SOUND 2
+//图片消息
+#define MESSAGE_CONTENT_TYPE_IMAGE 3
+//位置消息
+#define MESSAGE_CONTENT_TYPE_LOCATION 4
+//文件消息
+#define MESSAGE_CONTENT_TYPE_FILE 5
+//视频消息
+#define MESSAGE_CONTENT_TYPE_VIDEO 6
+//动态表情消息
+#define MESSAGE_CONTENT_TYPE_STICKER 7
+//图文消息
+#define MESSAGE_CONTENT_TYPE_IMAGETEXT 8
+
+
+//撤回消息
+#define MESSAGE_CONTENT_TYPE_RECALL 80
+
+//提醒消息
+#define MESSAGE_CONTENT_TYPE_TIP 90
+
+//正在输入消息
+#define MESSAGE_CONTENT_TYPE_TYPING 91
+
+//通知消息类型
+//创建群的通知消息
+#define MESSAGE_CONTENT_TYPE_CREATE_GROUP 104
+//加群的通知消息
+#define MESSAGE_CONTENT_TYPE_ADD_GROUP_MEMBER 105
+//踢出群成员的通知消息
+#define MESSAGE_CONTENT_TYPE_KICKOF_GROUP_MEMBER 106
+//退群的通知消息
+#define MESSAGE_CONTENT_TYPE_QUIT_GROUP 107
+//解散群的通知消息
+#define MESSAGE_CONTENT_TYPE_DISMISS_GROUP 108
+//转让群主的通知消息
+#define MESSAGE_CONTENT_TYPE_TRANSFER_GROUP_OWNER 109
+//修改群名称的通知消息
+#define MESSAGE_CONTENT_TYPE_CHANGE_GROUP_NAME 110
+//修改群昵称的通知消息
+#define MESSAGE_CONTENT_TYPE_MODIFY_GROUP_ALIAS 111
+//修改群头像的通知消息
+#define MESSAGE_CONTENT_TYPE_CHANGE_GROUP_PORTRAIT 112
+
+//VoIP开始消息
+#define VOIP_CONTENT_TYPE_START 400
+//VoIP结束消息
+#define VOIP_CONTENT_TYPE_END 402
+
+#define VOIP_CONTENT_TYPE_ACCEPT 401
+#define VOIP_CONTENT_TYPE_SIGNAL 403
+#define VOIP_CONTENT_TYPE_MODIFY 404
+#define VOIP_CONTENT_TYPE_ACCEPT_T 405
+#endif /* Common_h */

+ 995 - 0
wfclient/WFChatClient/Client/WFCCIMService.h

@@ -0,0 +1,995 @@
+//
+//  WFCCIMService.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/11/5.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "WFCCMessage.h"
+#import "WFCCGroupInfo.h"
+#import "WFCCConversationInfo.h"
+#import "WFCCUserInfo.h"
+#import "WFCCFriendRequest.h"
+#import "WFCCConversationSearchInfo.h"
+#import "WFCCGroupMember.h"
+#import "WFCCGroupSearchInfo.h"
+#import "WFCCChatroomInfo.h"
+#import "WFCCChatroomMemberInfo.h"
+#import "WFCCUnreadCount.h"
+#import "WFCCChannelInfo.h"
+
+#pragma mark - 频道通知定义
+//发送消息状态通知
+extern NSString *kSendingMessageStatusUpdated;
+extern NSString *kConnectionStatusChanged;
+extern NSString *kReceiveMessages;
+extern NSString *kRecallMessages;
+#pragma mark - 枚举值定义
+/**
+ 修改个人信息的内容
+
+ - Modify_DisplayName: 修改显示名
+ - Modify_Portrait: 修改头像
+ - Modify_Gender: 修改性别
+ - Modify_Mobile: 修改手机号
+ - Modify_Email: 修改邮箱
+ - Modify_Address: 修改地址
+ - Modify_Company: 修改公司信息
+ - Modify_Social: 修改社交信息
+ - Modify_Extra: 修改扩展信息
+ */
+typedef NS_ENUM(NSInteger, ModifyMyInfoType) {
+    Modify_DisplayName = 0,
+    Modify_Portrait = 1,
+    Modify_Gender = 2,
+    Modify_Mobile = 3,
+    Modify_Email = 4,
+    Modify_Address = 5,
+    Modify_Company = 6,
+    Modify_Social = 7,
+    Modify_Extra = 8
+};
+
+typedef NS_ENUM(NSInteger, ModifyGroupInfoType) {
+    Modify_Group_Name = 0,
+    Modify_Group_Portrait = 1,
+    Modify_Group_Extra = 2
+};
+
+
+typedef NS_ENUM(NSInteger, ModifyChannelInfoType) {
+    Modify_Channel_Name = 0,
+    Modify_Channel_Portrait = 1,
+    Modify_Channel_Desc = 2,
+    Modify_Channel_Extra = 3,
+    Modify_Channel_Secret = 4,
+    Modify_Channel_Callback = 5
+};
+
+/**
+ 个人设置Scope
+ 
+ @discussion 用户设置,1000以内被系统保留。应用不应该直接使用系统预制的范围。应用可以使用1000以上的值。
+ */
+typedef NS_ENUM(NSInteger, UserSettingScope) {
+    //不能直接使用,调用setConversation:silent:方法会使用到此值。
+    UserSettingScope_Conversation_Silent = 1,
+    //不能直接使用
+    UserSettingScope_Global_Silent = 2,
+    
+    //不能直接使用,调用setConversation:top:方法会使用到此值。
+    UserSettingScope_Conversation_Top = 3,
+    //不能直接使用
+    UserSettingScope_Hidden_Notification_Detail = 4,
+    //不能直接使用
+    UserSettingScope_Group_Hide_Nickname = 5,
+    //不能直接使用
+    UserSettingScope_Favourite_Group = 6,
+    
+    //不能直接使用,协议栈内会使用此值
+    UserSettingScope_Conversation_Sync = 7,
+    //不能直接使用,协议栈内会使用此值
+    UserSettingScope_My_Channel = 8,
+    //不能直接使用,协议栈内会使用此值
+    UserSettingScope_Listened_Channel = 9,
+    
+    
+    //自定义用户设置,请使用1000以上的key
+    UserSettingScope_Custom_Begin = 1000
+} ;
+
+#pragma mark - 用户源
+/*
+ * ChatClient内置支持用户信息托管,但对于很多应用来说都已经拥有自己的用户信息。此时可以实现用户源并设置到IMServer中去。这样ChatClient会从源中读取信息,从而ChatUIKit不用修改代码。
+ * 对于好友关系,由于页面简单。如果客户有自己的好友关系,建议客户自己修改相关UI。
+ * 对于群组建议使用我们的托管。
+ */
+@protocol WFCCUserSource <NSObject>
+- (WFCCUserInfo *)getUserInfo:(NSString *)userId
+                      refresh:(BOOL)refresh;
+
+- (void)searchUser:(NSString *)keyword
+           success:(void(^)(NSArray<WFCCUserInfo *> *machedUsers))successBlock
+             error:(void(^)(int errorCode))errorBlock;
+
+-(void)modifyMyInfo:(NSDictionary<NSNumber */*ModifyMyInfoType*/, NSString *> *)values
+            success:(void(^)(void))successBlock
+              error:(void(^)(int error_code))errorBlock;
+@end
+
+
+#pragma mark - IM服务
+
+/**
+ IM服务
+ */
+@interface WFCCIMService : NSObject
+
+/**
+ IM服务单例
+
+ @return IM服务单例
+ */
++ (WFCCIMService*)sharedWFCIMService;
+
+
+@property(nonatomic, weak)id<WFCCUserSource> userSource;
+
+#pragma mark - 会话相关
+/**
+ 获取会话信息
+ 
+ @param conversationTypes 会话类型
+ @param lines 默认传 @[@(0)]
+ @return 会话信息
+ */
+- (NSArray<WFCCConversationInfo *> *)getConversationInfos:(NSArray<NSNumber *> *)conversationTypes
+                                                    lines:(NSArray<NSNumber *> *)lines;
+
+/**
+ 获取会话信息
+ 
+ @param conversation 会话
+ @return 会话信息
+ */
+- (WFCCConversationInfo *)getConversationInfo:(WFCCConversation *)conversation;
+
+/**
+ 搜索会话
+ 
+ @param keyword 关键词
+ @param conversationTypes 会话类型
+ @param lines 默认传 @[@(0)]
+ @return 会话搜索结果信息
+ */
+- (NSArray<WFCCConversationSearchInfo *> *)searchConversation:(NSString *)keyword inConversation:(NSArray<NSNumber *> *)conversationTypes lines:(NSArray<NSNumber *> *)lines;
+
+/**
+ 删除会话
+ 
+ @param conversation 会话
+ @param clearMessage 是否删除会话中的消息
+ */
+- (void)removeConversation:(WFCCConversation *)conversation
+              clearMessage:(BOOL)clearMessage;
+
+/**
+ 设置或取消会话置顶
+ 
+ @param conversation 会话
+ @param top 是否置顶
+ */
+- (void)setConversation:(WFCCConversation *)conversation
+                    top:(BOOL)top
+                success:(void(^)(void))successBlock
+                  error:(void(^)(int error_code))errorBlock;
+
+/**
+ 设置会话免打扰
+ 
+ @param conversation 会话
+ @param silent 是否免打扰
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)setConversation:(WFCCConversation *)conversation
+                 silent:(BOOL)silent
+                success:(void(^)(void))successBlock
+                  error:(void(^)(int error_code))errorBlock;
+
+/**
+ 设置会话草稿
+ 
+ @param conversation 会话
+ @param draft 草稿
+ */
+- (void)setConversation:(WFCCConversation *)conversation
+                  draft:(NSString *)draft;
+
+#pragma mark - 未读数相关
+/**
+ 获取指定类型会话的未读数
+ 
+ @param conversationTypes 会话类型
+ @param lines 默认传 @[@(0)]
+ @return 未读数
+ */
+- (WFCCUnreadCount *)getUnreadCount:(NSArray<NSNumber *> *)conversationTypes
+                       lines:(NSArray<NSNumber *> *)lines;
+
+/**
+ 获取某个会话的未读数
+ 
+ @param conversation 会话
+ @return 未读数
+ */
+- (WFCCUnreadCount *)getUnreadCount:(WFCCConversation *)conversation;
+
+/**
+ 清空会话未读数
+ 
+ @param conversation 会话
+ */
+- (void)clearUnreadStatus:(WFCCConversation *)conversation;
+
+/**
+ 清空所有会话的未读数
+ */
+- (void)clearAllUnreadStatus;
+
+/**
+ 设置媒体消息已播放
+ */
+- (void)setMediaMessagePlayed:(long)messageId;
+#pragma mark - 消息相关
+/**
+ 获取消息
+ @discuss 获取从fromIndex起count条旧的消息。如果想要获取比fromIndex新的消息,count传负值。
+ 
+ @param conversation 会话
+ @param contentTypes 消息类型
+ @param fromIndex 起始index
+ @param count 总数
+ @return 消息实体
+ */
+- (NSArray<WFCCMessage *> *)getMessages:(WFCCConversation *)conversation
+                           contentTypes:(NSArray<NSNumber *> *)contentTypes
+                                   from:(NSUInteger)fromIndex
+                                  count:(NSInteger)count
+                               withUser:(NSString *)user;
+
+/**
+ 获取服务器消息
+ 
+ @param conversation 会话
+ @param beforeMessageUid 起始index
+ @param count 总数
+ @return 返回比messageUid对应消息更早的消息实体
+ */
+- (NSArray<WFCCMessage *> *)getRemoteMessages:(WFCCConversation *)conversation
+                                       before:(long long)beforeMessageUid
+                                        count:(NSUInteger)count;
+/**
+ 获取消息
+ 
+ @param messageId 消息ID
+ @return 消息实体
+ */
+- (WFCCMessage *)getMessage:(long)messageId;
+
+/**
+ 获取消息
+ 
+ @param messageUid 消息UID
+ @return 消息实体
+ */
+- (WFCCMessage *)getMessageByUid:(long long)messageUid;
+
+/**
+ 搜索消息
+ 
+ @param conversation 会话
+ @param keyword 关键词
+ @return 命中的消息
+ */
+- (NSArray<WFCCMessage *> *)searchMessage:(WFCCConversation *)conversation
+                                  keyword:(NSString *)keyword;
+
+/**
+ 发送消息
+
+ @param conversation 会话
+ @param content 消息内容
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ @return 消息实体
+ */
+- (WFCCMessage *)send:(WFCCConversation *)conversation
+              content:(WFCCMessageContent *)content
+              success:(void(^)(long long messageUid, long long timestamp))successBlock
+                error:(void(^)(int error_code))errorBlock;
+
+/**
+ 发送媒体消息
+
+ @param conversation 会话
+ @param content 消息内容
+ @param successBlock 成功的回调
+ @param progressBlock 上传进度的回调,注意仅当媒体内容大于300K才会有回调
+ @param errorBlock 失败的回调
+ @return 消息实体
+ */
+- (WFCCMessage *)sendMedia:(WFCCConversation *)conversation
+                   content:(WFCCMessageContent *)content
+                   success:(void(^)(long long messageUid, long long timestamp))successBlock
+                  progress:(void(^)(long uploaded, long total))progressBlock
+                     error:(void(^)(int error_code))errorBlock;
+
+/**
+ 发送消息
+ 
+ @param conversation 会话
+ @param content 消息内容
+ @param expireDuration 消息的有效期,0不限期,单位秒
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ @return 消息实体
+ */
+- (WFCCMessage *)send:(WFCCConversation *)conversation
+              content:(WFCCMessageContent *)content
+       expireDuration:(int)expireDuration
+              success:(void(^)(long long messageUid, long long timestamp))successBlock
+                error:(void(^)(int error_code))errorBlock;
+
+/**
+ 发送消息
+ 
+ @param conversation 会话
+ @param content 消息内容
+ @param toUser 在会话中只发给该用户,如果为空则发到会话中
+ @param expireDuration 消息的有效期,0不限期,单位秒
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ @return 消息实体
+ */
+- (WFCCMessage *)send:(WFCCConversation *)conversation
+              content:(WFCCMessageContent *)content
+               toUser:(NSString *)toUser
+       expireDuration:(int)expireDuration
+              success:(void(^)(long long messageUid, long long timestamp))successBlock
+                error:(void(^)(int error_code))errorBlock;
+
+/**
+ 发送媒体消息
+ 
+ @param conversation 会话
+ @param content 消息内容
+ @param expireDuration 消息的有效期,0不限期,单位秒
+ @param successBlock 成功的回调
+ @param progressBlock 上传进度的回调,注意仅当媒体内容大于300K才会有回调
+ @param errorBlock 失败的回调
+ @return 消息实体
+ */
+- (WFCCMessage *)sendMedia:(WFCCConversation *)conversation
+                   content:(WFCCMessageContent *)content
+            expireDuration:(int)expireDuration
+                   success:(void(^)(long long messageUid, long long timestamp))successBlock
+                  progress:(void(^)(long uploaded, long total))progressBlock
+                     error:(void(^)(int error_code))errorBlock;
+
+
+/**
+ 发送媒体消息
+ 
+ @param conversation 会话
+ @param content 消息内容
+ @param toUser 在会话中只发给该用户,如果为空则发到会话中
+ @param expireDuration 消息的有效期,0不限期,单位秒
+ @param successBlock 成功的回调
+ @param progressBlock 上传进度的回调,注意仅当媒体内容大于300K才会有回调
+ @param errorBlock 失败的回调
+ @return 消息实体
+ */
+- (WFCCMessage *)sendMedia:(WFCCConversation *)conversation
+                   content:(WFCCMessageContent *)content
+                    toUser:(NSString *)toUser
+            expireDuration:(int)expireDuration
+                   success:(void(^)(long long messageUid, long long timestamp))successBlock
+                  progress:(void(^)(long uploaded, long total))progressBlock
+                     error:(void(^)(int error_code))errorBlock;
+/**
+ 撤回消息
+ 
+ @param message 待撤回的消息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ @discuss 服务器不检查可撤回时间,应用逻辑来处理。
+ */
+- (void)recall:(WFCCMessage *)message
+       success:(void(^)(void))successBlock
+         error:(void(^)(int error_code))errorBlock;
+
+/**
+ 上传媒体(图片、语音、文件等)
+ 
+ @param mediaData 媒体信息
+ @param mediaType 媒体类型
+ @param successBlock 成功的回调
+ @param progressBlock 上传进度的回调,注意仅当媒体内容大于300K才会有回调
+ @param errorBlock 失败的回调
+ */
+- (void)uploadMedia:(NSData *)mediaData
+          mediaType:(WFCCMediaType)mediaType
+            success:(void(^)(NSString *remoteUrl))successBlock
+           progress:(void(^)(long uploaded, long total))progressBlock
+              error:(void(^)(int error_code))errorBlock;
+
+/**
+ 删除消息
+ 
+ @param messageId 消息ID
+ @return 是否删除成功
+ */
+- (BOOL)deleteMessage:(long)messageId;
+
+/**
+ 删除会话中的消息
+ 
+ @param conversation 会话
+ */
+- (void)clearMessages:(WFCCConversation *)conversation;
+
+/**
+ 注册自定义消息类型
+ 
+ @param contentClass 自定义消息
+ */
+- (void)registerMessageContent:(Class)contentClass;
+
+/**
+ 消息解码
+ 
+ @param payload 消息Payload
+ @return 消息内容
+ */
+- (WFCCMessageContent *)messageContentFromPayload:(WFCCMessagePayload *)payload;
+
+
+/**
+ 插入消息
+ 
+ @param conversation 会话
+ @param content 消息内容
+ @param status 消息状态,注意消息状态会影响消息方向
+ @param serverTime 时间,0为当前时间
+ @return 消息实体
+ */
+- (WFCCMessage *)insert:(WFCCConversation *)conversation
+                 sender:(NSString *)sender
+                content:(WFCCMessageContent *)content
+                 status:(WFCCMessageStatus)status
+                 notify:(BOOL)notify
+             serverTime:(long long)serverTime;
+
+/**
+ 更新消息内容
+ 
+ @param messageId 消息ID
+ @param content 消息内容
+ */
+- (void)updateMessage:(long)messageId
+              content:(WFCCMessageContent *)content;
+
+#pragma mark - 用户相关
+/**
+ 获取用户信息
+ 
+ @param userId 用户ID
+ @param refresh 是否强制从服务器更新,如果不刷新则从本地缓存中读取
+ @return 用户信息
+ */
+- (WFCCUserInfo *)getUserInfo:(NSString *)userId
+                      refresh:(BOOL)refresh;
+
+/**
+ 搜索用户
+ 
+ @param keyword 关键词
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)searchUser:(NSString *)keyword
+           success:(void(^)(NSArray<WFCCUserInfo *> *machedUsers))successBlock
+             error:(void(^)(int errorCode))errorBlock;
+
+#pragma mark - 好友相关
+/**
+ 查询用户和当前用户是否是好友关系
+
+ @param userId 用户ID
+ @return 是否是好友
+ */
+- (BOOL)isMyFriend:(NSString *)userId;
+
+/**
+ 获取当前用户的好友列表
+
+ @param refresh 是否强制从服务器更新,如果不刷新则从本地缓存中读取
+ @return 好友列表的用户ID
+ */
+- (NSArray<NSString *> *)getMyFriendList:(BOOL)refresh;
+
+
+/**
+ 搜索好友
+ @param keyword 关键词
+ @return 好友用户信息
+ */
+- (NSArray<WFCCUserInfo *> *)searchFriends:(NSString *)keyword;
+
+/**
+ 搜索群组
+ @param keyword 关键词
+ @return 群组搜索结果
+ */
+- (NSArray<WFCCGroupSearchInfo *> *)searchGroups:(NSString *)keyword;
+
+/**
+ 获取收到的好友请求
+
+ @return 好友请求
+ */
+- (NSArray<WFCCFriendRequest *> *)getIncommingFriendRequest;
+
+/**
+ 获取发出的好友请求
+
+ @return 好友请求
+ */
+- (NSArray<WFCCFriendRequest *> *)getOutgoingFriendRequest;
+
+/**
+ 从服务器更新好友请求
+ */
+- (void)loadFriendRequestFromRemote;
+
+/**
+ 获取未读的好友请求数
+
+ @return 未读的好友请求数
+ */
+- (int)getUnreadFriendRequestStatus;
+
+/**
+ 清除好友请求的未读数
+ */
+- (void)clearUnreadFriendRequestStatus;
+
+/**
+ 删除好友
+ 
+ @param userId 用户ID
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)deleteFriend:(NSString *)userId
+             success:(void(^)(void))successBlock
+               error:(void(^)(int error_code))errorBlock;
+
+/**
+ 发送好友请求
+
+ @param userId 用户ID
+ @param reason 请求说明
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)sendFriendRequest:(NSString *)userId
+                   reason:(NSString *)reason
+                  success:(void(^)(void))successBlock
+                    error:(void(^)(int error_code))errorBlock;
+
+/**
+ 处理好友请求
+
+ @param userId 用户ID
+ @param accpet 是否接受
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)handleFriendRequest:(NSString *)userId
+                     accept:(BOOL)accpet
+                  success:(void(^)(void))successBlock
+                    error:(void(^)(int error_code))errorBlock;
+
+/**
+ 查询用户是否被加入黑名单
+ 
+ @param userId 用户ID
+ @return 是否被加入黑名单
+ */
+- (BOOL)isBlackListed:(NSString *)userId;
+
+/**
+ 获取当前用户的黑名单列表
+ 
+ @param refresh 是否强制从服务器更新,如果不刷新则从本地缓存中读取
+ @return 黑名单列表的用户ID
+ */
+- (NSArray<NSString *> *)getBlackList:(BOOL)refresh;
+
+/**
+ 设置黑名单
+ 
+ @param userId 用户ID
+ @param isBlackListed YES 加入黑名单; NO 取消黑名单
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)setBlackList:(NSString *)userId
+       isBlackListed:(BOOL)isBlackListed
+             success:(void(^)(void))successBlock
+               error:(void(^)(int error_code))errorBlock;
+
+#pragma mark - 群相关
+/**
+ 获取群成员信息
+ 
+ @param groupId 群ID
+ @param forceUpdate 是否强制从服务器更新,如果不刷新则从本地缓存中读取
+ @return 群成员信息
+ */
+- (NSArray<WFCCGroupMember *> *)getGroupMembers:(NSString *)groupId
+                                    forceUpdate:(BOOL)forceUpdate;
+
+/**
+ 获取群信息
+ 
+ @param groupId 群ID
+ @param refresh 是否强制从服务器更新,如果不刷新则从本地缓存中读取
+ @return 群信息
+ */
+- (WFCCGroupInfo *)getGroupInfo:(NSString *)groupId
+                        refresh:(BOOL)refresh;
+
+/**
+ 获取群成员信息
+ 
+ @param groupId 群ID
+ @param memberId 群成员ID
+ @return 群成员信息
+ */
+- (WFCCGroupMember *)getGroupMember:(NSString *)groupId
+                           memberId:(NSString *)memberId;
+
+/**
+ 创建群
+
+ @param groupId 群ID
+ @param groupName 群名称
+ @param groupPortrait 群头像
+ @param groupMembers 群成员
+ @param notifyLines 默认传 @[@(0)]
+ @param notifyContent 通知消息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)createGroup:(NSString *)groupId
+               name:(NSString *)groupName
+           portrait:(NSString *)groupPortrait
+            members:(NSArray *)groupMembers
+        notifyLines:(NSArray<NSNumber *> *)notifyLines
+      notifyContent:(WFCCMessageContent *)notifyContent
+            success:(void(^)(NSString *groupId))successBlock
+              error:(void(^)(int error_code))errorBlock;
+
+/**
+ 添加群成员
+
+ @param members 成员的用户ID列表
+ @param groupId 群ID
+ @param notifyLines 默认传 @[@(0)]
+ @param notifyContent 通知消息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)addMembers:(NSArray *)members
+           toGroup:(NSString *)groupId
+       notifyLines:(NSArray<NSNumber *> *)notifyLines
+     notifyContent:(WFCCMessageContent *)notifyContent
+           success:(void(^)(void))successBlock
+             error:(void(^)(int error_code))errorBlock;
+
+/**
+ 踢出群成员
+
+ @param members 成员的用户ID列表
+ @param groupId 群ID
+ @param notifyLines 默认传 @[@(0)]
+ @param notifyContent 通知消息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)kickoffMembers:(NSArray *)members
+             fromGroup:(NSString *)groupId
+           notifyLines:(NSArray<NSNumber *> *)notifyLines
+         notifyContent:(WFCCMessageContent *)notifyContent
+               success:(void(^)(void))successBlock
+                 error:(void(^)(int error_code))errorBlock;
+
+/**
+ 退群
+
+ @param groupId 群ID
+ @param notifyLines 默认传 @[@(0)]
+ @param notifyContent 通知消息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)quitGroup:(NSString *)groupId
+      notifyLines:(NSArray<NSNumber *> *)notifyLines
+    notifyContent:(WFCCMessageContent *)notifyContent
+          success:(void(^)(void))successBlock
+            error:(void(^)(int error_code))errorBlock;
+
+/**
+ 解散群
+
+ @param groupId 群ID
+ @param notifyLines 默认传 @[@(0)]
+ @param notifyContent 通知消息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)dismissGroup:(NSString *)groupId
+         notifyLines:(NSArray<NSNumber *> *)notifyLines
+       notifyContent:(WFCCMessageContent *)notifyContent
+             success:(void(^)(void))successBlock
+               error:(void(^)(int error_code))errorBlock;
+
+/**
+ 修改群信息
+
+ @param groupId 群ID
+ @param type    要修改的群属性
+ @param newValue    要修改的群属性值
+ @param notifyLines 默认传 @[@(0)]
+ @param notifyContent 通知消息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)modifyGroupInfo:(NSString *)groupId
+                   type:(ModifyGroupInfoType)type
+               newValue:(NSString *)newValue
+            notifyLines:(NSArray<NSNumber *> *)notifyLines
+          notifyContent:(WFCCMessageContent *)notifyContent
+                success:(void(^)(void))successBlock
+                  error:(void(^)(int error_code))errorBlock;
+
+/**
+ 修改群昵称
+
+ @param groupId 群ID
+ @param newAlias 昵称
+ @param notifyLines 默认传 @[@(0)]
+ @param notifyContent 通知消息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)modifyGroupAlias:(NSString *)groupId
+                   alias:(NSString *)newAlias
+             notifyLines:(NSArray<NSNumber *> *)notifyLines
+           notifyContent:(WFCCMessageContent *)notifyContent
+                 success:(void(^)(void))successBlock
+                   error:(void(^)(int error_code))errorBlock;
+
+/**
+ 转移群主
+
+ @param groupId 群ID
+ @param newOwner 群主的用户ID
+ @param notifyLines 默认传 @[@(0)]
+ @param notifyContent 通知消息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)transferGroup:(NSString *)groupId
+                   to:(NSString *)newOwner
+          notifyLines:(NSArray<NSNumber *> *)notifyLines
+        notifyContent:(WFCCMessageContent *)notifyContent
+              success:(void(^)(void))successBlock
+                error:(void(^)(int error_code))errorBlock;
+
+/**
+ 获取当前用户收藏的群组
+ 
+ @return 当前用户收藏的群组ID
+ */
+- (NSArray<NSString *> *)getFavGroups;
+
+/**
+ 是否是当前用户收藏的群组
+ 
+ @return 是否是当前用户收藏的群组
+ */
+- (BOOL)isFavGroup:(NSString *)groupId;
+
+/**
+ 设置群组收藏状态
+ 
+ @param groupId 群组ID
+ @param fav 是否收藏
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)setFavGroup:(NSString *)groupId fav:(BOOL)fav success:(void(^)(void))successBlock error:(void(^)(int errorCode))errorBlock;
+#pragma mark - 个人设置相关
+/**
+ 获取个人设置
+
+ @param scope 设置项的scope
+ @param key 设置项的key
+ @return 设置值
+ */
+- (NSString *)getUserSetting:(UserSettingScope)scope
+                         key:(NSString *)key;
+
+/**
+ 获取个人一类设置
+ 
+ @param scope 设置项的scope
+ @return scope对应的所有设置值
+ */
+- (NSDictionary<NSString *, NSString *> *)getUserSettings:(UserSettingScope)scope;
+
+/**
+ 设置个人设置项
+
+ @param scope 设置项的scope
+ @param key 设置项的key
+ @param value 值
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)setUserSetting:(UserSettingScope)scope
+                   key:(NSString *)key
+                 value:(NSString *)value
+               success:(void(^)(void))successBlock
+                 error:(void(^)(int error_code))errorBlock;
+
+/**
+ 修改个人信息
+ 
+ @param values 信息
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ @discuss 性别属性是int类型,修改时需要转为字符串类型
+ */
+-(void)modifyMyInfo:(NSDictionary<NSNumber */*ModifyMyInfoType*/, NSString *> *)values
+            success:(void(^)(void))successBlock
+              error:(void(^)(int error_code))errorBlock;
+
+
+
+
+- (BOOL)isGlobalSlient;
+- (void)setGlobalSlient:(BOOL)slient
+                success:(void(^)(void))successBlock
+                  error:(void(^)(int error_code))errorBlock;
+- (BOOL)isHiddenNotificationDetail;
+- (void)setHiddenNotificationDetail:(BOOL)hidden
+                            success:(void(^)(void))successBlock
+                              error:(void(^)(int error_code))errorBlock;
+- (BOOL)isHiddenGroupMemberName:(NSString *)groupId;
+- (void)setHiddenGroupMemberName:(BOOL)hidden
+                           group:(NSString *)groupId
+                         success:(void(^)(void))successBlock
+                           error:(void(^)(int error_code))errorBlock;
+
+#pragma mark - 聊天室相关
+- (void)joinChatroom:(NSString *)chatroomId
+             success:(void(^)(void))successBlock
+               error:(void(^)(int error_code))errorBlock;
+
+- (void)quitChatroom:(NSString *)chatroomId
+             success:(void(^)(void))successBlock
+               error:(void(^)(int error_code))errorBlock;
+
+- (void)getChatroomInfo:(NSString *)chatroomId
+                upateDt:(long long)updateDt
+                success:(void(^)(WFCCChatroomInfo *chatroomInfo))successBlock
+                  error:(void(^)(int error_code))errorBlock;
+
+- (void)getChatroomMemberInfo:(NSString *)chatroomId
+                      maxCount:(int)maxCount
+                      success:(void(^)(WFCCChatroomMemberInfo *memberInfo))successBlock
+                        error:(void(^)(int error_code))errorBlock;
+
+#pragma mark - 频道相关
+- (void)createChannel:(NSString *)channelName
+             portrait:(NSString *)channelPortrait
+               status:(int)status
+                 desc:(NSString *)desc
+                extra:(NSString *)extra
+            success:(void(^)(WFCCChannelInfo *channelInfo))successBlock
+              error:(void(^)(int error_code))errorBlock;
+
+/**
+ 获取频道信息
+ 
+ @param channelId 频道ID
+ @param refresh 是否强制从服务器更新,如果不刷新则从本地缓存中读取
+ @return 群信息
+ */
+- (WFCCChannelInfo *)getChannelInfo:(NSString *)channelId
+                            refresh:(BOOL)refresh;
+
+/**
+ 修改频道信息
+ 
+ @param channelId 群ID
+ @param type    要修改的群属性
+ @param newValue    要修改的群属性值
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)modifyChannelInfo:(NSString *)channelId
+                   type:(ModifyChannelInfoType)type
+               newValue:(NSString *)newValue
+                success:(void(^)(void))successBlock
+                  error:(void(^)(int error_code))errorBlock;
+
+/**
+ 搜索频道
+ 
+ @param keyword 关键词
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)searchChannel:(NSString *)keyword success:(void(^)(NSArray<WFCCChannelInfo *> *machedChannels))successBlock error:(void(^)(int errorCode))errorBlock;
+
+/**
+ 是否收听频道
+ 
+ @param channelId 频道ID
+ @return YES,收听;NO,未收听
+ */
+- (BOOL)isListenedChannel:(NSString *)channelId;
+
+/**
+ 收听或者取消收听频道
+ 
+ @param channelId 频道ID
+ @param listen 是否收听
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)listenChannel:(NSString *)channelId listen:(BOOL)listen success:(void(^)(void))successBlock error:(void(^)(int errorCode))errorBlock;
+
+/**
+ 获取当前用户创建的频道
+ 
+ @return 当前用户创建的频道ID
+ */
+- (NSArray<NSString *> *)getMyChannels;
+
+/**
+ 获取当前用户收听的频道
+ 
+ @return 当前用户收听的频道ID
+ */
+- (NSArray<NSString *> *)getListenedChannels;
+
+/**
+ 销毁频道
+ 
+ @param channelId 频道ID
+ @param successBlock 成功的回调
+ @param errorBlock 失败的回调
+ */
+- (void)destoryChannel:(NSString *)channelId
+               success:(void(^)(void))successBlock
+                 error:(void(^)(int error_code))errorBlock;
+@end

+ 1460 - 0
wfclient/WFChatClient/Client/WFCCIMService.mm

@@ -0,0 +1,1460 @@
+//
+//  WFCCIMService.mm
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/11/5.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCIMService.h"
+#import "WFCCMediaMessageContent.h"
+#import <mars/proto/MessageDB.h>
+#import <objc/runtime.h>
+#import "WFCCNetworkService.h"
+#import <mars/app/app.h>
+#import "WFCCGroupSearchInfo.h"
+#import "WFCCUnknownMessageContent.h"
+#import "WFCCRecallMessageContent.h"
+
+
+NSString *kSendingMessageStatusUpdated = @"kSendingMessageStatusUpdated";
+NSString *kConnectionStatusChanged = @"kConnectionStatusChanged";
+NSString *kReceiveMessages = @"kReceiveMessages";
+NSString *kRecallMessages = @"kRecallMessages";
+
+class IMSendMessageCallback : public mars::stn::SendMessageCallback {
+private:
+    void(^m_successBlock)(long long messageUid, long long timestamp);
+    void(^m_errorBlock)(int error_code);
+    void(^m_progressBlock)(long uploaded, long total);
+    WFCCMessage *m_message;
+public:
+    IMSendMessageCallback(WFCCMessage *message, void(^successBlock)(long long messageUid, long long timestamp), void(^progressBlock)(long uploaded, long total), void(^errorBlock)(int error_code)) : mars::stn::SendMessageCallback(), m_message(message), m_successBlock(successBlock), m_progressBlock(progressBlock), m_errorBlock(errorBlock) {};
+     void onSuccess(long long messageUid, long long timestamp) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            m_message.messageUid = messageUid;
+            m_message.serverTime = timestamp;
+            m_message.status = Message_Status_Sent;
+            if (m_successBlock) {
+                m_successBlock(messageUid, timestamp);
+            }
+            [[NSNotificationCenter defaultCenter] postNotificationName:kSendingMessageStatusUpdated object:@(m_message.messageId) userInfo:@{@"status":@(Message_Status_Sent), @"messageUid":@(messageUid), @"timestamp":@(timestamp)}];
+            delete this;
+
+        });
+     }
+    void onFalure(int errorCode) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            m_message.status = Message_Status_Send_Failure;
+            if (m_errorBlock) {
+                m_errorBlock(errorCode);
+            }
+            [[NSNotificationCenter defaultCenter] postNotificationName:kSendingMessageStatusUpdated object:@(m_message.messageId) userInfo:@{@"status":@(Message_Status_Send_Failure)}];
+            delete this;
+        });
+    }
+    void onPrepared(long messageId, int64_t savedTime) {
+        m_message.messageId = messageId;
+        m_message.serverTime = savedTime;
+        [[NSNotificationCenter defaultCenter] postNotificationName:kSendingMessageStatusUpdated object:@(m_message.messageId) userInfo:@{@"status":@(Message_Status_Sending), @"message":m_message}];
+    }
+    void onMediaUploaded(std::string remoteUrl) {
+        if ([m_message.content isKindOfClass:[WFCCMediaMessageContent class]]) {
+            WFCCMediaMessageContent *mediaContent = (WFCCMediaMessageContent *)m_message.content;
+            mediaContent.remoteUrl = [NSString stringWithUTF8String:remoteUrl.c_str()];
+        }
+    }
+    
+    void onProgress(int uploaded, int total) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_progressBlock) {
+                m_progressBlock(uploaded, total);
+            }
+        });
+    }
+    
+    virtual ~IMSendMessageCallback() {
+        m_successBlock = nil;
+        m_errorBlock = nil;
+        m_progressBlock = nil;
+        m_message = nil;
+    }
+};
+extern WFCCUserInfo* convertUserInfo(const mars::stn::TUserInfo &tui);
+
+
+class IMCreateGroupCallback : public mars::stn::CreateGroupCallback {
+private:
+    void(^m_successBlock)(NSString *groupId);
+    void(^m_errorBlock)(int error_code);
+public:
+    IMCreateGroupCallback(void(^successBlock)(NSString *groupId), void(^errorBlock)(int error_code)) : mars::stn::CreateGroupCallback(), m_successBlock(successBlock), m_errorBlock(errorBlock) {};
+    void onSuccess(std::string groupId) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_successBlock) {
+                m_successBlock([NSString stringWithUTF8String:groupId.c_str()]);
+            }
+            delete this;
+        });
+    }
+    void onFalure(int errorCode) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_errorBlock) {
+                m_errorBlock(errorCode);
+            }
+            delete this;
+        });
+    }
+
+    virtual ~IMCreateGroupCallback() {
+        m_successBlock = nil;
+        m_errorBlock = nil;
+    }
+};
+
+class IMGeneralOperationCallback : public mars::stn::GeneralOperationCallback {
+private:
+    void(^m_successBlock)();
+    void(^m_errorBlock)(int error_code);
+public:
+    IMGeneralOperationCallback(void(^successBlock)(), void(^errorBlock)(int error_code)) : mars::stn::GeneralOperationCallback(), m_successBlock(successBlock), m_errorBlock(errorBlock) {};
+    void onSuccess() {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_successBlock) {
+                m_successBlock();
+            }
+            delete this;
+        });
+    }
+    void onFalure(int errorCode) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_errorBlock) {
+                m_errorBlock(errorCode);
+            }
+            delete this;
+        });
+    }
+
+    virtual ~IMGeneralOperationCallback() {
+        m_successBlock = nil;
+        m_errorBlock = nil;
+    }
+};
+
+class RecallMessageCallback : public mars::stn::GeneralOperationCallback {
+private:
+    void(^m_successBlock)();
+    void(^m_errorBlock)(int error_code);
+    WFCCMessage *message;
+public:
+    RecallMessageCallback(WFCCMessage *msg, void(^successBlock)(), void(^errorBlock)(int error_code)) : mars::stn::GeneralOperationCallback(), m_successBlock(successBlock), m_errorBlock(errorBlock), message(msg) {};
+    void onSuccess() {
+        WFCCRecallMessageContent *recallCnt = [[WFCCRecallMessageContent alloc] init];
+        recallCnt.operatorId = [WFCCNetworkService sharedInstance].userId;
+        recallCnt.messageUid = message.messageUid;
+        message.content = recallCnt;
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_successBlock) {
+                m_successBlock();
+            }
+            delete this;
+        });
+    }
+    void onFalure(int errorCode) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_errorBlock) {
+                m_errorBlock(errorCode);
+            }
+            delete this;
+        });
+    }
+    
+    virtual ~RecallMessageCallback() {
+        m_successBlock = nil;
+        m_errorBlock = nil;
+    }
+};
+
+class IMGetChatroomInfoCallback : public mars::stn::GetChatroomInfoCallback {
+private:
+    NSString *chatroomId;
+    void(^m_successBlock)(WFCCChatroomInfo *chatroomInfo);
+    void(^m_errorBlock)(int error_code);
+public:
+    IMGetChatroomInfoCallback(NSString *cid, void(^successBlock)(WFCCChatroomInfo *chatroomInfo), void(^errorBlock)(int error_code)) : mars::stn::GetChatroomInfoCallback(), chatroomId(cid),  m_successBlock(successBlock), m_errorBlock(errorBlock) {};
+    void onSuccess(const mars::stn::TChatroomInfo &info) {
+        WFCCChatroomInfo *chatroomInfo = [[WFCCChatroomInfo alloc] init];
+        chatroomInfo.chatroomId = chatroomId;
+        chatroomInfo.title = [NSString stringWithUTF8String:info.title.c_str()];
+        chatroomInfo.desc = [NSString stringWithUTF8String:info.desc.c_str()];
+        chatroomInfo.portrait = [NSString stringWithUTF8String:info.portrait.c_str()];
+        chatroomInfo.extra = [NSString stringWithUTF8String:info.extra.c_str()];
+        chatroomInfo.state = info.state;
+        chatroomInfo.memberCount = info.memberCount;
+        chatroomInfo.createDt = info.createDt;
+        chatroomInfo.updateDt = info.updateDt;
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_successBlock) {
+                m_successBlock(chatroomInfo);
+            }
+            delete this;
+        });
+    }
+    void onFalure(int errorCode) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_errorBlock) {
+                m_errorBlock(errorCode);
+            }
+            delete this;
+        });
+    }
+    
+    virtual ~IMGetChatroomInfoCallback() {
+        m_successBlock = nil;
+        m_errorBlock = nil;
+    }
+};
+
+class IMGetChatroomMemberInfoCallback : public mars::stn::GetChatroomMemberInfoCallback {
+private:
+    void(^m_successBlock)(WFCCChatroomMemberInfo *chatroomMemberInfo);
+    void(^m_errorBlock)(int error_code);
+public:
+    IMGetChatroomMemberInfoCallback(void(^successBlock)(WFCCChatroomMemberInfo *chatroomMemberInfo), void(^errorBlock)(int error_code)) : mars::stn::GetChatroomMemberInfoCallback(), m_successBlock(successBlock), m_errorBlock(errorBlock) {};
+    void onSuccess(const mars::stn::TChatroomMemberInfo &info) {
+        WFCCChatroomMemberInfo *memberInfo = [[WFCCChatroomMemberInfo alloc] init];
+        memberInfo.memberCount = info.memberCount;
+        NSMutableArray *members = [[NSMutableArray alloc] init];
+        for (std::list<std::string>::const_iterator it = info.olderMembers.begin(); it != info.olderMembers.end(); it++) {
+            [members addObject:[NSString stringWithUTF8String:it->c_str()]];
+        }
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_successBlock) {
+                m_successBlock(memberInfo);
+            }
+            delete this;
+        });
+    }
+    void onFalure(int errorCode) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_errorBlock) {
+                m_errorBlock(errorCode);
+            }
+            delete this;
+        });
+    }
+    
+    virtual ~IMGetChatroomMemberInfoCallback() {
+        m_successBlock = nil;
+        m_errorBlock = nil;
+    }
+};
+
+class IMGetGroupInfoCallback : public mars::stn::GetGroupInfoCallback {
+private:
+    void(^m_successBlock)(NSArray<WFCCGroupInfo *> *);
+    void(^m_errorBlock)(int error_code);
+public:
+    IMGetGroupInfoCallback(void(^successBlock)(NSArray<WFCCGroupInfo *> *), void(^errorBlock)(int error_code)) : mars::stn::GetGroupInfoCallback(), m_successBlock(successBlock), m_errorBlock(errorBlock) {};
+    void onSuccess(const std::list<const mars::stn::TGroupInfo> &groupInfoList) {
+        
+        NSMutableArray *ret = nil;
+        if (m_successBlock) {
+            NSMutableArray *ret = [[NSMutableArray alloc] init];
+            for (std::list<const mars::stn::TGroupInfo>::const_iterator it = groupInfoList.begin(); it != groupInfoList.end(); it++) {
+                WFCCGroupInfo *gi = [[WFCCGroupInfo alloc] init];
+                const mars::stn::TGroupInfo &tgi = *it;
+                gi.target = [NSString stringWithUTF8String:tgi.target.c_str()];
+                gi.type = (WFCCGroupType)tgi.type;
+                gi.memberCount = tgi.memberCount;
+                gi.name = [NSString stringWithUTF8String:tgi.name.c_str()];
+                gi.owner = [NSString stringWithUTF8String:tgi.owner.c_str()];
+                gi.extra = [NSData dataWithBytes:(const void *)tgi.extra.c_str() length:tgi.extra.length()];
+                [ret addObject:gi];
+            }
+            
+        }
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_successBlock) {
+                m_successBlock(ret);
+            }
+            delete this;
+        });
+    }
+    void onFalure(int errorCode) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_errorBlock) {
+                m_errorBlock(errorCode);
+            }
+            delete this;
+        });
+    }
+    
+    virtual ~IMGetGroupInfoCallback() {
+        m_successBlock = nil;
+        m_errorBlock = nil;
+    }
+};
+
+class GeneralUpdateMediaCallback : public mars::stn::UpdateMediaCallback {
+public:
+  void(^m_successBlock)(NSString *remoteUrl);
+  void(^m_errorBlock)(int error_code);
+  void(^m_progressBlock)(long uploaded, long total);
+  
+  GeneralUpdateMediaCallback(void(^successBlock)(NSString *remoteUrl), void(^progressBlock)(long uploaded, long total), void(^errorBlock)(int error_code)) : mars::stn::UpdateMediaCallback(), m_successBlock(successBlock), m_progressBlock(progressBlock), m_errorBlock(errorBlock) {}
+  
+  void onSuccess(const std::string &remoteUrl) {
+      NSString *url = [NSString stringWithUTF8String:remoteUrl.c_str()];
+      dispatch_async(dispatch_get_main_queue(), ^{
+          if (m_successBlock) {
+              m_successBlock(url);
+          }
+          delete this;
+      });
+  }
+  
+  void onFalure(int errorCode) {
+      dispatch_async(dispatch_get_main_queue(), ^{
+          if (m_errorBlock) {
+              m_errorBlock(errorCode);
+          }
+          delete this;
+      });
+  }
+  
+    void onProgress(int current, int total) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_progressBlock) {
+                m_progressBlock(current, total);
+            }
+        });
+    }
+    
+  ~GeneralUpdateMediaCallback() {
+    m_successBlock = nil;
+    m_errorBlock = nil;
+  }
+};
+
+static WFCCMessage *convertProtoMessage(const mars::stn::TMessage *tMessage) {
+    if (tMessage->messageId < 0 || tMessage->target.empty()) {
+        return nil;
+    }
+    WFCCMessage *ret = [[WFCCMessage alloc] init];
+    ret.fromUser = [NSString stringWithUTF8String:tMessage->from.c_str()];
+    ret.conversation = [[WFCCConversation alloc] init];
+    ret.conversation.type = (WFCCConversationType)tMessage->conversationType;
+    ret.conversation.target = [NSString stringWithUTF8String:tMessage->target.c_str()];
+    ret.conversation.line = tMessage->line;
+    ret.messageId = tMessage->messageId;
+    ret.messageUid = tMessage->messageUid;
+    ret.serverTime = tMessage->timestamp;
+    ret.toUser = [NSString stringWithUTF8String:tMessage->to.c_str()];
+    ret.direction = (WFCCMessageDirection)tMessage->direction;
+    ret.status = (WFCCMessageStatus)tMessage->status;
+    
+    WFCCMediaMessagePayload *payload = [[WFCCMediaMessagePayload alloc] init];
+    payload.contentType = tMessage->content.type;
+    payload.searchableContent = [NSString stringWithUTF8String:tMessage->content.searchableContent.c_str()];
+    payload.pushContent = [NSString stringWithUTF8String:tMessage->content.pushContent.c_str()];
+    
+    payload.content = [NSString stringWithUTF8String:tMessage->content.content.c_str()];
+    payload.binaryContent = [NSData dataWithBytes:tMessage->content.binaryContent.c_str() length:tMessage->content.binaryContent.length()];
+    payload.localContent = [NSString stringWithUTF8String:tMessage->content.localContent.c_str()];
+    payload.mediaType = (WFCCMediaType)tMessage->content.mediaType;
+    payload.remoteMediaUrl = [NSString stringWithUTF8String:tMessage->content.remoteMediaUrl.c_str()];
+    payload.localMediaPath = [NSString stringWithUTF8String:tMessage->content.localMediaPath.c_str()];
+    payload.mentionedType = tMessage->content.mentionedType;
+  NSMutableArray *mentionedType = [[NSMutableArray alloc] init];
+  for (std::list<std::string>::const_iterator it = tMessage->content.mentionedTargets.begin(); it != tMessage->content.mentionedTargets.end(); it++) {
+    [mentionedType addObject:[NSString stringWithUTF8String:(*it).c_str()]];
+  }
+  
+    ret.content = [[WFCCIMService sharedWFCIMService] messageContentFromPayload:payload];
+    return ret;
+}
+
+
+NSMutableArray* convertProtoMessageList(const std::list<mars::stn::TMessage> &messageList, BOOL reverse) {
+    NSMutableArray *messages = [[NSMutableArray alloc] init];
+    for (std::list<mars::stn::TMessage>::const_iterator it = messageList.begin(); it != messageList.end(); it++) {
+        const mars::stn::TMessage &tmsg = *it;
+        WFCCMessage *msg = convertProtoMessage(&tmsg);
+        if (msg) {
+            if (reverse) {
+                [messages insertObject:msg atIndex:0];
+            } else {
+                [messages addObject:msg];
+            }
+        }
+    }
+    return messages;
+}
+
+static WFCCConversationInfo* convertConversationInfo(const mars::stn::TConversation &tConv) {
+    WFCCConversationInfo *info = [[WFCCConversationInfo alloc] init];
+    info.conversation = [[WFCCConversation alloc] init];
+    info.conversation.type = (WFCCConversationType)tConv.conversationType;
+    info.conversation.target = [NSString stringWithUTF8String:tConv.target.c_str()];
+    info.conversation.line = tConv.line;
+    info.lastMessage = convertProtoMessage(&tConv.lastMessage);
+    info.draft = [NSString stringWithUTF8String:tConv.draft.c_str()];
+    info.timestamp = tConv.timestamp;
+    info.unreadCount = [WFCCUnreadCount countOf:tConv.unreadCount.unread mention:tConv.unreadCount.unreadMetion mentionAll:tConv.unreadCount.unreadMentionAll];
+    info.isTop = tConv.isTop;
+    info.isSilent = tConv.isSilent;
+    return info;
+}
+
+static WFCCIMService * sharedSingleton = nil;
+
+static void fillTMessageContent(mars::stn::TMessageContent &tmsgcontent, WFCCMessageContent *content) {
+    WFCCMessagePayload *payload = [content encode];
+    tmsgcontent.type = payload.contentType;
+    tmsgcontent.searchableContent = [payload.searchableContent UTF8String] ? [payload.searchableContent UTF8String] : "";
+    tmsgcontent.pushContent = [payload.pushContent UTF8String] ? [payload.pushContent UTF8String] : "";
+    
+    tmsgcontent.content = [payload.content UTF8String] ? [payload.content UTF8String] : "";
+    if (payload.binaryContent != nil) {
+        tmsgcontent.binaryContent = std::string((const char *)payload.binaryContent.bytes, payload.binaryContent.length);
+    }
+    tmsgcontent.localContent = [payload.localContent UTF8String] ? [payload.localContent UTF8String] : "";
+    if ([payload isKindOfClass:[WFCCMediaMessagePayload class]]) {
+        WFCCMediaMessagePayload *mediaPayload = (WFCCMediaMessagePayload *)payload;
+        tmsgcontent.mediaType = mediaPayload.mediaType;
+        tmsgcontent.remoteMediaUrl = [mediaPayload.remoteMediaUrl UTF8String] ? [mediaPayload.remoteMediaUrl UTF8String] : "";
+        tmsgcontent.localMediaPath = [mediaPayload.localMediaPath UTF8String] ? [mediaPayload.localMediaPath UTF8String] : "";
+    }
+    
+    tmsgcontent.mentionedType = payload.mentionedType;
+    for (NSString *target in payload.mentionedTargets) {
+        tmsgcontent.mentionedTargets.insert(tmsgcontent.mentionedTargets.end(), [target UTF8String]);
+    }
+}
+
+
+static void fillTMessage(mars::stn::TMessage &tmsg, WFCCConversation *conv, WFCCMessageContent *content) {
+    tmsg.conversationType = conv.type;
+    tmsg.target = conv.target ? [conv.target UTF8String] : "";
+    tmsg.line = conv.line;
+    tmsg.from = mars::app::GetUserName();
+    tmsg.status = mars::stn::MessageStatus::Message_Status_Sending;
+    tmsg.timestamp = time(NULL)*1000;
+    tmsg.direction = 0;
+    fillTMessageContent(tmsg.content, content);
+}
+
+@interface WFCCIMService ()
+@property(nonatomic, strong)NSMutableDictionary<NSNumber *, Class> *MessageContentMaps;
+@end
+@implementation WFCCIMService
++ (WFCCIMService *)sharedWFCIMService {
+    if (sharedSingleton == nil) {
+        @synchronized (self) {
+            if (sharedSingleton == nil) {
+                sharedSingleton = [[WFCCIMService alloc] init];
+                sharedSingleton.MessageContentMaps = [[NSMutableDictionary alloc] init];
+            }
+        }
+    }
+
+    return sharedSingleton;
+}
+
+- (WFCCMessage *)send:(WFCCConversation *)conversation
+              content:(WFCCMessageContent *)content
+              success:(void(^)(long long messageUd, long long timestamp))successBlock
+                error:(void(^)(int error_code))errorBlock {
+    return [self sendMedia:conversation content:content expireDuration:0 success:successBlock progress:nil error:errorBlock];
+}
+
+- (WFCCMessage *)sendMedia:(WFCCConversation *)conversation
+                   content:(WFCCMessageContent *)content
+                   success:(void(^)(long long messageUid, long long timestamp))successBlock
+                  progress:(void(^)(long uploaded, long total))progressBlock
+                     error:(void(^)(int error_code))errorBlock {
+    return [self sendMedia:conversation content:content expireDuration:0 success:successBlock progress:progressBlock error:errorBlock];
+}
+
+- (WFCCMessage *)send:(WFCCConversation *)conversation
+              content:(WFCCMessageContent *)content
+       expireDuration:(int)expireDuration
+              success:(void(^)(long long messageUid, long long timestamp))successBlock
+                error:(void(^)(int error_code))errorBlock {
+    return [self sendMedia:conversation content:content expireDuration:0 success:successBlock progress:nil error:errorBlock];
+}
+
+- (WFCCMessage *)send:(WFCCConversation *)conversation
+              content:(WFCCMessageContent *)content
+               toUser:(NSString *)toUser
+       expireDuration:(int)expireDuration
+              success:(void(^)(long long messageUid, long long timestamp))successBlock
+                error:(void(^)(int error_code))errorBlock {
+    return [self sendMedia:conversation content:content toUser:toUser expireDuration:0 success:successBlock progress:nil error:errorBlock];
+}
+- (WFCCMessage *)sendMedia:(WFCCConversation *)conversation
+                   content:(WFCCMessageContent *)content
+            expireDuration:(int)expireDuration
+                   success:(void(^)(long long messageUid, long long timestamp))successBlock
+                  progress:(void(^)(long uploaded, long total))progressBlock
+                     error:(void(^)(int error_code))errorBlock {
+    return [self sendMedia:conversation content:content toUser:nil expireDuration:expireDuration success:successBlock progress:progressBlock error:errorBlock];
+}
+
+- (WFCCMessage *)sendMedia:(WFCCConversation *)conversation
+                   content:(WFCCMessageContent *)content
+                    toUser:(NSString *)toUser
+            expireDuration:(int)expireDuration
+                   success:(void(^)(long long messageUid, long long timestamp))successBlock
+                  progress:(void(^)(long uploaded, long total))progressBlock
+                     error:(void(^)(int error_code))errorBlock {
+    
+    WFCCMessage *message = [[WFCCMessage alloc] init];
+    message.conversation = conversation;
+    message.content = content;
+    message.toUser = toUser;
+    mars::stn::TMessage tmsg;
+    tmsg.to = (toUser == nil ? "" : [toUser UTF8String]);
+    fillTMessage(tmsg, conversation, content);
+    mars::stn::sendMessage(tmsg, new IMSendMessageCallback(message, successBlock, progressBlock, errorBlock), expireDuration);
+    message.fromUser = [WFCCNetworkService sharedInstance].userId;
+    
+    return message;
+}
+
+- (void)recall:(WFCCMessage *)msg
+       success:(void(^)(void))successBlock
+         error:(void(^)(int error_code))errorBlock {
+    if (msg == nil) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            NSLog(@"recall msg failure, message not exist");
+            errorBlock(-1);
+        });
+        return;
+    }
+    
+    mars::stn::recallMessage(msg.messageUid, new RecallMessageCallback(msg, successBlock, errorBlock));
+}
+- (NSArray<WFCCConversationInfo *> *)getConversationInfos:(NSArray<NSNumber *> *)conversationTypes lines:(NSArray<NSNumber *> *)lines{
+    std::list<int> types;
+    for (NSNumber *type in conversationTypes) {
+        types.push_back([type intValue]);
+    }
+    
+    std::list<int> ls;
+    for (NSNumber *type in lines) {
+        ls.push_back([type intValue]);
+    }
+    std::list<mars::stn::TConversation> convers = mars::stn::MessageDB::Instance()->GetConversationList(types, ls);
+    NSMutableArray *ret = [[NSMutableArray alloc] init];
+    for (std::list<mars::stn::TConversation>::iterator it = convers.begin(); it != convers.end(); it++) {
+        mars::stn::TConversation &tConv = *it;
+        WFCCConversationInfo *info = convertConversationInfo(tConv);
+        [ret addObject:info];
+    }
+    return ret;
+}
+
+- (WFCCConversationInfo *)getConversationInfo:(WFCCConversation *)conversation {
+    mars::stn::TConversation tConv = mars::stn::MessageDB::Instance()->GetConversation(conversation.type, [conversation.target UTF8String], conversation.line);
+    return convertConversationInfo(tConv);
+}
+- (NSArray<WFCCMessage *> *)getMessages:(WFCCConversation *)conversation contentTypes:(NSArray<NSNumber *> *)contentTypes from:(NSUInteger)fromIndex count:(NSInteger)count withUser:(NSString *)user {
+    std::list<int> types;
+    for (NSNumber *num in contentTypes) {
+        types.push_back(num.intValue);
+    }
+    bool direction = true;
+    if (count < 0) {
+        direction = false;
+        count = -count;
+    }
+    
+    std::list<mars::stn::TMessage> messages = mars::stn::MessageDB::Instance()->GetMessages(conversation.type, [conversation.target UTF8String], conversation.line, types, direction, (int)count, fromIndex, user ? [user UTF8String] : "");
+    return convertProtoMessageList(messages, YES);
+}
+
+- (NSArray<WFCCMessage *> *)getRemoteMessages:(WFCCConversation *)conversation
+                                       before:(long long)beforeMessageUid
+                                        count:(NSUInteger)count {
+    return nil;
+}
+
+- (WFCCMessage *)getMessage:(long)messageId {
+  mars::stn::TMessage tMsg = mars::stn::MessageDB::Instance()->GetMessage(messageId);
+  return convertProtoMessage(&tMsg);
+}
+
+- (WFCCMessage *)getMessageByUid:(long long)messageUid {
+  mars::stn::TMessage tMsg = mars::stn::MessageDB::Instance()->GetMessageByUid(messageUid);
+  return convertProtoMessage(&tMsg);
+}
+
+- (WFCCUnreadCount *)getUnreadCount:(WFCCConversation *)conversation {
+    mars::stn::TUnreadCount tcount = mars::stn::MessageDB::Instance()->GetUnreadCount(conversation.type, [conversation.target UTF8String], conversation.line);
+    return [WFCCUnreadCount countOf:tcount.unread mention:tcount.unreadMetion mentionAll:tcount.unreadMentionAll];
+}
+
+- (WFCCUnreadCount *)getUnreadCount:(NSArray<NSNumber *> *)conversationTypes lines:(NSArray<NSNumber *> *)lines {
+    std::list<int> types;
+    std::list<int> ls;
+    for (NSNumber *type in conversationTypes) {
+        types.insert(types.end(), type.intValue);
+    }
+    
+    for (NSNumber *line in lines) {
+        ls.insert(ls.end(), line.intValue);
+    }
+    mars::stn::TUnreadCount tcount =  mars::stn::MessageDB::Instance()->GetUnreadCount(types, ls);
+    return [WFCCUnreadCount countOf:tcount.unread mention:tcount.unreadMetion mentionAll:tcount.unreadMentionAll];
+}
+
+- (void)clearUnreadStatus:(WFCCConversation *)conversation {
+    mars::stn::MessageDB::Instance()->ClearUnreadStatus(conversation.type, [conversation.target UTF8String], conversation.line);
+}
+
+- (void)clearAllUnreadStatus {
+    mars::stn::MessageDB::Instance()->ClearAllUnreadStatus();
+}
+
+
+- (void)setMediaMessagePlayed:(long)messageId {
+    WFCCMessage *message = [self getMessage:messageId];
+    if (!message || ![message.content isKindOfClass:[WFCCMediaMessageContent class]] || message.direction == MessageDirection_Send) {
+        return;
+    }
+    
+    mars::stn::MessageDB::Instance()->updateMessageStatus(messageId, mars::stn::Message_Status_Played);
+}
+
+- (void)removeConversation:(WFCCConversation *)conversation clearMessage:(BOOL)clearMessage {
+    mars::stn::MessageDB::Instance()->RemoveConversation(conversation.type, [conversation.target UTF8String], conversation.line, clearMessage);
+}
+
+- (void)clearMessages:(WFCCConversation *)conversation {
+    mars::stn::MessageDB::Instance()->ClearMessages(conversation.type, [conversation.target UTF8String], conversation.line);
+}
+
+- (void)setConversation:(WFCCConversation *)conversation top:(BOOL)top
+                success:(void(^)(void))successBlock
+                  error:(void(^)(int error_code))errorBlock {
+//    mars::stn::MessageDB::Instance()->updateConversationIsTop(conversation.type, [conversation.target UTF8String], conversation.line, top);
+    
+    [self setUserSetting:(UserSettingScope)mars::stn::kUserSettingConversationTop key:[NSString stringWithFormat:@"%zd-%d-%@", conversation.type, conversation.line, conversation.target] value:top ? @"1" : @"0" success:successBlock error:errorBlock];
+}
+
+- (void)setConversation:(WFCCConversation *)conversation draft:(NSString *)draft {
+    mars::stn::MessageDB::Instance()->updateConversationDraft(conversation.type, [conversation.target UTF8String], conversation.line, draft ? [draft UTF8String] : "");
+}
+
+class IMSearchUserCallback : public mars::stn::SearchUserCallback {
+private:
+    void(^m_successBlock)(NSArray<WFCCUserInfo *> *machedUsers);
+    void(^m_errorBlock)(int errorCode);
+public:
+    IMSearchUserCallback(void(^successBlock)(NSArray<WFCCUserInfo *> *machedUsers), void(^errorBlock)(int errorCode)) : m_successBlock(successBlock), m_errorBlock(errorBlock) {}
+    
+    void onSuccess(const std::list<mars::stn::TUserInfo> &users, const std::string &keyword, int page) {
+        NSMutableArray *outUsers = [[NSMutableArray alloc] initWithCapacity:users.size()];
+        for(std::list<mars::stn::TUserInfo>::const_iterator it = users.begin(); it != users.end(); it++) {
+            [outUsers addObject:convertUserInfo(*it)];
+        }
+        m_successBlock(outUsers);
+        delete this;
+    }
+    void onFalure(int errorCode) {
+        m_errorBlock(errorCode);
+        delete this;
+    }
+    
+    ~IMSearchUserCallback() {}
+};
+
+- (void)searchUser:(NSString *)keyword success:(void(^)(NSArray<WFCCUserInfo *> *machedUsers))successBlock error:(void(^)(int errorCode))errorBlock {
+    
+    if (self.userSource) {
+        [self.userSource searchUser:keyword success:successBlock error:errorBlock];
+        return;
+    }
+    
+    mars::stn::searchUser([keyword UTF8String], YES, 0, new IMSearchUserCallback(successBlock, errorBlock));
+}
+
+- (BOOL)isMyFriend:(NSString *)userId {
+    return mars::stn::MessageDB::Instance()->isMyFriend([userId UTF8String]);
+}
+
+- (NSArray<NSString *> *)getMyFriendList:(BOOL)refresh {
+    NSMutableArray *ret = [[NSMutableArray alloc] init];
+    std::list<std::string> friendList = mars::stn::MessageDB::Instance()->getMyFriendList(refresh);
+    for (std::list<std::string>::iterator it = friendList.begin(); it != friendList.end(); it++) {
+        [ret addObject:[NSString stringWithUTF8String:(*it).c_str()]];
+    }
+    return ret;
+}
+
+- (NSArray<WFCCUserInfo *> *)searchFriends:(NSString *)keyword {
+    std::list<mars::stn::TUserInfo> friends = mars::stn::MessageDB::Instance()->SearchFriends([keyword UTF8String], 50);
+    NSMutableArray<WFCCUserInfo *> *ret = [[NSMutableArray alloc] init];
+    for (std::list<mars::stn::TUserInfo>::iterator it = friends.begin(); it != friends.end(); it++) {
+        WFCCUserInfo *userInfo = convertUserInfo(*it);
+        if (userInfo) {
+            [ret addObject:userInfo];
+        }
+    }
+  return ret;
+}
+WFCCChannelInfo *convertProtoChannelInfo(const mars::stn::TChannelInfo &tci) {
+    if (tci.channelId.empty()) {
+        return nil;
+    }
+    WFCCChannelInfo *channelInfo = [[WFCCChannelInfo alloc] init];
+    channelInfo.channelId = [NSString stringWithUTF8String:tci.channelId.c_str()];
+    channelInfo.desc = [NSString stringWithUTF8String:tci.desc.c_str()];
+    channelInfo.name = [NSString stringWithUTF8String:tci.name.c_str()];
+    channelInfo.extra = [NSString stringWithUTF8String:tci.extra.c_str()];
+    channelInfo.portrait = [NSString stringWithUTF8String:tci.portrait.c_str()];
+    channelInfo.owner = [NSString stringWithUTF8String:tci.owner.c_str()];
+    channelInfo.secret = [NSString stringWithUTF8String:tci.secret.c_str()];
+    channelInfo.callback = [NSString stringWithUTF8String:tci.callback.c_str()];
+    channelInfo.status = tci.status;
+    channelInfo.updateDt = tci.updateDt;
+    return channelInfo;
+}
+
+
+class IMCreateChannelCallback : public mars::stn::CreateChannelCallback {
+private:
+    void(^m_successBlock)(WFCCChannelInfo *channelInfo);
+    void(^m_errorBlock)(int error_code);
+public:
+    IMCreateChannelCallback(void(^successBlock)(WFCCChannelInfo *channelInfo), void(^errorBlock)(int error_code)) : mars::stn::CreateChannelCallback(), m_successBlock(successBlock), m_errorBlock(errorBlock) {};
+    void onSuccess(const mars::stn::TChannelInfo &channelInfo) {
+        WFCCChannelInfo *ci = convertProtoChannelInfo(channelInfo);
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_successBlock) {
+                m_successBlock(ci);
+            }
+            delete this;
+        });
+    }
+    void onFalure(int errorCode) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (m_errorBlock) {
+                m_errorBlock(errorCode);
+            }
+            delete this;
+        });
+    }
+    
+    virtual ~IMCreateChannelCallback() {
+        m_successBlock = nil;
+        m_errorBlock = nil;
+    }
+};
+
+class IMSearchChannelCallback : public mars::stn::SearchChannelCallback {
+private:
+    void(^m_successBlock)(NSArray<WFCCChannelInfo *> *machedChannels);
+    void(^m_errorBlock)(int errorCode);
+public:
+    IMSearchChannelCallback(void(^successBlock)(NSArray<WFCCChannelInfo *> *machedUsers), void(^errorBlock)(int errorCode)) : m_successBlock(successBlock), m_errorBlock(errorBlock) {}
+    
+    void onSuccess(const std::list<mars::stn::TChannelInfo> &users, const std::string &keyword) {
+        NSMutableArray *outUsers = [[NSMutableArray alloc] initWithCapacity:users.size()];
+        for(std::list<mars::stn::TChannelInfo>::const_iterator it = users.begin(); it != users.end(); it++) {
+            [outUsers addObject:convertProtoChannelInfo(*it)];
+        }
+        m_successBlock(outUsers);
+        delete this;
+    }
+    void onFalure(int errorCode) {
+        m_errorBlock(errorCode);
+        delete this;
+    }
+    
+    ~IMSearchChannelCallback() {}
+};
+
+WFCCGroupInfo *convertProtoGroupInfo(mars::stn::TGroupInfo tgi) {
+    if (tgi.target.empty()) {
+        return nil;
+    }
+    WFCCGroupInfo *groupInfo = [[WFCCGroupInfo alloc] init];
+    groupInfo.type = (WFCCGroupType)tgi.type;
+    groupInfo.target = [NSString stringWithUTF8String:tgi.target.c_str()];
+    groupInfo.name = [NSString stringWithUTF8String:tgi.name.c_str()];
+    groupInfo.extra = [NSData dataWithBytes:tgi.extra.c_str() length:tgi.extra.length()];
+    groupInfo.portrait = [NSString stringWithUTF8String:tgi.portrait.c_str()];
+    groupInfo.owner = [NSString stringWithUTF8String:tgi.owner.c_str()];
+    groupInfo.memberCount = tgi.memberCount;
+    return groupInfo;
+}
+
+
+- (NSArray<WFCCGroupSearchInfo *> *)searchGroups:(NSString *)keyword {
+    std::list<mars::stn::TGroupSearchResult> groups = mars::stn::MessageDB::Instance()->SearchGroups([keyword UTF8String], 50);
+    NSMutableArray<WFCCGroupSearchInfo *> *ret = [[NSMutableArray alloc] init];
+    for (std::list<mars::stn::TGroupSearchResult>::iterator it = groups.begin(); it != groups.end(); it++) {
+        WFCCGroupSearchInfo *searchGroupInfo = [[WFCCGroupSearchInfo alloc] init];
+        searchGroupInfo.groupInfo = convertProtoGroupInfo(it->groupInfo);
+        searchGroupInfo.marchType = it->marchedType;
+        if (!it->marchedMemberNames.empty()) {
+            NSMutableArray *members = [[NSMutableArray alloc] init];
+            for (std::string name : it->marchedMemberNames) {
+                [members addObject:[NSString stringWithUTF8String:name.c_str()]];
+            }
+            searchGroupInfo.marchedMemberNames = [members copy];
+        }
+        searchGroupInfo.keyword = keyword;
+        [ret addObject:searchGroupInfo];
+    }
+    return ret;
+}
+
+
+- (NSArray<WFCCFriendRequest *> *)convertFriendRequest:(std::list<mars::stn::TFriendRequest>)tRequests {
+    NSMutableArray *ret = [[NSMutableArray alloc] init];
+    for (std::list<mars::stn::TFriendRequest>::iterator it = tRequests.begin(); it != tRequests.end(); it++) {
+        WFCCFriendRequest *request = [[WFCCFriendRequest alloc] init];
+        mars::stn::TFriendRequest *tRequest = &(*it);
+        request.direction = tRequest->direction;
+        request.target = [NSString stringWithUTF8String:tRequest->target.c_str()];
+        request.reason = [NSString stringWithUTF8String:tRequest->reason.c_str()];
+        request.status = tRequest->status;
+        request.readStatus = tRequest->readStatus;
+        request.timestamp = tRequest->timestamp;
+        [ret addObject:request];
+    }
+    return ret;
+}
+
+- (void)loadFriendRequestFromRemote {
+    mars::stn::loadFriendRequestFromRemote();
+}
+
+- (NSArray<WFCCFriendRequest *> *)getIncommingFriendRequest {
+    std::list<mars::stn::TFriendRequest> tRequests = mars::stn::MessageDB::Instance()->getFriendRequest(1);
+    return [self convertFriendRequest:tRequests];
+}
+
+- (NSArray<WFCCFriendRequest *> *)getOutgoingFriendRequest {
+    std::list<mars::stn::TFriendRequest> tRequests = mars::stn::MessageDB::Instance()->getFriendRequest(0);
+    return [self convertFriendRequest:tRequests];
+}
+
+- (void)clearUnreadFriendRequestStatus {
+    mars::stn::MessageDB::Instance()->clearUnreadFriendRequestStatus();
+}
+
+- (int)getUnreadFriendRequestStatus {
+    return mars::stn::MessageDB::Instance()->unreadFriendRequest();
+}
+
+- (void)sendFriendRequest:(NSString *)userId
+                   reason:(NSString *)reason
+                  success:(void(^)())successBlock
+                    error:(void(^)(int error_code))errorBlock {
+    mars::stn::sendFriendRequest([userId UTF8String], [reason UTF8String], new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+
+- (void)handleFriendRequest:(NSString *)userId
+                     accept:(BOOL)accpet
+                    success:(void(^)())successBlock
+                      error:(void(^)(int error_code))errorBlock {
+    mars::stn::handleFriendRequest([userId UTF8String], accpet, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)deleteFriend:(NSString *)userId
+             success:(void(^)())successBlock
+               error:(void(^)(int error_code))errorBlock {
+    mars::stn::deleteFriend([userId UTF8String], new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (BOOL)isBlackListed:(NSString *)userId {
+    return mars::stn::MessageDB::Instance()->isBlackListed([userId UTF8String]);
+}
+
+- (NSArray<NSString *> *)getBlackList:(BOOL)refresh {
+    NSMutableArray *ret = [[NSMutableArray alloc] init];
+    std::list<std::string> friendList = mars::stn::MessageDB::Instance()->getBlackList(refresh);
+    for (std::list<std::string>::iterator it = friendList.begin(); it != friendList.end(); it++) {
+        [ret addObject:[NSString stringWithUTF8String:(*it).c_str()]];
+    }
+    return ret;
+}
+
+- (void)setBlackList:(NSString *)userId
+       isBlackListed:(BOOL)isBlackListed
+             success:(void(^)(void))successBlock
+               error:(void(^)(int error_code))errorBlock {
+    mars::stn::blackListRequest([userId UTF8String], isBlackListed, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+- (WFCCUserInfo *)getUserInfo:(NSString *)userId refresh:(BOOL)refresh {
+    if (!userId) {
+        return nil;
+    }
+    
+    if (self.userSource) {
+        return [self.userSource getUserInfo:userId refresh:refresh];
+    }
+    
+    mars::stn::TUserInfo tui = mars::stn::MessageDB::Instance()->getUserInfo([userId UTF8String], refresh);
+    if (!tui.uid.empty()) {
+        WFCCUserInfo *userInfo = convertUserInfo(tui);
+        return userInfo;
+    }
+    return nil;
+}
+
+- (void)uploadMedia:(NSData *)mediaData
+          mediaType:(WFCCMediaType)mediaType
+            success:(void(^)(NSString *remoteUrl))successBlock
+           progress:(void(^)(long uploaded, long total))progressBlock
+              error:(void(^)(int error_code))errorBlock {
+    mars::stn::uploadGeneralMedia(std::string((char *)mediaData.bytes, mediaData.length), mediaType, new GeneralUpdateMediaCallback(successBlock, progressBlock, errorBlock));
+}
+
+-(void)modifyMyInfo:(NSDictionary<NSNumber */*ModifyMyInfoType*/, NSString *> *)values
+            success:(void(^)())successBlock
+              error:(void(^)(int error_code))errorBlock {
+    if (self.userSource) {
+        [self.userSource modifyMyInfo:values success:successBlock error:errorBlock];
+        return;
+    }
+    
+    std::list<std::pair<int, std::string>> infos;
+    for(NSNumber *key in values.allKeys) {
+        infos.push_back(std::pair<int, std::string>([key intValue], [values[key] UTF8String]));
+    }
+    mars::stn::modifyMyInfo(infos, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (BOOL)isGlobalSlient {
+    NSString *strValue = [[WFCCIMService sharedWFCIMService] getUserSetting:UserSettingScope_Global_Silent key:@""];
+    return [strValue isEqualToString:@"1"];
+}
+
+- (void)setGlobalSlient:(BOOL)slient
+                success:(void(^)(void))successBlock
+                  error:(void(^)(int error_code))errorBlock {
+    [[WFCCIMService sharedWFCIMService] setUserSetting:UserSettingScope_Global_Silent key:@"" value:slient?@"1":@"0" success:^{
+        if (successBlock) {
+            successBlock();
+        }
+    } error:^(int error_code) {
+        if (errorBlock) {
+            errorBlock(error_code);
+        }
+    }];
+}
+//UserSettingScope_Global_Silent = 2,
+//
+- (BOOL)isHiddenNotificationDetail {
+    NSString *strValue = [[WFCCIMService sharedWFCIMService] getUserSetting:UserSettingScope_Hidden_Notification_Detail key:@""];
+    return [strValue isEqualToString:@"1"];
+}
+
+- (void)setHiddenNotificationDetail:(BOOL)hidden
+                success:(void(^)(void))successBlock
+                  error:(void(^)(int error_code))errorBlock {
+    [[WFCCIMService sharedWFCIMService] setUserSetting:UserSettingScope_Hidden_Notification_Detail key:@"" value:hidden?@"1":@"0" success:^{
+        if (successBlock) {
+            successBlock();
+        }
+    } error:^(int error_code) {
+        if (errorBlock) {
+            errorBlock(error_code);
+        }
+    }];
+}
+
+//UserSettingScope_Hidden_Notification_Detail = 4,
+- (BOOL)isHiddenGroupMemberName:(NSString *)groupId {
+    NSString *strValue = [[WFCCIMService sharedWFCIMService] getUserSetting:UserSettingScope_Group_Hide_Nickname key:groupId];
+    return [strValue isEqualToString:@"1"];
+}
+
+- (void)setHiddenGroupMemberName:(BOOL)hidden
+                           group:(NSString *)groupId
+                            success:(void(^)(void))successBlock
+                              error:(void(^)(int error_code))errorBlock {
+    [[WFCCIMService sharedWFCIMService] setUserSetting:UserSettingScope_Group_Hide_Nickname key:groupId value:hidden?@"1":@"0" success:^{
+        if (successBlock) {
+            successBlock();
+        }
+    } error:^(int error_code) {
+        if (errorBlock) {
+            errorBlock(error_code);
+        }
+    }];
+}
+//UserSettingScope_Group_Hide_Nickname = 5,
+
+
+- (BOOL)deleteMessage:(long)messageId {
+    return mars::stn::MessageDB::Instance()->DeleteMessage(messageId);
+}
+
+- (NSArray<WFCCConversationSearchInfo *> *)searchConversation:(NSString *)keyword inConversation:(NSArray<NSNumber *> *)conversationTypes lines:(NSArray<NSNumber *> *)lines {
+    if (keyword.length == 0) {
+        return nil;
+    }
+    
+    std::list<int> types;
+    std::list<int> ls;
+    for (NSNumber *type in conversationTypes) {
+        types.insert(types.end(), type.intValue);
+    }
+    
+    for (NSNumber *line in lines) {
+        ls.insert(ls.end(), line.intValue);
+    }
+    
+    if(lines.count == 0) {
+        ls.insert(ls.end(), 0);
+    }
+    
+    std::list<mars::stn::TConversationSearchresult> tresult = mars::stn::MessageDB::Instance()->SearchConversations(types, ls, [keyword UTF8String], 50);
+    NSMutableArray *results = [[NSMutableArray alloc] init];
+    for (std::list<mars::stn::TConversationSearchresult>::iterator it = tresult.begin(); it != tresult.end(); it++) {
+        WFCCConversationSearchInfo *info = [[WFCCConversationSearchInfo alloc] init];
+        [results addObject:info];
+        info.conversation = [[WFCCConversation alloc] init];
+        info.conversation.type = (WFCCConversationType)(it->conversationType);
+        info.conversation.target = [NSString stringWithUTF8String:it->target.c_str()];
+        info.conversation.line = it->line;
+        info.marchedCount = it->marchedCount;
+        info.marchedMessage = convertProtoMessage(&(it->marchedMessage));
+        info.keyword = keyword;
+    }
+    return results;
+}
+
+- (NSArray<WFCCMessage *> *)searchMessage:(WFCCConversation *)conversation keyword:(NSString *)keyword {
+    if (keyword.length == 0) {
+        return nil;
+    }
+    std::list<mars::stn::TMessage> tmessages = mars::stn::MessageDB::Instance()->SearchMessages(conversation.type, [conversation.target UTF8String], conversation.line, [keyword UTF8String], 500);
+    return convertProtoMessageList(tmessages, YES);
+}
+
+- (void)createGroup:(NSString *)groupId
+               name:(NSString *)groupName
+           portrait:(NSString *)groupPortrait
+            members:(NSArray *)groupMembers
+        notifyLines:(NSArray<NSNumber *> *)notifyLines
+      notifyContent:(WFCCMessageContent *)notifyContent
+            success:(void(^)(NSString *groupId))successBlock
+              error:(void(^)(int error_code))errorBlock {
+
+    std::list<std::string> memberList;
+    for (NSString *member in groupMembers) {
+        memberList.push_back([member UTF8String]);
+    }
+    mars::stn::TMessageContent tcontent;
+    fillTMessageContent(tcontent, notifyContent);
+    
+    std::list<int> lines;
+    for (NSNumber *number in notifyLines) {
+        lines.push_back([number intValue]);
+    }
+    mars::stn::createGroup(groupId == nil ? "" : [groupId UTF8String], groupName == nil ? "" : [groupName UTF8String], groupPortrait == nil ? "" : [groupPortrait UTF8String], memberList, lines, tcontent, new IMCreateGroupCallback(successBlock, errorBlock));
+}
+
+- (void)addMembers:(NSArray *)members
+           toGroup:(NSString *)groupId
+       notifyLines:(NSArray<NSNumber *> *)notifyLines
+     notifyContent:(WFCCMessageContent *)notifyContent
+           success:(void(^)())successBlock
+             error:(void(^)(int error_code))errorBlock {
+
+    std::list<std::string> memberList;
+    for (NSString *member in members) {
+        memberList.push_back([member UTF8String]);
+    }
+
+    mars::stn::TMessageContent tcontent;
+    fillTMessageContent(tcontent, notifyContent);
+    
+    std::list<int> lines;
+    for (NSNumber *number in notifyLines) {
+        lines.push_back([number intValue]);
+    }
+    
+    mars::stn::addMembers([groupId UTF8String], memberList, lines, tcontent, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)kickoffMembers:(NSArray *)members
+             fromGroup:(NSString *)groupId
+           notifyLines:(NSArray<NSNumber *> *)notifyLines
+         notifyContent:(WFCCMessageContent *)notifyContent
+               success:(void(^)())successBlock
+                 error:(void(^)(int error_code))errorBlock {
+
+    std::list<std::string> memberList;
+    for (NSString *member in members) {
+        memberList.push_back([member UTF8String]);
+    }
+
+    mars::stn::TMessageContent tcontent;
+    fillTMessageContent(tcontent, notifyContent);
+    
+    std::list<int> lines;
+    for (NSNumber *number in notifyLines) {
+        lines.push_back([number intValue]);
+    }
+    
+    mars::stn::kickoffMembers([groupId UTF8String], memberList, lines, tcontent, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)quitGroup:(NSString *)groupId
+      notifyLines:(NSArray<NSNumber *> *)notifyLines
+    notifyContent:(WFCCMessageContent *)notifyContent
+          success:(void(^)())successBlock
+            error:(void(^)(int error_code))errorBlock {
+
+    mars::stn::TMessageContent tcontent;
+    fillTMessageContent(tcontent, notifyContent);
+    
+    std::list<int> lines;
+    for (NSNumber *number in notifyLines) {
+        lines.push_back([number intValue]);
+    }
+    
+    mars::stn::quitGroup([groupId UTF8String], lines, tcontent, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)dismissGroup:(NSString *)groupId
+         notifyLines:(NSArray<NSNumber *> *)notifyLines
+       notifyContent:(WFCCMessageContent *)notifyContent
+             success:(void(^)())successBlock
+               error:(void(^)(int error_code))errorBlock {
+
+    mars::stn::TMessageContent tcontent;
+    fillTMessageContent(tcontent, notifyContent);
+    
+    std::list<int> lines;
+    for (NSNumber *number in notifyLines) {
+        lines.push_back([number intValue]);
+    }
+    
+    mars::stn::dismissGroup([groupId UTF8String], lines, tcontent, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)modifyGroupInfo:(NSString *)groupId
+                   type:(ModifyGroupInfoType)type
+               newValue:(NSString *)newValue
+            notifyLines:(NSArray<NSNumber *> *)notifyLines
+          notifyContent:(WFCCMessageContent *)notifyContent
+                success:(void(^)(void))successBlock
+                  error:(void(^)(int error_code))errorBlock {
+    
+    mars::stn::TMessageContent tcontent;
+    fillTMessageContent(tcontent, notifyContent);
+    
+    std::list<int> lines;
+    for (NSNumber *number in notifyLines) {
+        lines.push_back([number intValue]);
+    }
+    
+    mars::stn::modifyGroupInfo([groupId UTF8String], (int)type, [newValue UTF8String], lines, tcontent, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)modifyGroupAlias:(NSString *)groupId
+                   alias:(NSString *)newAlias
+             notifyLines:(NSArray<NSNumber *> *)notifyLines
+           notifyContent:(WFCCMessageContent *)notifyContent
+                 success:(void(^)())successBlock
+                   error:(void(^)(int error_code))errorBlock {
+    
+    mars::stn::TMessageContent tcontent;
+    fillTMessageContent(tcontent, notifyContent);
+    
+    std::list<int> lines;
+    for (NSNumber *number in notifyLines) {
+        lines.push_back([number intValue]);
+    }
+    
+    mars::stn::modifyGroupAlias([groupId UTF8String], [newAlias UTF8String], lines, tcontent, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (NSArray<WFCCGroupMember *> *)getGroupMembers:(NSString *)groupId
+                             forceUpdate:(BOOL)forceUpdate {
+    std::list<mars::stn::TGroupMember> tmembers = mars::stn::MessageDB::Instance()->GetGroupMembers([groupId UTF8String], forceUpdate);
+    NSMutableArray *output = [[NSMutableArray alloc] init];
+    for(std::list<mars::stn::TGroupMember>::iterator it = tmembers.begin(); it != tmembers.end(); it++) {
+        WFCCGroupMember *member = [WFCCGroupMember new];
+        member.groupId = [NSString stringWithUTF8String:it->groupId.c_str()];
+        member.memberId = [NSString stringWithUTF8String:it->memberId.c_str()];
+        member.alias = [NSString stringWithUTF8String:it->alias.c_str()];
+        member.type = (WFCCGroupMemberType)it->type;
+        [output addObject:member];
+    }
+    return output;
+}
+
+- (WFCCGroupMember *)getGroupMember:(NSString *)groupId
+                           memberId:(NSString *)memberId {
+    mars::stn::TGroupMember tmember = mars::stn::MessageDB::Instance()->GetGroupMember([groupId UTF8String], [memberId UTF8String]);
+    if (tmember.memberId == [memberId UTF8String]) {
+        WFCCGroupMember *member = [WFCCGroupMember new];
+        member.groupId = groupId;
+        member.memberId = memberId;
+        member.alias = [NSString stringWithUTF8String:tmember.alias.c_str()];
+        member.type = (WFCCGroupMemberType)tmember.type;
+        return member;
+    }
+    return nil;
+}
+
+- (void)transferGroup:(NSString *)groupId
+                   to:(NSString *)newOwner
+          notifyLines:(NSArray<NSNumber *> *)notifyLines
+        notifyContent:(WFCCMessageContent *)notifyContent
+              success:(void(^)())successBlock
+                error:(void(^)(int error_code))errorBlock {
+    mars::stn::TMessageContent tcontent;
+    fillTMessageContent(tcontent, notifyContent);
+    
+    std::list<int> lines;
+    for (NSNumber *number in notifyLines) {
+        lines.push_back([number intValue]);
+    }
+    
+    mars::stn::transferGroup([groupId UTF8String], [newOwner UTF8String], lines, tcontent, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (NSArray<NSString *> *)getFavGroups {
+    NSDictionary *favGroupDict = [[WFCCIMService sharedWFCIMService] getUserSettings:UserSettingScope_Favourite_Group];
+    NSMutableArray *ids = [[NSMutableArray alloc] init];
+    [favGroupDict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
+        if ([obj isEqualToString:@"1"]) {
+            [ids addObject:key];
+        }
+    }];
+    return ids;
+}
+
+- (BOOL)isFavGroup:(NSString *)groupId {
+    NSString *strValue = [[WFCCIMService sharedWFCIMService] getUserSetting:UserSettingScope_Favourite_Group key:groupId];
+    if ([strValue isEqualToString:@"1"]) {
+        return YES;
+    }
+    return NO;
+}
+
+- (void)setFavGroup:(NSString *)groupId fav:(BOOL)fav success:(void(^)(void))successBlock error:(void(^)(int errorCode))errorBlock {
+    [[WFCCIMService sharedWFCIMService] setUserSetting:UserSettingScope_Favourite_Group key:groupId value:fav? @"1" : @"0" success:successBlock error:errorBlock];
+}
+- (WFCCGroupInfo *)getGroupInfo:(NSString *)groupId refresh:(BOOL)refresh {
+    mars::stn::TGroupInfo tgi = mars::stn::MessageDB::Instance()->GetGroupInfo([groupId UTF8String], refresh);
+    return convertProtoGroupInfo(tgi);
+}
+
+- (NSString *)getUserSetting:(UserSettingScope)scope key:(NSString *)key {
+    std::string str = mars::stn::MessageDB::Instance()->GetUserSetting(scope, [key UTF8String]);
+    return [NSString stringWithUTF8String:str.c_str()];
+}
+
+- (NSDictionary<NSString *, NSString *> *)getUserSettings:(UserSettingScope)scope {
+    std::map<std::string, std::string> settings = mars::stn::MessageDB::Instance()->GetUserSettings(scope);
+    NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
+    for (std::map<std::string, std::string>::iterator it = settings.begin() ; it != settings.end(); it++) {
+        NSString *key = [NSString stringWithUTF8String:it->first.c_str()];
+        NSString *value = [NSString stringWithUTF8String:it->second.c_str()];
+        [result setObject:value forKey:key];
+    }
+    return result;
+}
+
+- (void)setUserSetting:(UserSettingScope)scope key:(NSString *)key value:(NSString *)value
+               success:(void(^)())successBlock
+                 error:(void(^)(int error_code))errorBlock {
+    mars::stn::modifyUserSetting(scope, [key UTF8String], [value UTF8String], new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)setConversation:(WFCCConversation *)conversation silent:(BOOL)silent
+                success:(void(^)())successBlock
+                  error:(void(^)(int error_code))errorBlock {
+    [self setUserSetting:(UserSettingScope)mars::stn::kUserSettingConversationSilent key:[NSString stringWithFormat:@"%zd-%d-%@", conversation.type, conversation.line, conversation.target] value:silent ? @"1" : @"0" success:successBlock error:errorBlock];
+}
+
+- (WFCCMessageContent *)messageContentFromPayload:(WFCCMessagePayload *)payload {
+    int contenttype = payload.contentType;
+    Class contentClass = self.MessageContentMaps[@(contenttype)];
+    if (contentClass != nil) {
+        id messageInstance = [[contentClass alloc] init];
+        
+        if ([contentClass conformsToProtocol:@protocol(WFCCMessageContent)]) {
+            if ([messageInstance respondsToSelector:@selector(decode:)]) {
+                [messageInstance performSelector:@selector(decode:)
+                                      withObject:payload];
+            }
+        }
+        return messageInstance;
+    }
+    WFCCUnknownMessageContent *unknownMsg = [[WFCCUnknownMessageContent alloc] init];
+    [unknownMsg decode:payload];
+    return unknownMsg;
+}
+
+- (WFCCMessage *)insert:(WFCCConversation *)conversation
+                 sender:(NSString *)sender
+                content:(WFCCMessageContent *)content
+                 status:(WFCCMessageStatus)status
+                 notify:(BOOL)notify
+             serverTime:(long long)serverTime {
+    WFCCMessage *message = [[WFCCMessage alloc] init];
+    message.conversation = conversation;
+    message.content = content;
+    mars::stn::TMessage tmsg;
+    fillTMessage(tmsg, conversation, content);
+    
+    if(status >= Message_Status_Unread) {
+        tmsg.direction = 1;
+        if(conversation.type == Single_Type) {
+            tmsg.from = [conversation.target UTF8String];
+        } else {
+            tmsg.from = [sender UTF8String];
+        }
+    }
+    tmsg.status = (mars::stn::MessageStatus)status;
+    
+    if(serverTime > 0) {
+        tmsg.timestamp = serverTime;
+    }
+    
+    long msgId = mars::stn::MessageDB::Instance()->InsertMessage(tmsg);
+    message.messageId = msgId;
+    if(msgId > 0) {
+        mars::stn::MessageDB::Instance()->updateConversationTimestamp(tmsg.conversationType, tmsg.target, tmsg.line, tmsg.timestamp);
+    }
+    
+    message.fromUser = [WFCCNetworkService sharedInstance].userId;
+    if (notify) {
+        [[WFCCNetworkService sharedInstance].receiveMessageDelegate onReceiveMessage:@[message] hasMore:NO];
+    }
+    return message;
+}
+
+- (void)updateMessage:(long)messageId
+              content:(WFCCMessageContent *)content {
+    mars::stn::TMessageContent tmc;
+    fillTMessageContent(tmc, content);
+    mars::stn::MessageDB::Instance()->UpdateMessageContent(messageId, tmc);
+}
+
+- (void)registerMessageContent:(Class)contentClass {
+    int contenttype;
+    if (class_getClassMethod(contentClass, @selector(getContentType))) {
+        contenttype = [contentClass getContentType];
+        self.MessageContentMaps[@(contenttype)] = contentClass;
+        int contentflag = [contentClass getContentFlags];
+        mars::stn::MessageDB::Instance()->RegisterMessageFlag(contenttype, contentflag);
+    } else {
+        return;
+    }
+}
+
+- (void)joinChatroom:(NSString *)chatroomId
+             success:(void(^)(void))successBlock
+               error:(void(^)(int error_code))errorBlock {
+    mars::stn::joinChatroom([chatroomId UTF8String], new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)quitChatroom:(NSString *)chatroomId
+             success:(void(^)(void))successBlock
+               error:(void(^)(int error_code))errorBlock {
+    mars::stn::quitChatroom([chatroomId UTF8String], new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)getChatroomInfo:(NSString *)chatroomId
+                upateDt:(long long)updateDt
+                success:(void(^)(WFCCChatroomInfo *chatroomInfo))successBlock
+                  error:(void(^)(int error_code))errorBlock {
+    mars::stn::getChatroomInfo([chatroomId UTF8String], updateDt, new IMGetChatroomInfoCallback(chatroomId, successBlock, errorBlock));
+}
+
+- (void)getChatroomMemberInfo:(NSString *)chatroomId
+                     maxCount:(int)maxCount
+                      success:(void(^)(WFCCChatroomMemberInfo *memberInfo))successBlock
+                        error:(void(^)(int error_code))errorBlock {
+    mars::stn::getChatroomMemberInfo([chatroomId UTF8String], 30, new IMGetChatroomMemberInfoCallback(successBlock, errorBlock));
+}
+
+- (void)createChannel:(NSString *)channelName
+             portrait:(NSString *)channelPortrait
+               status:(int)status
+                 desc:(NSString *)desc
+                extra:(NSString *)extra
+              success:(void(^)(WFCCChannelInfo *channelInfo))successBlock
+                error:(void(^)(int error_code))errorBlock {
+    if (!extra) {
+        extra = @"";
+    }
+    mars::stn::createChannel("", [channelName UTF8String], [channelPortrait UTF8String], status, [desc UTF8String], [extra UTF8String], "", "", new IMCreateChannelCallback(successBlock, errorBlock));
+}
+
+- (void)destoryChannel:(NSString *)channelId
+              success:(void(^)(void))successBlock
+                error:(void(^)(int error_code))errorBlock {
+    mars::stn::destoryChannel([channelId UTF8String], new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (WFCCChannelInfo *)getChannelInfo:(NSString *)channelId
+                            refresh:(BOOL)refresh {
+    mars::stn::TChannelInfo tgi = mars::stn::MessageDB::Instance()->GetChannelInfo([channelId UTF8String], refresh);
+    
+    return convertProtoChannelInfo(tgi);
+}
+
+- (void)modifyChannelInfo:(NSString *)channelId
+                     type:(ModifyChannelInfoType)type
+                 newValue:(NSString *)newValue
+                  success:(void(^)(void))successBlock
+                    error:(void(^)(int error_code))errorBlock {
+    mars::stn::modifyChannelInfo([channelId UTF8String], type, [newValue UTF8String], new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (void)searchChannel:(NSString *)keyword success:(void(^)(NSArray<WFCCChannelInfo *> *machedChannels))successBlock error:(void(^)(int errorCode))errorBlock {
+    
+    mars::stn::searchChannel([keyword UTF8String], YES, new IMSearchChannelCallback(successBlock, errorBlock));
+}
+
+- (BOOL)isListenedChannel:(NSString *)channelId {
+    if([@"1" isEqualToString:[self getUserSetting:UserSettingScope_Listened_Channel key:channelId]]) {
+        return YES;
+    }
+    return NO;
+}
+
+- (void)listenChannel:(NSString *)channelId listen:(BOOL)listen success:(void(^)(void))successBlock error:(void(^)(int errorCode))errorBlock {
+    mars::stn::listenChannel([channelId UTF8String], listen, new IMGeneralOperationCallback(successBlock, errorBlock));
+}
+
+- (NSArray<NSString *> *)getMyChannels {
+    NSDictionary *myChannelDict = [[WFCCIMService sharedWFCIMService] getUserSettings:UserSettingScope_My_Channel];
+    NSMutableArray *ids = [[NSMutableArray alloc] init];
+    [myChannelDict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
+        if ([obj isEqualToString:@"1"]) {
+            [ids addObject:key];
+        }
+    }];
+    return ids;
+}
+- (NSArray<NSString *> *)getListenedChannels {
+    NSDictionary *myChannelDict = [[WFCCIMService sharedWFCIMService] getUserSettings:UserSettingScope_Listened_Channel];
+    NSMutableArray *ids = [[NSMutableArray alloc] init];
+    [myChannelDict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
+        if ([obj isEqualToString:@"1"]) {
+            [ids addObject:key];
+        }
+    }];
+    return ids;
+}
+@end

+ 215 - 0
wfclient/WFChatClient/Client/WFCCNetworkService.h

@@ -0,0 +1,215 @@
+//
+//  WFCCNetworkService.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/11/5.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#ifndef WFCCNetworkService_h
+#define WFCCNetworkService_h
+
+#import <Foundation/Foundation.h>
+#import "WFCCMessage.h"
+
+extern const NSString *SDKVERSION;
+#pragma mark - 频道通知定义
+//群组信息更新通知
+extern NSString *kGroupInfoUpdated;
+//用户信息更新通知
+extern NSString *kUserInfoUpdated;
+//好友列表更新通知
+extern NSString *kFriendListUpdated;
+//好友请求信息更新通知
+extern NSString *kFriendRequestUpdated;
+//设置更新通知
+extern NSString *kSettingUpdated;
+//频道信息更新通知
+extern NSString *kChannelInfoUpdated;
+
+#pragma mark - 枚举值定义
+/**
+ 连接状态
+
+ - kConnectionStatusRejected: 被拒绝
+ - kConnectionStatusLogout: 退出登录
+ - kConnectionStatusUnconnected: 未连接
+ - kConnectionStatusConnecting: 连接中
+ - kConnectionStatusConnected: 已连接
+ - kConnectionStatusReceiving: 获取离线消息中,可忽略
+ */
+typedef NS_ENUM(NSInteger, ConnectionStatus) {
+  kConnectionStatusRejected = -3,
+  kConnectionStatusLogout = -2,
+  kConnectionStatusUnconnected = -1,
+  kConnectionStatusConnecting = 0,
+  kConnectionStatusConnected = 1,
+  kConnectionStatusReceiving = 2
+};
+
+#pragma mark - 连接状态&消息监听
+/**
+ 连接状态的监听
+ */
+@protocol ConnectionStatusDelegate <NSObject>
+
+/**
+ 连接状态变化的回调
+
+ @param status 连接状态
+ */
+- (void)onConnectionStatusChanged:(ConnectionStatus)status;
+
+@end
+
+/**
+ 消息接收的监听
+ */
+@protocol ReceiveMessageDelegate <NSObject>
+
+/**
+ 接收消息的回调
+
+ @param messages 收到的消息
+ @param hasMore 是否还有待接受的消息,UI可以根据此参数决定刷新的时机
+ */
+- (void)onReceiveMessage:(NSArray<WFCCMessage *> *)messages hasMore:(BOOL)hasMore;
+
+@optional
+- (void)onRecallMessage:(long long)messageUid;
+@end
+
+/**
+ 接收消息前的拦截Filter
+ */
+@protocol ReceiveMessageFilter <NSObject>
+
+/**
+ 是否拦截收到的消息
+
+ @param message 消息
+ @return 是否拦截,如果拦截该消息,则ReceiveMessageDelegate回调不会再收到此消息
+ */
+- (BOOL)onReceiveMessage:(WFCCMessage *)message;
+@end
+
+#pragma mark - 连接服务
+/**
+ 连接服务
+ */
+@interface WFCCNetworkService : NSObject
+
+/**
+ 连接服务单例
+
+ @return 连接服务单例
+ */
++ (WFCCNetworkService *)sharedInstance;
+
+/**
+ 连接状态监听
+ */
+@property(nonatomic, weak) id<ConnectionStatusDelegate> connectionStatusDelegate;
+
+/**
+ 消息接收监听
+ */
+@property(nonatomic, weak) id<ReceiveMessageDelegate> receiveMessageDelegate;
+
+/**
+ 当前是否处于登陆状态
+ */
+@property(nonatomic, assign, getter=isLogined, readonly)BOOL logined;
+
+/**
+ 当前的连接状态
+ */
+@property(nonatomic, assign, readonly)ConnectionStatus currentConnectionStatus;
+
+/**
+ 当前登陆的用户ID
+ */
+@property (nonatomic, strong, readonly)NSString *userId;
+
+/**
+ 服务器时间与本地时间的差值
+ */
+@property(nonatomic, assign, readonly)long long serverDeltaTime;
+
+/**
+ 开启Log
+ */
++ (void)startLog;
+
+/**
+ 停止Log
+ */
++ (void)stopLog;
+
+/**
+ 获取客户端id
+ 
+ @return 客户端ID
+ */
+- (NSString *)getClientId;
+
+/**
+ 连接服务器
+
+ @param userId 用户Id
+ @param token 密码
+ */
+- (void)connect:(NSString *)userId token:(NSString *)token;
+
+/**
+ 断开连接
+
+ @param clearSession 是否清除Session信息
+ */
+- (void)disconnect:(BOOL)clearSession;
+
+/**
+ 设置服务器信息
+
+ @param host 服务器地址
+ */
+- (void)setServerAddress:(NSString *)host port:(uint)port;
+
+/**
+ 设置当前设备的device token
+
+ @param token 苹果APNs Device Token
+ */
+- (void)setDeviceToken:(NSString *)token;
+
+/**
+ 设置当前设备的Voip device token
+ 
+ @param token 苹果APNs Device Token
+ */
+- (void)setVoipDeviceToken:(NSString *)token;
+
+/**
+ 添加消息拦截Filter
+
+ @param filter 消息拦截Filter
+ */
+- (void)addReceiveMessageFilter:(id<ReceiveMessageFilter>)filter;
+
+/**
+ 移除消息拦截Filter
+
+ @param filter 消息拦截Filter
+ */
+- (void)removeReceiveMessageFilter:(id<ReceiveMessageFilter>)filter;
+
+/**
+ 应用已经login且在后台的情况下,强制进行连接,确保后台连接5秒钟,用于voip推送后台刷新等场景。
+ 应用在前台情况下,此方法无效。
+ */
+- (void)forceConnect:(NSUInteger)second;
+
+- (void)cancelForceConnect;
+@end
+
+#endif

+ 700 - 0
wfclient/WFChatClient/Client/WFCCNetworkService.mm

@@ -0,0 +1,700 @@
+//
+//  WFCCNetworkService.mm
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/11/5.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#include "WFCCNetworkService.h"
+#import <UIKit/UIKit.h>
+#import <SystemConfiguration/SCNetworkReachability.h>
+#import <sys/xattr.h>
+#import <CommonCrypto/CommonDigest.h>
+
+#import "app_callback.h"
+#include <mars/baseevent/base_logic.h>
+#include <mars/xlog/xlogger.h>
+#include <mars/xlog/xloggerbase.h>
+#include <mars/xlog/appender.h>
+#include <mars/proto/proto.h>
+#include <mars/stn/stn_logic.h>
+#include <list>
+#import "WFCCIMService.h"
+#import "WFCCNetworkStatus.h"
+#import "WFCCRecallMessageContent.h"
+
+const NSString *SDKVERSION = @"0.1";
+extern NSMutableArray* convertProtoMessageList(const std::list<mars::stn::TMessage> &messageList, BOOL reverse);
+
+NSString *kGroupInfoUpdated = @"kGroupInfoUpdated";
+NSString *kUserInfoUpdated = @"kUserInfoUpdated";
+NSString *kFriendListUpdated = @"kFriendListUpdated";
+NSString *kFriendRequestUpdated = @"kFriendRequestUpdated";
+NSString *kSettingUpdated = @"kSettingUpdated";
+NSString *kChannelInfoUpdated = @"kChannelInfoUpdated";
+
+@protocol RefreshGroupInfoDelegate <NSObject>
+- (void)onGroupInfoUpdated:(NSArray<WFCCGroupInfo *> *)updatedGroupInfo;
+@end
+
+@protocol RefreshChannelInfoDelegate <NSObject>
+- (void)onChannelInfoUpdated:(NSArray<WFCCChannelInfo *> *)updatedChannelInfo;
+@end
+
+@protocol RefreshUserInfoDelegate <NSObject>
+- (void)onUserInfoUpdated:(NSArray<WFCCUserInfo *> *)updatedUserInfo;
+@end
+
+@protocol RefreshFriendListDelegate <NSObject>
+- (void)onFriendListUpdated;
+@end
+
+@protocol RefreshFriendRequestDelegate <NSObject>
+- (void)onFriendRequestUpdated;
+@end
+
+@protocol RefreshSettingDelegate <NSObject>
+- (void)onSettingUpdated;
+@end
+
+
+
+class CSCB : public mars::stn::ConnectionStatusCallback {
+public:
+  CSCB(id<ConnectionStatusDelegate> delegate) : m_delegate(delegate) {
+  }
+  void onConnectionStatusChanged(mars::stn::ConnectionStatus connectionStatus) {
+    if (m_delegate) {
+      [m_delegate onConnectionStatusChanged:(ConnectionStatus)connectionStatus];
+    }
+  }
+  id<ConnectionStatusDelegate> m_delegate;
+};
+
+
+
+class RPCB : public mars::stn::ReceiveMessageCallback {
+public:
+    RPCB(id<ReceiveMessageDelegate> delegate) : m_delegate(delegate) {}
+    
+    void onReceiveMessage(const std::list<mars::stn::TMessage> &messageList, bool hasMore) {
+        if (m_delegate) {
+            NSMutableArray *messages = convertProtoMessageList(messageList, NO);
+            [m_delegate onReceiveMessage:messages hasMore:hasMore];
+        }
+    }
+    
+    void onRecallMessage(const std::string operatorId, long long messageUid) {
+        if (m_delegate) {
+            [m_delegate onRecallMessage:messageUid];
+        }
+    }
+    id<ReceiveMessageDelegate> m_delegate;
+};
+
+WFCCUserInfo* convertUserInfo(const mars::stn::TUserInfo &tui) {
+    WFCCUserInfo *userInfo = [[WFCCUserInfo alloc] init];
+    userInfo.userId = [NSString stringWithUTF8String:tui.uid.c_str()];
+    userInfo.name = [NSString stringWithUTF8String:tui.name.c_str()];
+    userInfo.portrait = [NSString stringWithUTF8String:tui.portrait.c_str()];
+    
+    userInfo.displayName = [NSString stringWithUTF8String:tui.displayName.c_str()];
+    userInfo.gender = tui.gender;
+    userInfo.social = [NSString stringWithUTF8String:tui.social.c_str()];
+    userInfo.mobile = [NSString stringWithUTF8String:tui.mobile.c_str()];
+    userInfo.email = [NSString stringWithUTF8String:tui.email.c_str()];
+    userInfo.address = [NSString stringWithUTF8String:tui.address.c_str()];
+    userInfo.company = [NSString stringWithUTF8String:tui.company.c_str()];
+    userInfo.social = [NSString stringWithUTF8String:tui.social.c_str()];
+    userInfo.extra = [NSString stringWithUTF8String:tui.extra.c_str()];
+    userInfo.updateDt = tui.updateDt;
+    
+    return userInfo;
+}
+
+NSArray<WFCCUserInfo *>* converUserInfos(const std::list<mars::stn::TUserInfo> &userInfoList) {
+    NSMutableArray *out = [[NSMutableArray alloc] init];
+    for (std::list<mars::stn::TUserInfo>::const_iterator it = userInfoList.begin(); it != userInfoList.end(); it++) {
+        [out addObject:convertUserInfo(*it)];
+    }
+    return out;
+}
+
+WFCCGroupInfo* convertGroupInfo(const mars::stn::TGroupInfo &tgi) {
+    WFCCGroupInfo *groupInfo = [[WFCCGroupInfo alloc] init];
+    groupInfo.type = (WFCCGroupType)tgi.type;
+    groupInfo.target = [NSString stringWithUTF8String:tgi.target.c_str()];
+    groupInfo.name = [NSString stringWithUTF8String:tgi.name.c_str()];
+    groupInfo.extra = [NSData dataWithBytes:tgi.extra.c_str() length:tgi.extra.length()];
+    groupInfo.portrait = [NSString stringWithUTF8String:tgi.portrait.c_str()];
+    groupInfo.owner = [NSString stringWithUTF8String:tgi.owner.c_str()];
+    groupInfo.memberCount = tgi.memberCount;
+    return groupInfo;
+}
+
+extern WFCCChannelInfo *convertProtoChannelInfo(const mars::stn::TChannelInfo &tci);
+
+NSArray<WFCCGroupInfo *>* convertGroupInfos(const std::list<mars::stn::TGroupInfo> &groupInfoList) {
+    NSMutableArray *out = [[NSMutableArray alloc] init];
+    for (std::list<mars::stn::TGroupInfo>::const_iterator it = groupInfoList.begin(); it != groupInfoList.end(); it++) {
+        [out addObject:convertGroupInfo(*it)];
+    }
+    return out;
+}
+NSArray<WFCCChannelInfo *>* convertChannelInfos(const std::list<mars::stn::TChannelInfo> &channelInfoList) {
+    NSMutableArray *out = [[NSMutableArray alloc] init];
+    for (std::list<mars::stn::TChannelInfo>::const_iterator it = channelInfoList.begin(); it != channelInfoList.end(); it++) {
+        [out addObject:convertProtoChannelInfo(*it)];
+    }
+    return out;
+}
+
+class GUCB : public mars::stn::GetUserInfoCallback {
+  public:
+  GUCB(id<RefreshUserInfoDelegate> delegate) : m_delegate(delegate) {}
+  
+  void onSuccess(const std::list<mars::stn::TUserInfo> &userInfoList) {
+      if(m_delegate) {
+          [m_delegate onUserInfoUpdated:converUserInfos(userInfoList)];
+      }
+  }
+  void onFalure(int errorCode) {
+    
+  }
+  id<RefreshUserInfoDelegate> m_delegate;
+};
+
+class GGCB : public mars::stn::GetGroupInfoCallback {
+  public:
+  GGCB(id<RefreshGroupInfoDelegate> delegate) : m_delegate(delegate) {}
+  
+  void onSuccess(const std::list<mars::stn::TGroupInfo> &groupInfoList) {
+      if(m_delegate && !groupInfoList.empty()) {
+          [m_delegate onGroupInfoUpdated:convertGroupInfos(groupInfoList)];
+      }
+  }
+  void onFalure(int errorCode) {
+  }
+  id<RefreshGroupInfoDelegate> m_delegate;
+};
+
+class GCHCB : public mars::stn::GetChannelInfoCallback {
+public:
+    GCHCB(id<RefreshChannelInfoDelegate> delegate) : m_delegate(delegate) {}
+    
+    void onSuccess(const std::list<mars::stn::TChannelInfo> &channelInfoList) {
+        if(m_delegate && !channelInfoList.empty()) {
+            [m_delegate onChannelInfoUpdated:convertChannelInfos(channelInfoList)];
+        }
+    }
+    void onFalure(int errorCode) {
+    }
+    id<RefreshChannelInfoDelegate> m_delegate;
+};
+
+class GFLCB : public mars::stn::GetMyFriendsCallback {
+public:
+    GFLCB(id<RefreshFriendListDelegate> delegate) : m_delegate(delegate) {}
+    void onSuccess(std::list<std::string> friendIdList) {
+        if(m_delegate && friendIdList.size() > 0) {
+            [m_delegate onFriendListUpdated];
+        }
+    }
+    void onFalure(int errorCode) {
+        
+    }
+    id<RefreshFriendListDelegate> m_delegate;
+};
+
+class GFRCB : public mars::stn::GetFriendRequestCallback {
+public:
+    GFRCB(id<RefreshFriendRequestDelegate> delegate) : m_delegate(delegate) {}
+    void onSuccess(bool hasNewRequest) {
+        if(m_delegate && hasNewRequest) {
+            [m_delegate onFriendRequestUpdated];
+        }
+    }
+    void onFalure(int errorCode) {
+        
+    }
+    id<RefreshFriendRequestDelegate> m_delegate;
+};
+
+class GSCB : public mars::stn::GetSettingCallback {
+public:
+  GSCB(id<RefreshSettingDelegate> delegate) : m_delegate(delegate) {}
+  void onSuccess(bool hasNewRequest) {
+    if(m_delegate && hasNewRequest) {
+      [m_delegate onSettingUpdated];
+    }
+  }
+  void onFalure(int errorCode) {
+    
+  }
+  id<RefreshSettingDelegate> m_delegate;
+};
+
+
+
+@interface WFCCNetworkService () <ConnectionStatusDelegate, ReceiveMessageDelegate, RefreshUserInfoDelegate, RefreshGroupInfoDelegate, WFCCNetworkStatusDelegate, RefreshFriendListDelegate, RefreshFriendRequestDelegate, RefreshSettingDelegate, RefreshChannelInfoDelegate>
+@property(nonatomic, assign)ConnectionStatus currentConnectionStatus;
+@property (nonatomic, strong)NSString *userId;
+@property (nonatomic, strong)NSString *passwd;
+
+@property(nonatomic, strong)NSString *serverHost;
+@property(nonatomic, assign)int serverPort;
+
+@property(nonatomic, assign)UIBackgroundTaskIdentifier bgTaskId;
+@property(nonatomic, strong)NSTimer *forceConnectTimer;
+@property(nonatomic, strong)NSTimer *suspendTimer;
+@property(nonatomic, strong)NSTimer *endBgTaskTimer;
+@property(nonatomic, strong)NSString *backupDeviceToken;
+@property(nonatomic, strong)NSString *backupVoipDeviceToken;
+
+@property(nonatomic, assign)BOOL requestProxying;
+@property(nonatomic, strong) NSMutableArray *messageFilterList;
+- (void)reportEvent_OnForeground:(BOOL)isForeground;
+
+@property(nonatomic, assign)NSUInteger backgroudRunTime;
+@end
+
+@implementation WFCCNetworkService
+
+static WFCCNetworkService * sharedSingleton = nil;
++ (void)startLog {
+    NSString* logPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingString:@"/log"];
+    
+    // set do not backup for logpath
+    const char* attrName = "com.apple.MobileBackup";
+    u_int8_t attrValue = 1;
+    setxattr([logPath UTF8String], attrName, &attrValue, sizeof(attrValue), 0, 0);
+    
+    // init xlog
+#if DEBUG
+    xlogger_SetLevel(kLevelVerbose);
+    appender_set_console_log(true);
+#else
+    xlogger_SetLevel(kLevelInfo);
+    appender_set_console_log(false);
+#endif
+    appender_open(kAppednerAsync, [logPath UTF8String], "Test", NULL);
+}
+
++ (void)stopLog {
+    appender_close();
+}
+
+- (void)onRecallMessage:(long long)messageUid {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [[NSNotificationCenter defaultCenter] postNotificationName:kRecallMessages object:@(messageUid)];
+        if ([self.receiveMessageDelegate respondsToSelector:@selector(onRecallMessage:)]) {
+            [self.receiveMessageDelegate onRecallMessage:messageUid];
+        }
+    });
+}
+
+- (void)onReceiveMessage:(NSArray<WFCCMessage *> *)messages hasMore:(BOOL)hasMore {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        NSMutableArray *messageList = [messages mutableCopy];
+        for (WFCCMessage *message in messages) {
+            for (id<ReceiveMessageFilter> filter in self.messageFilterList) {
+                if ([filter onReceiveMessage:message]) {
+                    [messageList removeObject:message];
+                    break;
+                }
+            }
+        }
+        
+        [[NSNotificationCenter defaultCenter] postNotificationName:kReceiveMessages object:messages];
+        [self.receiveMessageDelegate onReceiveMessage:messageList hasMore:hasMore];
+    });
+}
+
+- (void)addReceiveMessageFilter:(id<ReceiveMessageFilter>)filter {
+    [self.messageFilterList addObject:filter];
+}
+
+- (void)removeReceiveMessageFilter:(id<ReceiveMessageFilter>)filter {
+    [self.messageFilterList removeObject:filter];
+}
+
+- (void)onDisconnected {
+  mars::baseevent::OnDestroy();
+}
+
+- (void)setCurrentConnectionStatus:(ConnectionStatus)currentConnectionStatus {
+    NSLog(@"Connection status changed to (%ld)", (long)currentConnectionStatus);
+    if (_currentConnectionStatus != currentConnectionStatus) {
+        _currentConnectionStatus = currentConnectionStatus;
+        
+        [[NSNotificationCenter defaultCenter] postNotificationName:kConnectionStatusChanged object:@(_currentConnectionStatus)];
+        
+        if (_connectionStatusDelegate) {
+            [_connectionStatusDelegate onConnectionStatusChanged:currentConnectionStatus];
+        }
+    }
+}
+- (void)onConnectionStatusChanged:(ConnectionStatus)status {
+  if (!_logined || kConnectionStatusRejected == status) {
+    dispatch_async(dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
+      [self disconnect:YES];
+    });
+    return;
+  }
+    if((int)status == (int)mars::stn::kConnectionStatusServerDown) {
+        status = kConnectionStatusUnconnected;
+    }
+  dispatch_async(dispatch_get_main_queue(), ^{
+    self.currentConnectionStatus = status;
+    if (status == kConnectionStatusConnected) {
+        if (self.backupDeviceToken.length) {
+            [self setDeviceToken:self.backupDeviceToken];
+        }
+        
+        if (self.backupVoipDeviceToken.length) {
+            [self setVoipDeviceToken:self.backupVoipDeviceToken];
+        }
+    }
+  });
+    
+}
+
++ (WFCCNetworkService *)sharedInstance {
+    if (sharedSingleton == nil) {
+        @synchronized (self) {
+            if (sharedSingleton == nil) {
+                sharedSingleton = [[WFCCNetworkService alloc] init];
+            }
+        }
+    }
+    
+    return sharedSingleton;
+}
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        _currentConnectionStatus = kConnectionStatusLogout;
+        _messageFilterList = [[NSMutableArray alloc] init];
+      
+      [[NSNotificationCenter defaultCenter] addObserver:self
+                                               selector:@selector(onAppSuspend)
+                                                   name:UIApplicationDidEnterBackgroundNotification
+                                                 object:nil];
+      [[NSNotificationCenter defaultCenter] addObserver:self
+                                               selector:@selector(onAppResume)
+                                                   name:UIApplicationWillEnterForegroundNotification
+                                                 object:nil];
+      [[NSNotificationCenter defaultCenter] addObserver:self
+                                               selector:@selector(onAppTerminate)
+                                                   name:UIApplicationWillTerminateNotification
+                                                 object:nil];
+    }
+    return self;
+}
+
+- (void)startBackgroundTask {
+    if (!_logined) {
+        return;
+    }
+    
+    if (_bgTaskId !=  UIBackgroundTaskInvalid) {
+        [[UIApplication sharedApplication] endBackgroundTask:_bgTaskId];
+    }
+    _bgTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
+        if (_suspendTimer) {
+            [_suspendTimer invalidate];
+            _suspendTimer = nil;
+        }
+        
+        if(_endBgTaskTimer) {
+            [_endBgTaskTimer invalidate];
+            _endBgTaskTimer = nil;
+        }
+        if(_forceConnectTimer) {
+            [_forceConnectTimer invalidate];
+            _forceConnectTimer = nil;
+        }
+        
+        _bgTaskId = UIBackgroundTaskInvalid;
+    }];
+}
+
+- (void)onAppSuspend {
+    if (!_logined) {
+        return;
+    }
+    
+    [self reportEvent_OnForeground:NO];
+    
+    
+    self.backgroudRunTime = 0;
+    [self startBackgroundTask];
+    
+    [self checkBackGroundTask];
+}
+
+- (void)checkBackGroundTask {
+    if(_suspendTimer) {
+        [_suspendTimer invalidate];
+    }
+    if(_endBgTaskTimer) {
+        [_endBgTaskTimer invalidate];
+        _endBgTaskTimer = nil;
+    }
+    
+    NSTimeInterval timeInterval = 3;
+    
+    _suspendTimer = [NSTimer scheduledTimerWithTimeInterval:timeInterval
+                                                     target:self
+                                                   selector:@selector(suspend)
+                                                   userInfo:nil
+                                                    repeats:NO];
+
+}
+- (void)suspend {
+  if(_bgTaskId != UIBackgroundTaskInvalid) {
+      self.backgroudRunTime += 3;
+      if (mars::stn::GetTaskCount() > 0 && self.backgroudRunTime < 60) {
+          [self checkBackGroundTask];
+      } else {
+    mars::stn::Reset();
+    _endBgTaskTimer = [NSTimer scheduledTimerWithTimeInterval:1
+                                                       target:self
+                                                     selector:@selector(endBgTask)
+                                                     userInfo:nil
+                                                      repeats:NO];
+      }
+  }
+}
+- (void)endBgTask {
+  if(_bgTaskId !=  UIBackgroundTaskInvalid) {
+    [[UIApplication sharedApplication] endBackgroundTask:_bgTaskId];
+    _bgTaskId =  UIBackgroundTaskInvalid;
+  }
+  
+  if (_suspendTimer) {
+    [_suspendTimer invalidate];
+    _suspendTimer = nil;
+  }
+  
+  if(_endBgTaskTimer) {
+    [_endBgTaskTimer invalidate];
+    _endBgTaskTimer = nil;
+  }
+    
+    if (_forceConnectTimer) {
+        [_forceConnectTimer invalidate];
+        _forceConnectTimer = nil;
+    }
+    
+    self.backgroudRunTime = 0;
+}
+
+- (void)onAppResume {
+  if (!_logined) {
+    return;
+  }
+  [self reportEvent_OnForeground:YES];
+  mars::stn::MakesureLonglinkConnected();
+  [self endBgTask];
+}
+
+- (void)onAppTerminate {
+  
+}
+
+- (void)dealloc {
+    
+}
+
+- (void) createMars {
+  mars::app::SetCallback(mars::app::AppCallBack::Instance());
+  mars::stn::setConnectionStatusCallback(new CSCB(self));
+  mars::stn::setReceiveMessageCallback(new RPCB(self));
+  mars::stn::setRefreshUserInfoCallback(new GUCB(self));
+  mars::stn::setRefreshGroupInfoCallback(new GGCB(self));
+  mars::stn::setRefreshChannelInfoCallback(new GCHCB(self));
+  mars::stn::setRefreshFriendListCallback(new GFLCB(self));
+    mars::stn::setRefreshFriendRequestCallback(new GFRCB(self));
+  mars::stn::setRefreshSettingCallback(new GSCB(self));
+  mars::baseevent::OnCreate();
+}
+- (void)connect:(NSString *)host port:(int)port {
+    mars::stn::Connect([host UTF8String], port);
+    
+  dispatch_async(dispatch_get_main_queue(), ^{
+    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
+      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
+          [self onAppSuspend];
+        }
+      });
+    }
+  });
+}
+
+- (void)forceConnectTimeOut {
+    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
+        [self onAppSuspend];
+    }
+}
+
+- (void)forceConnect:(NSUInteger)second {
+  dispatch_async(dispatch_get_main_queue(), ^{
+    if (_logined &&[UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
+        [self onAppResume];
+        [self startBackgroundTask];
+        _forceConnectTimer = [NSTimer scheduledTimerWithTimeInterval:second
+                                                         target:self
+                                                       selector:@selector(forceConnectTimeOut)
+                                                       userInfo:nil
+                                                        repeats:NO];
+    }
+  });
+}
+
+- (void)cancelForceConnect {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        if (_forceConnectTimer) {
+            [_forceConnectTimer invalidate];
+            _forceConnectTimer = nil;
+        }
+    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
+        [self onAppSuspend];
+    }
+    });
+}
+
+- (long long)serverDeltaTime {
+    return mars::stn::getServerDeltaTime();
+}
+
+- (NSString *)getClientId {
+    return [UIDevice currentDevice].identifierForVendor.UUIDString;
+}
+
+- (void)connect:(NSString *)userId token:(NSString *)token {
+  _logined = YES;
+    mars::app::AppCallBack::Instance()->SetAccountUserName([userId UTF8String]);
+    [self createMars];
+    self.userId = userId;
+    self.passwd = token;
+    mars::stn::setAuthInfo([userId cStringUsingEncoding:NSUTF8StringEncoding], [token cStringUsingEncoding:NSUTF8StringEncoding]);
+    
+    self.currentConnectionStatus = kConnectionStatusConnecting;
+    [[WFCCNetworkStatus sharedInstance] Start:[WFCCNetworkService sharedInstance]];
+    
+    [self connect:self.serverHost port:self.serverPort];
+}
+
+- (void)disconnect:(BOOL)clearSession {
+  _logined = NO;
+    self.userId = nil;
+    self.currentConnectionStatus = kConnectionStatusLogout;
+    [[WFCCNetworkStatus sharedInstance] Stop];
+  if (mars::stn::getConnectionStatus() != mars::stn::kConnectionStatusConnected && mars::stn::getConnectionStatus() != mars::stn::kConnectionStatusReceiving) {
+    [self destroyMars];
+  } else {
+    mars::stn::Disconnect(clearSession ? 8 : 0);
+  }
+}
+
+- (void)setServerAddress:(NSString *)host port:(uint)port {
+    self.serverHost = host;
+    self.serverPort = port;
+}
+
+
+- (void)destroyMars {
+  [[WFCCNetworkStatus sharedInstance] Stop];
+    mars::baseevent::OnDestroy();
+}
+
+
+// event reporting
+- (void)reportEvent_OnForeground:(BOOL)isForeground {
+    mars::baseevent::OnForeground(isForeground);
+}
+
+- (void)setDeviceToken:(NSString *)token {
+  if (token.length == 0) {
+    return;
+  }
+  
+  if (!self.isLogined || self.currentConnectionStatus != kConnectionStatusConnected) {
+    self.backupDeviceToken = token;
+    return;
+  }
+  
+    NSString *appName =
+    [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
+    mars::stn::setDeviceToken([appName UTF8String], [token UTF8String], mars::app::AppCallBack::Instance()->GetPushType());
+}
+
+- (void)setVoipDeviceToken:(NSString *)token {
+    if (token.length == 0) {
+        return;
+    }
+    
+    if (!self.isLogined || self.currentConnectionStatus != kConnectionStatusConnected) {
+        self.backupVoipDeviceToken = token;
+        return;
+    }
+    
+    NSString *appName =
+    [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
+    mars::stn::setDeviceToken([appName UTF8String], [token UTF8String], 2);
+}
+
+- (void)onGroupInfoUpdated:(NSArray<WFCCGroupInfo *> *)updatedGroupInfo {
+  dispatch_async(dispatch_get_main_queue(), ^{
+    for (WFCCGroupInfo *groupInfo in updatedGroupInfo) {
+      [[NSNotificationCenter defaultCenter] postNotificationName:kGroupInfoUpdated object:groupInfo.target userInfo:@{@"groupInfo":groupInfo}];
+    }
+  });
+}
+
+- (void)onChannelInfoUpdated:(NSArray<WFCCChannelInfo *> *)updatedChannelInfo {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        for (WFCCChannelInfo *channelInfo in updatedChannelInfo) {
+            [[NSNotificationCenter defaultCenter] postNotificationName:kChannelInfoUpdated object:channelInfo.channelId userInfo:@{@"channelInfo":channelInfo}];
+        }
+    });
+}
+
+- (void)onUserInfoUpdated:(NSArray<WFCCUserInfo *> *)updatedUserInfo {
+  dispatch_async(dispatch_get_main_queue(), ^{
+    for (WFCCUserInfo *userInfo in updatedUserInfo) {
+      [[NSNotificationCenter defaultCenter] postNotificationName:kUserInfoUpdated object:userInfo.userId userInfo:@{@"userInfo":userInfo}];
+    }
+  });
+}
+
+- (void)onFriendListUpdated {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [[NSNotificationCenter defaultCenter] postNotificationName:kFriendListUpdated object:nil];
+    });
+}
+
+- (void)onFriendRequestUpdated {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [[NSNotificationCenter defaultCenter] postNotificationName:kFriendRequestUpdated object:nil];
+    });
+}
+
+- (void)onSettingUpdated {
+  dispatch_async(dispatch_get_main_queue(), ^{
+    [[NSNotificationCenter defaultCenter] postNotificationName:kSettingUpdated object:nil];
+  });
+}
+#pragma mark WFCCNetworkStatusDelegate
+-(void) ReachabilityChange:(UInt32)uiFlags {
+    if ((uiFlags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) {
+        mars::baseevent::OnNetworkChange();
+    }
+}
+
+@end
+

+ 29 - 0
wfclient/WFChatClient/Client/WFCCNetworkStatus.h

@@ -0,0 +1,29 @@
+//
+//  WFCCNetworkStatus.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/11/5.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <SystemConfiguration/SCNetworkReachability.h>
+
+@protocol WFCCNetworkStatusDelegate
+
+-(void) ReachabilityChange:(UInt32)uiFlags;
+
+@end
+
+@interface WFCCNetworkStatus : NSObject {
+	__unsafe_unretained id<WFCCNetworkStatusDelegate> m_delWFCNetworkStatus;
+}
+
++ (WFCCNetworkStatus*)sharedInstance;
+
+-(void) Start:(__unsafe_unretained id<WFCCNetworkStatusDelegate>)delWFCNetworkStatus;
+-(void) Stop;
+-(void) ChangeReach;
+- (SCNetworkConnectionFlags)connFlags;
+- (bool)isConnectionAvaible;
+@end

+ 102 - 0
wfclient/WFChatClient/Client/WFCCNetworkStatus.m

@@ -0,0 +1,102 @@
+//
+//  WFCCNetworkStatus.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/11/5.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNetworkStatus.h"
+
+#import <Foundation/Foundation.h>
+#import <SystemConfiguration/CaptiveNetwork.h>
+#import <SystemConfiguration/SCNetworkReachability.h>
+#import <netinet/in.h>
+
+SCNetworkReachabilityRef g_Reach = nil;
+
+static void ReachCallback(SCNetworkReachabilityRef target, SCNetworkConnectionFlags flags, void* info)
+{
+    @autoreleasepool {
+        [(__bridge id)info performSelector:@selector(ChangeReach)];
+    }
+}
+
+@implementation WFCCNetworkStatus
+
+static WFCCNetworkStatus * sharedSingleton = nil;
+
++ (WFCCNetworkStatus*)sharedInstance {
+    @synchronized (self) {
+        if (sharedSingleton == nil) {
+            sharedSingleton = [[WFCCNetworkStatus alloc] init];
+        }
+    }
+    
+    return sharedSingleton;
+}
+
+-(void) Start:(__unsafe_unretained id<WFCCNetworkStatusDelegate>)delWFCNetworkStatus {
+    
+    m_delWFCNetworkStatus = delWFCNetworkStatus;
+    
+    if (g_Reach == nil) {
+        struct sockaddr_in zeroAddress;
+        bzero(&zeroAddress, sizeof(zeroAddress));
+        zeroAddress.sin_len = sizeof(zeroAddress);
+        zeroAddress.sin_family = AF_INET;
+        g_Reach = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr *)&zeroAddress);
+    }
+
+  
+    SCNetworkReachabilityContext context = {0, (__bridge void *)self, NULL, NULL, NULL};
+    if(SCNetworkReachabilitySetCallback(g_Reach, ReachCallback, &context)) {
+        if(!SCNetworkReachabilityScheduleWithRunLoop(g_Reach, CFRunLoopGetCurrent(), kCFRunLoopCommonModes)) {
+
+            SCNetworkReachabilitySetCallback(g_Reach, NULL, NULL);
+            return;
+        }
+    }
+    
+
+    
+}
+
+-(void) Stop {
+    if(g_Reach != nil) {
+        SCNetworkReachabilitySetCallback(g_Reach, NULL, NULL);
+        SCNetworkReachabilityUnscheduleFromRunLoop(g_Reach, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
+        CFRelease(g_Reach);
+        g_Reach = nil;
+    }
+
+    m_delWFCNetworkStatus = nil;
+}
+
+- (bool)isConnectionAvaible {
+    SCNetworkConnectionFlags connFlags = [self connFlags];
+    return (connFlags & kSCNetworkFlagsReachable) || (connFlags & kSCNetworkFlagsConnectionRequired);
+}
+
+- (SCNetworkConnectionFlags)connFlags {
+    SCNetworkConnectionFlags connFlags;
+    
+    
+    if(g_Reach == nil || !SCNetworkReachabilityGetFlags(g_Reach, &connFlags)) {
+        return 0;
+    }
+    return connFlags;
+}
+
+-(void) ChangeReach {
+    
+    SCNetworkConnectionFlags connFlags = [self connFlags];
+   
+    if(m_delWFCNetworkStatus != nil && connFlags != 0) {
+        [m_delWFCNetworkStatus ReachabilityChange:connFlags];
+    }
+
+
+}
+
+@end

+ 51 - 0
wfclient/WFChatClient/Client/app_callback.h

@@ -0,0 +1,51 @@
+//
+//  app_callback.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/11/5.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#ifndef appcomm_callback_h
+#define appcomm_callback_h
+
+#import <mars/app/app.h>
+#import <mars/app/app_logic.h>
+
+namespace mars {
+    namespace app {
+
+
+class AppCallBack : public Callback {
+    
+private:
+    AppCallBack();
+    ~AppCallBack() {}
+    AppCallBack(AppCallBack&);
+    AppCallBack& operator = (AppCallBack&);
+    std::string filePath;
+    AccountInfo info;
+    
+public:
+    static AppCallBack* Instance();
+    static void Release();
+    
+    int GetPushType();
+    virtual std::string GetAppFilePath();
+    
+    virtual AccountInfo GetAccountInfo();
+    
+    virtual void SetAccountUserName(const std::string &userName);
+    virtual void SetAccountLogoned(bool isLogoned);
+    
+    virtual unsigned int GetClientVersion();
+    
+    virtual DeviceInfo GetDeviceInfo();
+    
+private:
+    static AppCallBack* instance_;
+};
+        
+}}
+
+#endif /* appcomm_callback_h */

+ 126 - 0
wfclient/WFChatClient/Client/app_callback.mm

@@ -0,0 +1,126 @@
+//
+//  app_callback.mm
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/11/5.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#include "app_callback.h"
+
+#include <mars/comm/autobuffer.h>
+#import <UIKit/UIKit.h>
+#import "WFCCUtilities.h"
+#import "sys/utsname.h"
+#import "WFCCNetworkService.h"
+#import <CoreTelephony/CTCarrier.h>
+#import <CoreTelephony/CTTelephonyNetworkInfo.h>
+
+namespace mars {
+    namespace app {
+
+AppCallBack* AppCallBack::instance_ = NULL;
+
+AppCallBack* AppCallBack::Instance() {
+    if(instance_ == NULL) {
+        instance_ = new AppCallBack();
+    }
+    
+    return instance_;
+}
+
+void AppCallBack::Release() {
+    delete instance_;
+    instance_ = NULL;
+}
+        
+    AppCallBack::AppCallBack() {
+        
+        
+    }
+
+        
+        void AppCallBack::SetAccountUserName(const std::string &userName) {
+            info.username = userName;
+            
+            NSString *path = [WFCCUtilities getDocumentPathWithComponent:[NSString stringWithUTF8String:info.username.c_str()]];
+            filePath = [path UTF8String];
+        }
+        
+        void AppCallBack::SetAccountLogoned(bool isLogoned) {
+            info.is_logoned = isLogoned;
+        }
+        
+// return your app path
+std::string AppCallBack::GetAppFilePath(){
+    return filePath;
+}
+        
+AccountInfo AppCallBack::GetAccountInfo() {
+    return info;
+}
+
+unsigned int AppCallBack::GetClientVersion() {
+    
+    return 0;
+}
+
+static BOOL PSPDFIsDevelopmentBuild() {
+#if TARGET_IPHONE_SIMULATOR
+    return YES;
+#else
+    static BOOL isDevelopment = NO;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        // There is no provisioning profile in AppStore Apps.
+        NSData *data = [NSData dataWithContentsOfFile:[NSBundle.mainBundle pathForResource:@"embedded" ofType:@"mobileprovision"]];
+        if (data) {
+            const char *bytes = (const char *)[data bytes];
+            NSMutableString *profile = [[NSMutableString alloc] initWithCapacity:data.length];
+            for (NSUInteger i = 0; i < data.length; i++) {
+                [profile appendFormat:@"%c", bytes[i]];
+            }
+            // Look for debug value, if detected we're a development build.
+            NSString *cleared = [[profile componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet] componentsJoinedByString:@""];
+            isDevelopment = [cleared rangeOfString:@"<key>get-task-allow</key><true/>"].length > 0;
+        }
+    });
+    return isDevelopment;
+#endif
+}
+        
+int AppCallBack::GetPushType() {
+    return PSPDFIsDevelopmentBuild() ? 1 : 0;
+}
+        
+DeviceInfo AppCallBack::GetDeviceInfo() {
+    DeviceInfo info;
+    struct utsname systemInfo;
+    uname(&systemInfo);
+    NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
+
+    
+    info.clientid = [[UIDevice currentDevice].identifierForVendor.UUIDString cStringUsingEncoding:NSUTF8StringEncoding];
+    info.platform = PlatformType_iOS;
+    
+    info.packagename = [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"] UTF8String];
+    info.pushtype = mars::app::AppCallBack::Instance()->GetPushType();
+    info.device = [deviceString UTF8String];
+    info.deviceversion = [[UIDevice currentDevice].systemVersion UTF8String];
+    info.phonename = [[UIDevice currentDevice].name UTF8String];
+    
+    NSArray *languages = [NSLocale preferredLanguages];
+    NSString *currentLanguage = [languages objectAtIndex:0];
+    info.language = [currentLanguage UTF8String];
+    
+    CTTelephonyNetworkInfo *nwinfo = [[CTTelephonyNetworkInfo alloc] init];
+    CTCarrier *carrier = nwinfo.subscriberCellularProvider;
+    info.carriername = carrier.carrierName ? [carrier.carrierName UTF8String] : "";
+    
+    info.appversion = [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] UTF8String];
+    info.sdkversion = [SDKVERSION UTF8String];
+    
+    return info;
+}
+
+}}

+ 24 - 0
wfclient/WFChatClient/Info.plist

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>FMWK</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>$(CURRENT_PROJECT_VERSION)</string>
+	<key>NSPrincipalClass</key>
+	<string></string>
+</dict>
+</plist>

+ 26 - 0
wfclient/WFChatClient/Messages/WFCCAddGroupeMemberNotificationContent.h

@@ -0,0 +1,26 @@
+//
+//  WFCCAddGroupeMemberNotificationContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 群组加人的通知消息
+ */
+@interface WFCCAddGroupeMemberNotificationContent : WFCCNotificationMessageContent
+
+/**
+ 邀请者ID
+ */
+@property (nonatomic, strong)NSString *invitor;
+
+/**
+ 被邀请者ID列表
+ */
+@property (nonatomic, strong)NSArray<NSString *> *invitees;
+
+@end

+ 92 - 0
wfclient/WFChatClient/Messages/WFCCAddGroupeMemberNotificationContent.m

@@ -0,0 +1,92 @@
+//
+//  WFCCAddGroupeMemberNotificationContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCAddGroupeMemberNotificationContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+
+@implementation WFCCAddGroupeMemberNotificationContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.invitor) {
+        [dataDict setObject:self.invitor forKey:@"o"];
+    }
+    if (self.invitees) {
+        [dataDict setObject:self.invitees forKey:@"ms"];
+    }
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.invitor = dictionary[@"o"];
+        self.invitees = dictionary[@"ms"];
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_ADD_GROUP_MEMBER;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [self formatNotification];
+}
+
+- (NSString *)formatNotification {
+    NSString *formatMsg;
+    if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.invitor]) {
+        formatMsg = @"你邀请";
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.invitor refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            formatMsg = [NSString stringWithFormat:@"%@邀请", userInfo.displayName];
+        } else {
+            formatMsg = [NSString stringWithFormat:@"%@邀请", self.invitor];
+        }
+    }
+    
+    for (NSString *member in self.invitees) {
+        if ([member isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
+            formatMsg = [formatMsg stringByAppendingString:@" 你"];
+        } else {
+            WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:member refresh:NO];
+            if (userInfo.displayName.length > 0) {
+                formatMsg = [formatMsg stringByAppendingFormat:@" %@", userInfo.displayName];
+            } else {
+                formatMsg = [formatMsg stringByAppendingFormat:@" %@", member];
+            }
+        }
+    }
+    formatMsg = [formatMsg stringByAppendingString:@"加入了群聊"];
+    return formatMsg;
+}
+@end

+ 52 - 0
wfclient/WFChatClient/Messages/WFCCCallStartMessageContent.h

@@ -0,0 +1,52 @@
+//
+//  WFCCTextMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMessageContent.h"
+
+/**
+ 电话总结消息
+ */
+@interface WFCCCallStartMessageContent : WFCCMessageContent
+
+
+/**
+ CallId
+ */
+@property (nonatomic, strong)NSString *callId;
+/**
+ 对端用户Id
+ */
+@property (nonatomic, strong)NSString *targetId;
+/**
+ * 开始时间
+ */
+@property (nonatomic, assign)long long connectTime;
+/**
+ * 结束时间
+ */
+@property (nonatomic, assign)long long endTime;
+/* 结束原因
+WFAVCallEndReason
+ 0: kWFAVCallEndReasonUnknown,
+ 1: kWFAVCallEndReasonBusy,
+ 2: kWFAVCallEndReasonSignalError,
+ 3: kWFAVCallEndReasonHangup,
+ 4: kWFAVCallEndReasonMediaError,
+ 5: kWFAVCallEndReasonRemoteHangup,
+ 6: kWFAVCallEndReasonOpenCameraFailure,
+ 7: kWFAVCallEndReasonTimeout,
+ 8: kWFAVCallEndReasonAcceptByOtherClient
+ */
+@property (nonatomic, assign)int status;
+
+/*
+ * 是否仅音频
+ */
+@property (nonatomic, assign, getter=isAudioOnly)BOOL audioOnly;
+
+@end

+ 74 - 0
wfclient/WFChatClient/Messages/WFCCCallStartMessageContent.m

@@ -0,0 +1,74 @@
+//
+//  WFCCTextMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCCallStartMessageContent.h"
+#import "WFCCIMService.h"
+#import "Common.h"
+
+
+@implementation WFCCCallStartMessageContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.content = self.callId;
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.connectTime) {
+        [dataDict setObject:@(self.connectTime) forKey:@"c"];
+    }
+    if (self.endTime) {
+        [dataDict setObject:@(self.endTime) forKey:@"e"];
+    }
+    if (self.status) {
+        [dataDict setObject:@(self.status) forKey:@"s"];
+    }
+    
+    [dataDict setObject:self.targetId forKey:@"t"];
+    [dataDict setValue:@(self.audioOnly?1:0) forKey:@"a"];
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    self.callId = payload.content;
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.connectTime = dictionary[@"c"] ? [dictionary[@"c"] longLongValue] : 0;
+        self.endTime = dictionary[@"e"] ? [dictionary[@"e"] longLongValue] : 0;
+        self.status = dictionary[@"s"] ? [dictionary[@"s"] intValue] : 0;
+        self.audioOnly = [dictionary[@"a"] intValue] ? YES : NO;
+        self.targetId = dictionary[@"t"];
+    }
+}
+
++ (int)getContentType {
+    return VOIP_CONTENT_TYPE_START;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    if (_audioOnly) {
+        return @"[语音通话]";
+    } else {
+        return @"[视频通话]";
+    }
+}
+@end

+ 26 - 0
wfclient/WFChatClient/Messages/WFCCChangeGroupNameNotificationContent.h

@@ -0,0 +1,26 @@
+//
+//  WFCCChangeGroupNameNotificationContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 修改群名的通知消息
+ */
+@interface WFCCChangeGroupNameNotificationContent : WFCCNotificationMessageContent
+
+/**
+ 操作者ID
+ */
+@property (nonatomic, strong)NSString *operateUser;
+
+/**
+ 群名
+ */
+@property (nonatomic, strong)NSString *name;
+
+@end

+ 84 - 0
wfclient/WFChatClient/Messages/WFCCChangeGroupNameNotificationContent.m

@@ -0,0 +1,84 @@
+//
+//  WFCCChangeGroupNameNotificationContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCChangeGroupNameNotificationContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+@implementation WFCCChangeGroupNameNotificationContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.operateUser) {
+        [dataDict setObject:self.operateUser forKey:@"o"];
+    }
+    if (self.name) {
+        [dataDict setObject:self.name forKey:@"n"];
+    }
+    
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.operateUser = dictionary[@"o"];
+        self.name = dictionary[@"n"];
+        if (self.name == nil) {
+            self.name = @"";
+        }
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_CHANGE_GROUP_NAME;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [self formatNotification];
+}
+
+- (NSString *)formatNotification {
+    NSString *formatMsg;
+    if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.operateUser]) {
+        formatMsg = [NSString stringWithFormat:@"你修改群名称为:%@", self.name];
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.operateUser refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            formatMsg = [NSString stringWithFormat:@"%@修改群名称为:", userInfo.displayName];
+        } else {
+            formatMsg = [NSString stringWithFormat:@"%@修改群名称为:", self.operateUser];
+        }
+        
+        formatMsg = [formatMsg stringByAppendingString:self.name];
+    }
+    
+    return formatMsg;
+}
+@end

+ 21 - 0
wfclient/WFChatClient/Messages/WFCCChangeGroupPortraitNotificationContent.h

@@ -0,0 +1,21 @@
+//
+//  WFCCChangeGroupNameNotificationContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 修改群头像的通知消息
+ */
+@interface WFCCChangeGroupPortraitNotificationContent : WFCCNotificationMessageContent
+
+/**
+ 操作者ID
+ */
+@property (nonatomic, strong)NSString *operateUser;
+
+@end

+ 75 - 0
wfclient/WFChatClient/Messages/WFCCChangeGroupPortraitNotificationContent.m

@@ -0,0 +1,75 @@
+//
+//  WFCCChangeGroupNameNotificationContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCChangeGroupPortraitNotificationContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+@implementation WFCCChangeGroupPortraitNotificationContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.operateUser) {
+        [dataDict setObject:self.operateUser forKey:@"o"];
+    }
+    
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.operateUser = dictionary[@"o"];
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_CHANGE_GROUP_PORTRAIT;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [self formatNotification];
+}
+
+- (NSString *)formatNotification {
+    NSString *formatMsg;
+    if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.operateUser]) {
+        formatMsg = @"你更新了群头像";
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.operateUser refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            formatMsg = [NSString stringWithFormat:@"%@更新了群头像", userInfo.displayName];
+        } else {
+            formatMsg = [NSString stringWithFormat:@"用户<%@>更新了群头像", self.operateUser];
+        }
+    }
+    
+    return formatMsg;
+}
+@end

+ 26 - 0
wfclient/WFChatClient/Messages/WFCCCreateGroupNotificationContent.h

@@ -0,0 +1,26 @@
+//
+//  WFCCCreateGroupNotificationContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/19.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 建群的通知消息
+ */
+@interface WFCCCreateGroupNotificationContent : WFCCNotificationMessageContent
+
+/**
+ 创建者ID
+ */
+@property (nonatomic, strong)NSString *creator;
+
+/**
+ 群名
+ */
+@property (nonatomic, strong)NSString *groupName;
+
+@end

+ 75 - 0
wfclient/WFChatClient/Messages/WFCCCreateGroupNotificationContent.m

@@ -0,0 +1,75 @@
+//
+//  WFCCCreateGroupNotificationContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/19.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCCreateGroupNotificationContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+@implementation WFCCCreateGroupNotificationContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.creator) {
+        [dataDict setObject:self.creator forKey:@"o"];
+    }
+    if (self.groupName) {
+        [dataDict setObject:self.groupName forKey:@"n"];
+    }
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                                           options:kNilOptions
+                                                                             error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.creator = dictionary[@"o"];
+        self.groupName = dictionary[@"n"];
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_CREATE_GROUP;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [self formatNotification];
+}
+
+- (NSString *)formatNotification {
+    if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.creator]) {
+        return [NSString stringWithFormat:@"你创建了群\"%@\"", self.groupName];
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.creator refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            return [NSString stringWithFormat:@"%@创建了群\"%@\"", userInfo.displayName, self.groupName];
+        } else {
+            return [NSString stringWithFormat:@"用户<%@>创建了群\"%@\"", self.creator, self.groupName];
+        }
+    }
+}
+@end

+ 21 - 0
wfclient/WFChatClient/Messages/WFCCDismissGroupNotificationContent.h

@@ -0,0 +1,21 @@
+//
+//  WFCCDismissGroupNotificationContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 群解散的通知消息
+ */
+@interface WFCCDismissGroupNotificationContent : WFCCNotificationMessageContent
+
+/**
+ 操作者ID
+ */
+@property (nonatomic, strong)NSString *operateUser;
+
+@end

+ 76 - 0
wfclient/WFChatClient/Messages/WFCCDismissGroupNotificationContent.m

@@ -0,0 +1,76 @@
+//
+//  WFCCDismissGroupNotificationContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCDismissGroupNotificationContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+
+@implementation WFCCDismissGroupNotificationContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.operateUser) {
+        [dataDict setObject:self.operateUser forKey:@"o"];
+    }
+    
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.operateUser = dictionary[@"o"];
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_DISMISS_GROUP;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [self formatNotification];
+}
+
+- (NSString *)formatNotification {
+    NSString *formatMsg;
+    if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.operateUser]) {
+        formatMsg = @"你解散了群聊";
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.operateUser refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            formatMsg = [NSString stringWithFormat:@"%@解散了群聊", userInfo.displayName];
+        } else {
+            formatMsg = [NSString stringWithFormat:@"用户<%@>解散了群聊", self.operateUser];
+        }
+    }
+    
+    return formatMsg;
+}
+@end

+ 33 - 0
wfclient/WFChatClient/Messages/WFCCFileMessageContent.h

@@ -0,0 +1,33 @@
+//
+//  WFCCSoundMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/9.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMediaMessageContent.h"
+
+/**
+ 语音消息
+ */
+@interface WFCCFileMessageContent : WFCCMediaMessageContent
+
+/**
+ 构造方法
+
+ @param filePath 文件路径
+ @return 语音消息
+ */
++ (instancetype)fileMessageContentFromPath:(NSString *)filePath;
+
+/**
+ 文件名
+ */
+@property (nonatomic, strong)NSString *name;
+
+/**
+ 文件名
+ */
+@property (nonatomic, assign)NSUInteger size;
+@end

+ 64 - 0
wfclient/WFChatClient/Messages/WFCCFileMessageContent.m

@@ -0,0 +1,64 @@
+//
+//  WFCCSoundMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/9.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCFileMessageContent.h"
+#import "WFCCUtilities.h"
+#import "WFCCIMService.h"
+#import "Common.h"
+
+@implementation WFCCFileMessageContent
++ (instancetype)fileMessageContentFromPath:(NSString *)filePath {
+    WFCCFileMessageContent *fileMsg = [[WFCCFileMessageContent alloc] init];
+    fileMsg.localPath = filePath;
+    fileMsg.name = [filePath lastPathComponent];
+    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
+    fileMsg.size = [fileAttributes fileSize];
+
+    return fileMsg;
+}
+
+- (WFCCMessagePayload *)encode {
+    WFCCMediaMessagePayload *payload = [[WFCCMediaMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.searchableContent = self.name;
+    payload.content = [NSString stringWithFormat:@"%ld", (long)self.size];
+    payload.mediaType = Media_Type_File;
+    
+    payload.remoteMediaUrl = self.remoteUrl;
+    payload.localMediaPath = self.localPath;
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    if ([payload isKindOfClass:[WFCCMediaMessagePayload class]]) {
+        WFCCMediaMessagePayload *mediaPayload = (WFCCMediaMessagePayload *)payload;
+        self.remoteUrl = mediaPayload.remoteMediaUrl;
+        self.localPath = mediaPayload.localMediaPath;
+        self.name = mediaPayload.searchableContent;
+        self.size = [mediaPayload.content integerValue];
+    }
+}
+
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_FILE;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST_AND_COUNT;
+}
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [NSString stringWithFormat:@"[文件]:%@", self.name];
+}
+@end

+ 30 - 0
wfclient/WFChatClient/Messages/WFCCImageMessageContent.h

@@ -0,0 +1,30 @@
+//
+//  WFCCImageMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/2.
+//  Copyright © 2017年 wildfire chat. All rights reserved.
+//
+
+#import "WFCCMediaMessageContent.h"
+#import <UIKit/UIKit.h>
+
+/**
+ 图片消息
+ */
+@interface WFCCImageMessageContent : WFCCMediaMessageContent
+
+/**
+ 构造方法
+
+ @param image 图片
+ @return 图片消息
+ */
++ (instancetype)contentFrom:(UIImage *)image;
+
+/**
+ 缩略图,自动生成
+ */
+@property (nonatomic, strong)UIImage *thumbnail;
+
+@end

+ 79 - 0
wfclient/WFChatClient/Messages/WFCCImageMessageContent.m

@@ -0,0 +1,79 @@
+//
+//  WFCCImageMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/2.
+//  Copyright © 2017年 wildfire chat. All rights reserved.
+//
+
+#import "WFCCImageMessageContent.h"
+#import "WFCCNetworkService.h"
+#import "WFCCIMService.h"
+#import "WFCCUtilities.h"
+#import "Common.h"
+
+
+@implementation WFCCImageMessageContent
++ (instancetype)contentFrom:(UIImage *)image {
+    WFCCImageMessageContent *content = [[WFCCImageMessageContent alloc] init];
+    UInt64 recordTime = [[NSDate date] timeIntervalSince1970]*1000;
+    
+    NSString *path = [[WFCCUtilities getDocumentPathWithComponent:@"/IMG"] stringByAppendingPathComponent:[NSString stringWithFormat:@"img%lld.jpg", recordTime]];
+    
+    
+    NSData *imgData = UIImageJPEGRepresentation([WFCCUtilities generateThumbnail:image withWidth:1024 withHeight:1024], 0.85);
+    
+    [imgData writeToFile:path atomically:YES];
+    
+    content.localPath = path;
+    content.thumbnail = [WFCCUtilities generateThumbnail:image withWidth:120 withHeight:120];
+    
+    return content;
+}
+- (WFCCMessagePayload *)encode {
+    WFCCMediaMessagePayload *payload = [[WFCCMediaMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.searchableContent = @"[图片]";
+    payload.binaryContent = UIImageJPEGRepresentation(self.thumbnail, 0.45);
+    payload.mediaType = Media_Type_IMAGE;
+    payload.remoteMediaUrl = self.remoteUrl;
+    payload.localMediaPath = self.localPath;
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    if ([payload isKindOfClass:[WFCCMediaMessagePayload class]]) {
+        WFCCMediaMessagePayload *mediaPayload = (WFCCMediaMessagePayload *)payload;
+        self.thumbnail = [UIImage imageWithData:payload.binaryContent];
+        self.remoteUrl = mediaPayload.remoteMediaUrl;
+        self.localPath = mediaPayload.localMediaPath;
+    }
+}
+
+- (UIImage *)thumbnail {
+    if (!_thumbnail) {
+        UIImage *image = [UIImage imageWithContentsOfFile:self.localPath];
+        _thumbnail = [WFCCUtilities generateThumbnail:image withWidth:120 withHeight:120];
+    }
+    return _thumbnail;
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_IMAGE;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST_AND_COUNT;
+}
+
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return @"[图片]";
+}
+@end

+ 26 - 0
wfclient/WFChatClient/Messages/WFCCKickoffGroupMemberNotificaionContent.h

@@ -0,0 +1,26 @@
+//
+//  WFCCKickoffGroupMemberNotificaionContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 群组踢人的通知消息
+ */
+@interface WFCCKickoffGroupMemberNotificaionContent : WFCCNotificationMessageContent
+
+/**
+ 操作者ID
+ */
+@property (nonatomic, strong)NSString *operateUser;
+
+/**
+ 被踢成员的ID列表
+ */
+@property (nonatomic, strong)NSArray<NSString *> *kickedMembers;
+
+@end

+ 93 - 0
wfclient/WFChatClient/Messages/WFCCKickoffGroupMemberNotificaionContent.m

@@ -0,0 +1,93 @@
+//
+//  WFCCKickoffGroupMemberNotificaionContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCKickoffGroupMemberNotificaionContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+
+@implementation WFCCKickoffGroupMemberNotificaionContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.operateUser) {
+        [dataDict setObject:self.operateUser forKey:@"o"];
+    }
+    if (self.kickedMembers) {
+        [dataDict setObject:self.kickedMembers forKey:@"ms"];
+    }
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.operateUser = dictionary[@"o"];
+        self.kickedMembers = dictionary[@"ms"];
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_KICKOF_GROUP_MEMBER;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [self formatNotification];
+}
+
+- (NSString *)formatNotification {
+    NSString *formatMsg;
+    if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.operateUser]) {
+        formatMsg = @"你把";
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.operateUser refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            formatMsg = [NSString stringWithFormat:@"%@把", userInfo.displayName];
+        } else {
+            formatMsg = [NSString stringWithFormat:@"用户<%@>把", self.operateUser];
+        }
+    }
+    
+    for (NSString *member in self.kickedMembers) {
+        if ([member isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
+            formatMsg = [formatMsg stringByAppendingString:@" 你"];
+        } else {
+            WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:member refresh:NO];
+            if (userInfo.displayName.length > 0) {
+                formatMsg = [formatMsg stringByAppendingFormat:@" %@", userInfo.displayName];
+            } else {
+                formatMsg = [formatMsg stringByAppendingFormat:@" 用户<%@>", member];
+            }
+
+        }
+    }
+    formatMsg = [formatMsg stringByAppendingString:@"移出群聊"];
+    return formatMsg;
+}
+@end

+ 45 - 0
wfclient/WFChatClient/Messages/WFCCLocationMessageContent.h

@@ -0,0 +1,45 @@
+//
+//  WFCCTextMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMessageContent.h"
+#import <CoreLocation/CoreLocation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ 位置消息
+ */
+@interface WFCCLocationMessageContent : WFCCMessageContent
+
+/**
+ 构造消息
+
+ @param coordinate 坐标值
+ @param title 位置信息
+ @param thumbnail 缩略图
+ @return 位置消息
+ */
++ (instancetype)contentWith:(CLLocationCoordinate2D) coordinate
+                      title:(NSString *)title
+                  thumbnail:(UIImage *)thumbnail;
+
+/**
+ 位置坐标
+ */
+@property (nonatomic, assign)CLLocationCoordinate2D coordinate;
+
+/**
+ 位置信息
+ */
+@property (nonatomic, strong)NSString *title;
+
+/**
+ 缩略图
+ */
+@property (nonatomic, strong)UIImage *thumbnail;
+
+@end

+ 70 - 0
wfclient/WFChatClient/Messages/WFCCLocationMessageContent.m

@@ -0,0 +1,70 @@
+//
+//  WFCCTextMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCLocationMessageContent.h"
+#import "WFCCIMService.h"
+#import "Common.h"
+#import "WFCCUtilities.h"
+
+@implementation WFCCLocationMessageContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.searchableContent = self.title;
+    payload.binaryContent = UIImageJPEGRepresentation(self.thumbnail, 0.67);
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    [dataDict setObject:@(self.coordinate.latitude) forKey:@"lat"];
+    [dataDict setObject:@(self.coordinate.longitude) forKey:@"long"];
+    payload.content = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:dataDict
+                                                                                     options:kNilOptions
+                                                                                       error:nil] encoding:NSUTF8StringEncoding];
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    self.title = payload.searchableContent;
+    self.thumbnail = [UIImage imageWithData:payload.binaryContent];
+    
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:[payload.content dataUsingEncoding:NSUTF8StringEncoding]
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        double latitude = [dictionary[@"lat"] doubleValue];
+        double longitude = [dictionary[@"long"] doubleValue];
+        self.coordinate = CLLocationCoordinate2DMake(latitude, longitude);
+    }
+
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_LOCATION;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST_AND_COUNT;
+}
+
+
++ (instancetype)contentWith:(CLLocationCoordinate2D) coordinate title:(NSString *)title thumbnail:(UIImage *)thumbnail {
+    WFCCLocationMessageContent *content = [[WFCCLocationMessageContent alloc] init];
+    content.coordinate = coordinate;
+    content.title = title;
+    content.thumbnail = [WFCCUtilities generateThumbnail:thumbnail withWidth:180 withHeight:120];;
+    return content;
+}
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+  return @"[位置]";
+}
+@end

+ 25 - 0
wfclient/WFChatClient/Messages/WFCCMediaMessageContent.h

@@ -0,0 +1,25 @@
+//
+//  WFCCMediaMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/6.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMessageContent.h"
+
+/**
+ 媒体消息
+ */
+@interface WFCCMediaMessageContent : WFCCMessageContent
+
+/**
+ 媒体内容的本地存储路径
+ */
+@property (nonatomic, strong)NSString *localPath;
+
+/**
+ 媒体内容的服务器路径
+ */
+@property (nonatomic, strong)NSString *remoteUrl;
+@end

+ 19 - 0
wfclient/WFChatClient/Messages/WFCCMediaMessageContent.m

@@ -0,0 +1,19 @@
+//
+//  WFCCMediaMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/6.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMediaMessageContent.h"
+#import "WFCCUtilities.h"
+#import "Common.h"
+
+
+@implementation WFCCMediaMessageContent
+- (NSString *)localPath {
+    _localPath = [WFCCUtilities getSendBoxFilePath:_localPath];
+    return _localPath;
+}
+@end

+ 95 - 0
wfclient/WFChatClient/Messages/WFCCMessage.h

@@ -0,0 +1,95 @@
+//
+//  WFCCMessage.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "WFCCConversation.h"
+#import "WFCCMessageContent.h"
+
+/**
+ 消息方向
+
+ - MessageDirection_Send: 发送
+ - MessageDirection_Receive: 接收
+ */
+typedef NS_ENUM(NSInteger, WFCCMessageDirection) {
+    MessageDirection_Send,
+    MessageDirection_Receive
+};
+
+/**
+ 消息状态
+
+ - Message_Status_Sending: 发送中
+ - Message_Status_Sent: 发送成功
+ - Message_Status_Send_Failure: 发送失败
+ - Message_Status_Unread: 未读
+ - Message_Status_Readed: 已读
+ - Message_Status_Played: 已播放(媒体消息)
+ */
+typedef NS_ENUM(NSInteger, WFCCMessageStatus) {
+    Message_Status_Sending,
+    Message_Status_Sent,
+    Message_Status_Send_Failure,
+    Message_Status_Mentioned,
+    Message_Status_AllMentioned,
+    Message_Status_Unread,
+    Message_Status_Readed,
+    Message_Status_Played
+};
+
+/**
+ 消息实体
+ */
+@interface WFCCMessage : NSObject
+
+/**
+ 消息ID,当前用户本地唯一
+ */
+@property (nonatomic, assign)long messageId;
+
+/**
+ 消息UID,所有用户全局唯一
+ */
+@property (nonatomic, assign)long long messageUid;
+
+/**
+ 消息所属的会话
+ */
+@property (nonatomic, strong)WFCCConversation *conversation;
+
+/**
+ 消息发送者的用户ID
+ */
+@property (nonatomic, strong)NSString * fromUser;
+
+/**
+ 消息在会话中定向发送给该用户的
+ */
+@property (nonatomic, strong)NSString * toUser;
+
+/**
+ 消息内容
+ */
+@property (nonatomic, strong)WFCCMessageContent *content;
+
+/**
+ 消息方向
+ */
+@property (nonatomic, assign)WFCCMessageDirection direction;
+
+/**
+ 消息状态
+ */
+@property (nonatomic, assign)WFCCMessageStatus status;
+
+/**
+ 消息的发送时间
+ */
+@property (nonatomic, assign)long long serverTime;
+
+@end

+ 15 - 0
wfclient/WFChatClient/Messages/WFCCMessage.m

@@ -0,0 +1,15 @@
+//
+//  WFCCMessage.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMessage.h"
+#import "Common.h"
+
+
+@implementation WFCCMessage
+
+@end

+ 164 - 0
wfclient/WFChatClient/Messages/WFCCMessageContent.h

@@ -0,0 +1,164 @@
+//
+//  WFCCMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/15.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ 媒体类型
+
+ - Media_Type_GENERAL: 一般
+ - Media_Type_IMAGE: 图片
+ - Media_Type_VOICE: 语音
+ - Media_Type_VIDEO: 视频
+ - Media_Type_File: 文件
+ - Media_Type_PORTRAIT: 头像
+ - Media_Type_FAVORITE: 收藏
+ */
+typedef NS_ENUM(NSInteger, WFCCMediaType) {
+    Media_Type_GENERAL = 0,
+    Media_Type_IMAGE = 1,
+    Media_Type_VOICE = 2,
+    Media_Type_VIDEO = 3,
+    Media_Type_File = 4,
+    Media_Type_PORTRAIT = 5,
+    Media_Type_FAVORITE = 6
+};
+
+
+/**
+ 消息存储类型
+ 
+ - NOT_PERSIST: 本地不存储
+ - PERSIST: 本地存储
+ - PERSIST_AND_COUNT: 本地存储,并计入未读计数
+ - TRANSPARENT: 透传消息,不多端同步,如果对端不在线,消息会丢弃
+ */
+typedef NS_ENUM(NSInteger, WFCCPersistFlag) {
+    WFCCPersistFlag_NOT_PERSIST = 0,
+    WFCCPersistFlag_PERSIST = 1,
+    WFCCPersistFlag_PERSIST_AND_COUNT = 3,
+    WFCCPersistFlag_TRANSPARENT = 4,
+};
+
+/**
+ 普通消息的持久化内容
+ */
+@interface WFCCMessagePayload : NSObject
+
+/**
+ 消息类型
+ */
+@property (nonatomic, assign)int contentType;
+
+/**
+ 搜索内容
+ */
+@property (nonatomic, strong)NSString *searchableContent;
+
+/**
+ 推送内容
+*/
+@property (nonatomic, strong)NSString *pushContent;
+
+/**
+ 内容
+ */
+@property (nonatomic, strong)NSString *content;
+
+/**
+ 内容流
+ */
+@property (nonatomic, strong)NSData *binaryContent;
+
+/**
+ 只存储在客户端本地的内容
+ */
+@property (nonatomic, strong)NSString *localContent;
+
+/**
+ 提醒类型,1,提醒部分对象(mentinedTarget)。2,提醒全部。其他不提醒
+ */
+@property (nonatomic, assign)int mentionedType;
+
+/**
+ 提醒对象,mentionedType 1时有效
+ */
+@property (nonatomic, strong)NSArray<NSString *> *mentionedTargets;
+
+@end
+
+/**
+ 媒体消息的持久化内容
+ */
+@interface WFCCMediaMessagePayload : WFCCMessagePayload
+
+/**
+ 媒体类型
+ */
+@property (nonatomic, assign)WFCCMediaType mediaType;
+
+/**
+ 媒体内容的服务器URL
+ */
+@property (nonatomic, strong)NSString *remoteMediaUrl;
+
+/**
+ 媒体内容的本地URL,发送消息时不会携带,用于缓存加速显示
+ */
+@property (nonatomic, strong)NSString *localMediaPath;
+
+@end
+
+/**
+ 消息协议,所有消息(包括自定义消息均需要实现此协议)
+ */
+@protocol WFCCMessageContent <NSObject>
+
+/**
+ 消息编码
+
+ @return 消息的持久化内容
+ */
+- (WFCCMessagePayload *)encode;
+
+/**
+ 消息解码
+
+ @param payload 消息的持久化内容
+ */
+- (void)decode:(WFCCMessagePayload *)payload;
+
+/**
+ 消息类型,必须全局唯一。1000及以下为系统内置类型,自定义消息需要使用1000以上。
+
+ @return 消息类型的唯一值
+ */
++ (int)getContentType;
+
+/**
+ 消息的存储策略
+
+ @return 存储策略
+ */
++ (int)getContentFlags;
+
+/**
+ 消息的简短信息
+
+ @return 消息的简短信息,主要用于通知提示和会话列表等需要简略信息的地方。
+ */
+- (NSString *)digest;
+
+@end
+
+/**
+ 消息内容,自定义消息可以继承此类
+ */
+@interface WFCCMessageContent : NSObject <WFCCMessageContent>
+
+@end

+ 37 - 0
wfclient/WFChatClient/Messages/WFCCMessageContent.m

@@ -0,0 +1,37 @@
+//
+//  WFCCMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/15.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMessageContent.h"
+#import "Common.h"
+
+@implementation WFCCMessagePayload
+@end
+
+@implementation WFCCMediaMessagePayload
+@end
+
+@implementation WFCCMessageContent
++ (void)load {
+    
+}
+- (WFCCMessagePayload *)encode {
+    return nil;
+}
+- (void)decode:(WFCCMessagePayload *)payload {
+    
+}
++ (int)getContentType {
+    return 0;
+}
++ (int)getContentFlags {
+    return 0;
+}
+- (NSString *)digest {
+  return @"Unimplement digest function";
+}
+@end

+ 26 - 0
wfclient/WFChatClient/Messages/WFCCModifyGroupAliasNotificationContent.h

@@ -0,0 +1,26 @@
+//
+//  WFCCModifyGroupAliasNotificationContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 群成员修改群昵称的通知消息
+ */
+@interface WFCCModifyGroupAliasNotificationContent : WFCCNotificationMessageContent
+
+/**
+ 群成员ID
+ */
+@property (nonatomic, strong)NSString *operateUser;
+
+/**
+ 群昵称
+ */
+@property (nonatomic, strong)NSString *alias;
+
+@end

+ 79 - 0
wfclient/WFChatClient/Messages/WFCCModifyGroupAliasNotificationContent.m

@@ -0,0 +1,79 @@
+//
+//  WFCCModifyGroupAliasNotificationContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCModifyGroupAliasNotificationContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+@implementation WFCCModifyGroupAliasNotificationContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.operateUser) {
+        [dataDict setObject:self.operateUser forKey:@"o"];
+    }
+    if (self.alias) {
+        [dataDict setObject:self.alias forKey:@"n"];
+    }
+    
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.operateUser = dictionary[@"o"];
+        self.alias = dictionary[@"n"];
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_MODIFY_GROUP_ALIAS;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [self formatNotification];
+}
+
+- (NSString *)formatNotification {
+    NSString *formatMsg;
+    if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.operateUser]) {
+        formatMsg = [NSString stringWithFormat:@"你修改群名片为:%@", self.alias];
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.operateUser refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            formatMsg = [NSString stringWithFormat:@"%@修改群名片为:%@", userInfo.displayName, self.alias];
+        } else {
+            formatMsg = [NSString stringWithFormat:@"%@修改群名片为:%@", self.operateUser, self.alias];
+        }
+    }
+    
+    return formatMsg;
+}
+@end

+ 30 - 0
wfclient/WFChatClient/Messages/WFCCNotificationMessageContent.h

@@ -0,0 +1,30 @@
+//
+//  WFCCNotificationMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/19.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMessageContent.h"
+
+
+/**
+ 通知消息的协议
+ */
+@protocol WFCCNotificationMessageContent <WFCCMessageContent>
+
+/**
+ 获取通知的提示内容
+
+ @return 提示内容
+ */
+- (NSString *)formatNotification;
+@end
+
+/**
+ 通知消息
+ */
+@interface WFCCNotificationMessageContent : WFCCMessageContent <WFCCNotificationMessageContent>
+
+@end

+ 18 - 0
wfclient/WFChatClient/Messages/WFCCNotificationMessageContent.m

@@ -0,0 +1,18 @@
+//
+//  WFCCNotificationMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/19.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+#import "Common.h"
+
+@implementation WFCCNotificationMessageContent
+
+- (NSString *)formatNotification {
+    return nil;
+}
+
+@end

+ 20 - 0
wfclient/WFChatClient/Messages/WFCCQuitGroupNotificationContent.h

@@ -0,0 +1,20 @@
+//
+//  WFCCQuitGroupNotificationContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 退群的通知消息
+ */
+@interface WFCCQuitGroupNotificationContent : WFCCNotificationMessageContent
+
+/**
+ 退群成员的ID
+ */
+@property (nonatomic, strong)NSString *quitMember;
+@end

+ 75 - 0
wfclient/WFChatClient/Messages/WFCCQuitGroupNotificationContent.m

@@ -0,0 +1,75 @@
+//
+//  WFCCQuitGroupNotificationContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCQuitGroupNotificationContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+@implementation WFCCQuitGroupNotificationContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.quitMember) {
+        [dataDict setObject:self.quitMember forKey:@"o"];
+    }
+    
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.quitMember = dictionary[@"o"];
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_QUIT_GROUP;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [self formatNotification];
+}
+
+- (NSString *)formatNotification {
+    NSString *formatMsg;
+    if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.quitMember]) {
+        formatMsg = @"你退出了群聊";
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.quitMember refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            formatMsg = [NSString stringWithFormat:@"%@退出了群聊", userInfo.displayName];
+        } else {
+            formatMsg = [NSString stringWithFormat:@"用户<%@>退出了群聊", self.quitMember];
+        }
+    }
+    
+    return formatMsg;
+}
+@end

+ 25 - 0
wfclient/WFChatClient/Messages/WFCCRecallMessageContent.h

@@ -0,0 +1,25 @@
+//
+//  WFCCRecallMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 文本消息
+ */
+@interface WFCCRecallMessageContent : WFCCNotificationMessageContent
+
+/**
+ 被撤回消息的Uid
+ */
+@property (nonatomic, assign)long long messageUid;
+
+/**
+ 撤回用户Id
+ */
+@property (nonatomic, strong)NSString *operatorId;
+@end

+ 59 - 0
wfclient/WFChatClient/Messages/WFCCRecallMessageContent.m

@@ -0,0 +1,59 @@
+//
+//  WFCCTextMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCRecallMessageContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+
+@implementation WFCCRecallMessageContent
+- (WFCCMessagePayload *)encode {
+    //注意:在proto层收到撤回命令或主动撤回成功会直接更新被撤回的消息,如果修改encode&decode,需要同步修改
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.content = self.operatorId;
+    payload.binaryContent = [[[NSNumber numberWithLongLong:self.messageUid] stringValue] dataUsingEncoding:NSUTF8StringEncoding];
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    //注意:在proto层收到撤回命令或主动撤回成功会直接更新被撤回的消息,如果修改encode&decode,需要同步修改
+    self.operatorId = payload.content;
+    self.messageUid = [[[NSString alloc] initWithData:payload.binaryContent encoding:NSUTF8StringEncoding] longLongValue];
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_RECALL;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)formatNotification {
+    return self.digest;
+}
+
+- (NSString *)digest {
+    if ([self.operatorId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
+        return @"你撤回了一条消息";
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.operatorId refresh:NO];
+        if (userInfo.displayName != nil) {
+            return [NSString stringWithFormat:@"%@撤回了一条消息", userInfo.displayName];
+        }
+        return [NSString stringWithFormat:@"用户<%@>撤回了一条消息", self.operatorId];
+    }
+}
+@end

+ 44 - 0
wfclient/WFChatClient/Messages/WFCCSoundMessageContent.h

@@ -0,0 +1,44 @@
+//
+//  WFCCSoundMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/9.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMediaMessageContent.h"
+
+/**
+ 语音消息
+ */
+@interface WFCCSoundMessageContent : WFCCMediaMessageContent
+
+/**
+ 构造方法
+
+ @param wavPath 文件路径
+ @param duration 时间
+ @return 语音消息
+ */
++ (instancetype)soundMessageContentForWav:(NSString *)wavPath
+                                 duration:(long)duration;
+
+/**
+ 时间
+ */
+@property (nonatomic, assign)long duration;
+
+/**
+ 设置wav内容
+
+ @param voiceData wav数据
+ */
+- (void)updateAmrData:(NSData *)voiceData;
+
+/**
+ 获取语音消息的wav数据
+
+ @return wav数据
+ */
+- (NSData *)getWavData;
+@end

+ 94 - 0
wfclient/WFChatClient/Messages/WFCCSoundMessageContent.m

@@ -0,0 +1,94 @@
+//
+//  WFCCSoundMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/9.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCSoundMessageContent.h"
+#import "WFCCUtilities.h"
+#import "wav_amr.h"
+#import "WFCCIMService.h"
+#import "Common.h"
+
+@implementation WFCCSoundMessageContent
++ (instancetype)soundMessageContentForWav:(NSString *)wavPath duration:(long)duration {
+    WFCCSoundMessageContent *soundMsg = [[WFCCSoundMessageContent alloc] init];
+    soundMsg.duration = duration;
+    
+    UInt64 recordTime = [[NSDate date] timeIntervalSince1970]*1000;
+    
+    NSString *amrPath = [[WFCCUtilities getDocumentPathWithComponent:@"/Vioce"] stringByAppendingPathComponent:[NSString stringWithFormat:@"img%lld.amr", recordTime]];
+    
+    encode_amr([wavPath UTF8String], [amrPath UTF8String]);
+    
+    soundMsg.localPath = amrPath;
+    
+    return soundMsg;
+}
+
+- (void)updateAmrData:(NSData *)voiceData {
+    UInt64 recordTime = [[NSDate date] timeIntervalSince1970]*1000;
+    
+    NSString *amrPath = [[WFCCUtilities getDocumentPathWithComponent:@"/Vioce"] stringByAppendingPathComponent:[NSString stringWithFormat:@"img%lld.amr", recordTime]];
+    [voiceData writeToFile:amrPath atomically:YES];
+    
+    self.localPath = amrPath;
+}
+- (NSData *)getWavData {
+    NSMutableData *data = [[NSMutableData alloc] init];
+    decode_amr([self.localPath UTF8String], data);
+    
+//    UInt64 recordTime = [[NSDate date] timeIntervalSince1970]*1000;
+//    NSString *amrPath = [[WFCCUtilities getDocumentPathWithComponent:@"/Vioce"] stringByAppendingPathComponent:[NSString stringWithFormat:@"img%lld.wav", recordTime]];
+//    
+//    [data writeToFile:amrPath atomically:YES];
+    return data;
+}
+
+- (WFCCMessagePayload *)encode {
+    WFCCMediaMessagePayload *payload = [[WFCCMediaMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.searchableContent = @"[声音]";
+    payload.mediaType = Media_Type_VOICE;
+    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
+    [dict setObject:@(_duration) forKey:@"duration"];
+    payload.content = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:dict options:kNilOptions error:nil] encoding:NSUTF8StringEncoding];
+    
+    payload.remoteMediaUrl = self.remoteUrl;
+    payload.localMediaPath = self.localPath;
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    if ([payload isKindOfClass:[WFCCMediaMessagePayload class]]) {
+        WFCCMediaMessagePayload *mediaPayload = (WFCCMediaMessagePayload *)payload;
+        self.remoteUrl = mediaPayload.remoteMediaUrl;
+        self.localPath = mediaPayload.localMediaPath;
+        
+        NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:[payload.content dataUsingEncoding:NSUTF8StringEncoding]
+                                                                   options:kNilOptions
+                                                                     error:nil];
+        self.duration = [dictionary[@"duration"] longValue];
+    }
+}
+
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_SOUND;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST_AND_COUNT;
+}
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return @"[声音]";
+}
+@end

+ 26 - 0
wfclient/WFChatClient/Messages/WFCCStickerMessageContent.h

@@ -0,0 +1,26 @@
+//
+//  WFCCImageMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/2.
+//  Copyright © 2017年 wildfire chat. All rights reserved.
+//
+
+#import "WFCCMediaMessageContent.h"
+#import <UIKit/UIKit.h>
+
+/**
+ 图片消息
+ */
+@interface WFCCStickerMessageContent : WFCCMediaMessageContent
+
+/**
+ 构造方法
+
+ @param stickerPath 表情路径
+ @return 表情消息
+ */
++ (instancetype)contentFrom:(NSString *)stickerPath;
+
+@property (nonatomic, assign)CGSize size;
+@end

+ 77 - 0
wfclient/WFChatClient/Messages/WFCCStickerMessageContent.m

@@ -0,0 +1,77 @@
+//
+//  WFCCImageMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/2.
+//  Copyright © 2017年 wildfire chat. All rights reserved.
+//
+
+#import "WFCCStickerMessageContent.h"
+#import "WFCCNetworkService.h"
+#import "WFCCIMService.h"
+#import "WFCCUtilities.h"
+#import "Common.h"
+
+
+@implementation WFCCStickerMessageContent
++ (instancetype)contentFrom:(NSString *)stickerPath {
+    WFCCStickerMessageContent *content = [[WFCCStickerMessageContent alloc] init];
+    content.localPath = stickerPath;
+    content.size = [UIImage imageWithContentsOfFile:stickerPath].size;
+    return content;
+}
+
+- (WFCCMessagePayload *)encode {
+    WFCCMediaMessagePayload *payload = [[WFCCMediaMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.searchableContent = @"[动态表情]";
+    payload.mediaType = Media_Type_File;
+    payload.remoteMediaUrl = self.remoteUrl;
+    payload.localMediaPath = self.localPath;
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    [dataDict setObject:@(self.size.width) forKey:@"x"];
+    [dataDict setObject:@(self.size.height) forKey:@"y"];
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    if ([payload isKindOfClass:[WFCCMediaMessagePayload class]]) {
+        WFCCMediaMessagePayload *mediaPayload = (WFCCMediaMessagePayload *)payload;
+        self.remoteUrl = mediaPayload.remoteMediaUrl;
+        self.localPath = mediaPayload.localMediaPath;
+    }
+    
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.size = CGSizeMake([dictionary[@"x"] floatValue], [dictionary[@"x"] floatValue]);
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_STICKER;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST_AND_COUNT;
+}
+
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return @"[动态表情]";
+}
+@end

+ 39 - 0
wfclient/WFChatClient/Messages/WFCCTextMessageContent.h

@@ -0,0 +1,39 @@
+//
+//  WFCCTextMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMessageContent.h"
+
+/**
+ 文本消息
+ */
+@interface WFCCTextMessageContent : WFCCMessageContent
+
+/**
+ 构造方法
+
+ @param text 文本
+ @return 文本消息
+ */
++ (instancetype)contentWith:(NSString *)text;
+
+/**
+ 文本内容
+ */
+@property (nonatomic, strong)NSString *text;
+
+
+/**
+ 提醒类型,1,提醒部分对象(mentinedTarget)。2,提醒全部。其他不提醒
+ */
+@property (nonatomic, assign)int mentionedType;
+
+/**
+ 提醒对象,mentionedType 1时有效
+ */
+@property (nonatomic, strong)NSArray<NSString *> *mentionedTargets;
+@end

+ 52 - 0
wfclient/WFChatClient/Messages/WFCCTextMessageContent.m

@@ -0,0 +1,52 @@
+//
+//  WFCCTextMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCTextMessageContent.h"
+#import "WFCCIMService.h"
+#import "Common.h"
+
+
+@implementation WFCCTextMessageContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.searchableContent = self.text;
+    payload.mentionedType = self.mentionedType;
+    payload.mentionedTargets = self.mentionedTargets;
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    self.text = payload.searchableContent;
+    self.mentionedType = payload.mentionedType;
+    self.mentionedTargets = payload.mentionedTargets;
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_TEXT;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST_AND_COUNT;
+}
+
+
++ (instancetype)contentWith:(NSString *)text {
+    WFCCTextMessageContent *content = [[WFCCTextMessageContent alloc] init];
+    content.text = text;
+    return content;
+}
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+  return self.text;
+}
+@end

+ 20 - 0
wfclient/WFChatClient/Messages/WFCCTipNotificationMessageContent.h

@@ -0,0 +1,20 @@
+//
+//  WFCCNotificationMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/19.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 退群的通知消息
+ */
+@interface WFCCTipNotificationContent : WFCCNotificationMessageContent
+
+/**
+ 退群成员的ID
+ */
+@property (nonatomic, strong)NSString *tip;
+@end

+ 48 - 0
wfclient/WFChatClient/Messages/WFCCTipNotificationMessageContent.m

@@ -0,0 +1,48 @@
+//
+//  WFCCNotificationMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/19.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCTipNotificationMessageContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+@implementation WFCCTipNotificationContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    payload.content = self.tip;
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    self.tip = payload.content;
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_TIP;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)formatNotification {
+    return self.tip;
+}
+
+- (NSString *)digest {
+    return self.tip;
+}
+@end

+ 26 - 0
wfclient/WFChatClient/Messages/WFCCTransferGroupOwnerNotificationContent.h

@@ -0,0 +1,26 @@
+//
+//  WFCCTransferGroupOwnerNotificationContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCNotificationMessageContent.h"
+
+/**
+ 转让群主的通知消息
+ */
+@interface WFCCTransferGroupOwnerNotificationContent : WFCCNotificationMessageContent
+
+/**
+ 操作者的ID
+ */
+@property (nonatomic, strong)NSString *operateUser;
+
+/**
+ 新的群主ID
+ */
+@property (nonatomic, strong)NSString *owner;
+
+@end

+ 95 - 0
wfclient/WFChatClient/Messages/WFCCTransferGroupOwnerNotificationContent.m

@@ -0,0 +1,95 @@
+//
+//  WFCCTransferGroupOwnerNotificationContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/20.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCTransferGroupOwnerNotificationContent.h"
+#import "WFCCIMService.h"
+#import "WFCCNetworkService.h"
+#import "Common.h"
+
+@implementation WFCCTransferGroupOwnerNotificationContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    
+    NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];
+    if (self.operateUser) {
+        [dataDict setObject:self.operateUser forKey:@"o"];
+    }
+    if (self.owner) {
+        [dataDict setObject:self.owner forKey:@"m"];
+    }
+    
+    
+    payload.binaryContent = [NSJSONSerialization dataWithJSONObject:dataDict
+                                                            options:kNilOptions
+                                                              error:nil];
+    
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    NSError *__error = nil;
+    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:payload.binaryContent
+                                                               options:kNilOptions
+                                                                 error:&__error];
+    if (!__error) {
+        self.operateUser = dictionary[@"o"];
+        self.owner = dictionary[@"m"];
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_TRANSFER_GROUP_OWNER;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return [self formatNotification];
+}
+
+- (NSString *)formatNotification {
+    NSString *formatMsg;
+    if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.operateUser]) {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.owner refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            formatMsg = [NSString stringWithFormat:@"你把群主转让给了%@", userInfo.displayName];
+        } else {
+            formatMsg = [NSString stringWithFormat:@"你把群主转让给了%@", self.owner];
+        }
+    } else {
+        WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.operateUser refresh:NO];
+        if (userInfo.displayName.length > 0) {
+            formatMsg = [NSString stringWithFormat:@"%@把群主转让给了", userInfo.displayName];
+        } else {
+            formatMsg = [NSString stringWithFormat:@"%@把群主转让给了", self.operateUser];
+        }
+        
+        if ([[WFCCNetworkService sharedInstance].userId isEqualToString:self.owner]) {
+            formatMsg = [formatMsg stringByAppendingString:@"你"];
+        } else {
+            userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:self.owner refresh:NO];
+            if (userInfo.displayName.length > 0) {
+                formatMsg = [formatMsg stringByAppendingString:userInfo.displayName];
+            } else {
+                formatMsg = [formatMsg stringByAppendingString:self.owner];
+            }
+        }
+    }
+    
+    return formatMsg;
+}
+@end

+ 46 - 0
wfclient/WFChatClient/Messages/WFCCTypingMessageContent.h

@@ -0,0 +1,46 @@
+//
+//  TypingMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMessageContent.h"
+
+/**
+ 媒体类型
+ 
+ - Typing_TEXT : 正在输入文本
+ - Typing_VOICE : 正在输入语音
+ - Typing_CAMERA : 正在拍摄
+ - Typing_LOCATION : 正在选取位置
+ - Typing_FILE : 正在选取文件
+ */
+typedef NS_ENUM(NSInteger, WFCCTypingType) {
+    Typing_TEXT = 0,
+    Typing_VOICE = 1,
+    Typing_CAMERA = 2,
+    Typing_LOCATION = 3,
+    Typing_FILE = 4
+};
+
+
+/**
+ 正在输入消息
+ */
+@interface WFCCTypingMessageContent : WFCCMessageContent
+
+/**
+ 构造方法
+
+ @param type 输入类型类型。
+ @return 正在输入消息
+ */
++ (instancetype)contentType:(WFCCTypingType)type;
+
+/**
+ 输入类型类型。0 文本;1 语言。
+ */
+@property (nonatomic, assign)WFCCTypingType type;
+@end

+ 48 - 0
wfclient/WFChatClient/Messages/WFCCTypingMessageContent.m

@@ -0,0 +1,48 @@
+//
+//  TypingMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCTypingMessageContent.h"
+#import "WFCCIMService.h"
+#import "Common.h"
+
+
+@implementation WFCCTypingMessageContent
+- (WFCCMessagePayload *)encode {
+    WFCCMessagePayload *payload = [[WFCCMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.content = [NSString stringWithFormat:@"%d", (int)self.type];
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    self.type = [payload.content intValue];
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_TYPING;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_TRANSPARENT;
+}
+
+
++ (instancetype)contentType:(WFCCTypingType)type {
+    WFCCTypingMessageContent *content = [[WFCCTypingMessageContent alloc] init];
+    content.type = type;
+    return content;
+}
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+  return nil;
+}
+@end

+ 21 - 0
wfclient/WFChatClient/Messages/WFCCUnknownMessageContent.h

@@ -0,0 +1,21 @@
+//
+//  WFCCUnknownMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCMessageContent.h"
+
+/**
+ 未知消息。所有未注册的消息都会解析为为止消息,主要用于新旧版本兼容
+ */
+@interface WFCCUnknownMessageContent : WFCCMessageContent
+
+/**
+ 消息类型
+ */
+@property (nonatomic, assign)NSInteger orignalType;
+
+@end

+ 36 - 0
wfclient/WFChatClient/Messages/WFCCUnknownMessageContent.m

@@ -0,0 +1,36 @@
+//
+//  WFCCUnknownMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCUnknownMessageContent.h"
+#import "WFCCIMService.h"
+#import "Common.h"
+
+
+@implementation WFCCUnknownMessageContent
+- (WFCCMessagePayload *)encode {
+    return nil;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    self.orignalType = payload.contentType;
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_UNKNOWN;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST;
+}
+
+
+
+- (NSString *)digest {
+  return [NSString stringWithFormat:@"未知类型消息(%zd)", self.orignalType];
+}
+@end

+ 30 - 0
wfclient/WFChatClient/Messages/WFCCVideoMessageContent.h

@@ -0,0 +1,30 @@
+//
+//  WFCCVideoMessageContent.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/2.
+//  Copyright © 2017年 wildfire chat. All rights reserved.
+//
+
+#import "WFCCMediaMessageContent.h"
+#import <UIKit/UIKit.h>
+
+/**
+ 图片消息
+ */
+@interface WFCCVideoMessageContent : WFCCMediaMessageContent
+
+/**
+ 构造方法
+
+ @param image 图片
+ @return 图片消息
+ */
++ (instancetype)contentPath:(NSString *)localPath thumbnail:(UIImage *)image;
+
+/**
+ 缩略图
+ */
+@property (nonatomic, strong)UIImage *thumbnail;
+
+@end

+ 62 - 0
wfclient/WFChatClient/Messages/WFCCVideoMessageContent.m

@@ -0,0 +1,62 @@
+//
+//  WFCCVideoMessageContent.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/2.
+//  Copyright © 2017年 wildfire chat. All rights reserved.
+//
+
+#import "WFCCVideoMessageContent.h"
+#import "WFCCNetworkService.h"
+#import "WFCCIMService.h"
+#import "WFCCUtilities.h"
+#import "Common.h"
+
+
+@implementation WFCCVideoMessageContent
++ (instancetype)contentPath:(NSString *)localPath thumbnail:(UIImage *)image {
+    WFCCVideoMessageContent *content = [[WFCCVideoMessageContent alloc] init];
+    content.localPath = localPath;
+    content.thumbnail = image;
+    
+    return content;
+}
+- (WFCCMessagePayload *)encode {
+    WFCCMediaMessagePayload *payload = [[WFCCMediaMessagePayload alloc] init];
+    payload.contentType = [self.class getContentType];
+    payload.searchableContent = @"[图片]";
+    payload.binaryContent = UIImageJPEGRepresentation(self.thumbnail, 0.45);
+    payload.mediaType = Media_Type_VIDEO;
+    payload.remoteMediaUrl = self.remoteUrl;
+    payload.localMediaPath = self.localPath;
+    return payload;
+}
+
+- (void)decode:(WFCCMessagePayload *)payload {
+    if ([payload isKindOfClass:[WFCCMediaMessagePayload class]]) {
+        WFCCMediaMessagePayload *mediaPayload = (WFCCMediaMessagePayload *)payload;
+        self.thumbnail = [UIImage imageWithData:payload.binaryContent];
+        self.remoteUrl = mediaPayload.remoteMediaUrl;
+        self.localPath = mediaPayload.localMediaPath;
+    }
+}
+
++ (int)getContentType {
+    return MESSAGE_CONTENT_TYPE_VIDEO;
+}
+
++ (int)getContentFlags {
+    return WFCCPersistFlag_PERSIST_AND_COUNT;
+}
+
+
+
+
++ (void)load {
+    [[WFCCIMService sharedWFCIMService] registerMessageContent:self];
+}
+
+- (NSString *)digest {
+    return @"[视频]";
+}
+@end

+ 24 - 0
wfclient/WFChatClient/Model/WFCCChannelInfo.h

@@ -0,0 +1,24 @@
+//
+//  WFCCChatroomInfo.h
+//  WFChatClient
+//
+//  Created by heavyrain lee on 2018/8/24.
+//  Copyright © 2018 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface WFCCChannelInfo : NSObject
+@property(nonatomic, strong)NSString *channelId;
+@property(nonatomic, strong)NSString *name;
+@property(nonatomic, strong)NSString *portrait;
+@property(nonatomic, strong)NSString *owner;
+@property(nonatomic, strong)NSString *desc;
+@property(nonatomic, strong)NSString *extra;
+@property(nonatomic, strong)NSString *secret;
+@property(nonatomic, strong)NSString *callback;
+
+//0 public; 1 private; 2 destoryed
+@property(nonatomic, assign)int status;
+@property(nonatomic, assign)long long updateDt;
+@end

+ 15 - 0
wfclient/WFChatClient/Model/WFCCChannelInfo.m

@@ -0,0 +1,15 @@
+//
+//  WFCCChatroomInfo.m
+//  WFChatClient
+//
+//  Created by heavyrain lee on 2018/8/24.
+//  Copyright © 2018 WildFireChat. All rights reserved.
+//
+
+#import "WFCCChannelInfo.h"
+
+@implementation WFCCChannelInfo
+
+
+
+@end

+ 23 - 0
wfclient/WFChatClient/Model/WFCCChatroomInfo.h

@@ -0,0 +1,23 @@
+//
+//  WFCCChatroomInfo.h
+//  WFChatClient
+//
+//  Created by heavyrain lee on 2018/8/24.
+//  Copyright © 2018 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface WFCCChatroomInfo : NSObject
+@property(nonatomic, strong)NSString *chatroomId;
+@property(nonatomic, strong)NSString *title;
+@property(nonatomic, strong)NSString *desc;
+@property(nonatomic, strong)NSString *portrait;
+@property(nonatomic, strong)NSString *extra;
+
+//0 normal; 1 not started; 2 end
+@property(nonatomic, assign)int state;
+@property(nonatomic, assign)int memberCount;
+@property(nonatomic, assign)long long createDt;
+@property(nonatomic, assign)long long updateDt;
+@end

+ 15 - 0
wfclient/WFChatClient/Model/WFCCChatroomInfo.m

@@ -0,0 +1,15 @@
+//
+//  WFCCChatroomInfo.m
+//  WFChatClient
+//
+//  Created by heavyrain lee on 2018/8/24.
+//  Copyright © 2018 WildFireChat. All rights reserved.
+//
+
+#import "WFCCChatroomInfo.h"
+
+@implementation WFCCChatroomInfo
+
+
+
+@end

+ 14 - 0
wfclient/WFChatClient/Model/WFCCChatroomMemberInfo.h

@@ -0,0 +1,14 @@
+//
+//  WFCCChatroomInfo.h
+//  WFChatClient
+//
+//  Created by heavyrain lee on 2018/8/24.
+//  Copyright © 2018 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface WFCCChatroomMemberInfo : NSObject
+@property(nonatomic, assign)int memberCount;
+@property(nonatomic, strong)NSArray<NSString *> *members;
+@end

+ 15 - 0
wfclient/WFChatClient/Model/WFCCChatroomMemberInfo.m

@@ -0,0 +1,15 @@
+//
+//  WFCCChatroomInfo.m
+//  WFChatClient
+//
+//  Created by heavyrain lee on 2018/8/24.
+//  Copyright © 2018 WildFireChat. All rights reserved.
+//
+
+#import "WFCCChatroomMemberInfo.h"
+
+@implementation WFCCChatroomMemberInfo
+
+
+
+@end

+ 57 - 0
wfclient/WFChatClient/Model/WFCCConversation.h

@@ -0,0 +1,57 @@
+//
+//  WFCCConversation.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ 会话类型
+
+ - Single_Type: 单聊
+ - Group_Type: 群组
+ - Chatroom_Type: 聊天室
+ */
+typedef NS_ENUM(NSInteger, WFCCConversationType) {
+    Single_Type,
+    Group_Type,
+    Chatroom_Type,
+    Channel_Type,
+} ;
+
+/**
+ 会话
+ */
+@interface WFCCConversation : NSObject
+
+/**
+ 构造方法
+
+ @param type 会话类型
+ @param target 目标会话ID
+ @param line 默认传0
+ @return 会话
+ */
++(instancetype)conversationWithType:(WFCCConversationType)type
+                             target:(NSString *)target
+                               line:(int)line;
+
+/**
+ 会话类型
+ */
+@property (nonatomic, assign)WFCCConversationType type;
+
+/**
+ 目标会话ID,单聊为对方用户ID,群聊为群ID
+ */
+@property (nonatomic, strong)NSString *target;
+
+/**
+ 默认为0
+ */
+@property (nonatomic, assign)int line;
+
+@end

+ 28 - 0
wfclient/WFChatClient/Model/WFCCConversation.m

@@ -0,0 +1,28 @@
+//
+//  WFCCConversation.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCConversation.h"
+
+@implementation WFCCConversation
++(instancetype)conversationWithType:(WFCCConversationType)type target:(NSString *)target line:(int)line {
+    WFCCConversation *conversation = [[WFCCConversation alloc] init];
+    conversation.type = type;
+    conversation.target = target;
+    conversation.line = line;
+    return conversation;
+}
+- (BOOL)isEqual:(id)object {
+    if ([object isMemberOfClass:[WFCCConversation class]]) {
+        WFCCConversation *o = (WFCCConversation *)object;
+        if (self.type == o.type && [self.target isEqual:o.target] && self.line == o.line) {
+            return YES;
+        }
+    }
+    return NO;
+}
+@end

+ 56 - 0
wfclient/WFChatClient/Model/WFCCConversationInfo.h

@@ -0,0 +1,56 @@
+//
+//  WFCCConversationInfo.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/29.
+//  Copyright © 2017年 wildfire chat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "WFCCConversation.h"
+#import "WFCCMessage.h"
+#import "WFCCUnreadCount.h"
+
+/**
+ 会话信息
+ */
+@interface WFCCConversationInfo : NSObject
+
+/**
+ 会话
+ */
+@property (nonatomic, strong)WFCCConversation *conversation;
+
+/**
+ 最后一条消息
+ */
+@property (nonatomic, strong)WFCCMessage *lastMessage;
+
+/**
+ 草稿
+ */
+@property (nonatomic, strong)NSString *draft;
+
+/**
+ 最后一条消息的时间戳
+ */
+@property (nonatomic, assign)long long timestamp;
+
+/**
+ 未读数
+ */
+@property (nonatomic, strong)WFCCUnreadCount *unreadCount;
+
+/**
+ 是否置顶
+ */
+@property (nonatomic, assign)BOOL isTop;
+
+/**
+ 是否设置了免打扰
+ */
+@property (nonatomic, assign)BOOL isSilent;
+
+@end
+
+

+ 14 - 0
wfclient/WFChatClient/Model/WFCCConversationInfo.m

@@ -0,0 +1,14 @@
+//
+//  WFCCConversationInfo.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/29.
+//  Copyright © 2017年 wildfire chat. All rights reserved.
+//
+
+#import "WFCCConversationInfo.h"
+
+
+@implementation WFCCConversationInfo
+
+@end

+ 37 - 0
wfclient/WFChatClient/Model/WFCCConversationSearchInfo.h

@@ -0,0 +1,37 @@
+//
+//  WFCCConversationSearchInfo.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/10/22.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "WFCCConversation.h"
+#import "WFCCMessage.h"
+
+/**
+ 会话搜索信息
+ */
+@interface WFCCConversationSearchInfo : NSObject
+
+/**
+ 会话
+ */
+@property (nonatomic, strong)WFCCConversation *conversation;
+
+/**
+ 命中的消息
+ */
+@property (nonatomic, strong)WFCCMessage *marchedMessage;
+
+/**
+ 命中数量
+ */
+@property (nonatomic, assign)int marchedCount;
+
+/**
+ 搜索关键字
+ */
+@property (nonatomic, strong)NSString *keyword;
+@end

+ 13 - 0
wfclient/WFChatClient/Model/WFCCConversationSearchInfo.m

@@ -0,0 +1,13 @@
+//
+//  WFCCConversationSearchInfo.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/10/22.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCConversationSearchInfo.h"
+
+@implementation WFCCConversationSearchInfo
+
+@end

+ 46 - 0
wfclient/WFChatClient/Model/WFCCFriendRequest.h

@@ -0,0 +1,46 @@
+//
+//  WFCCFriendRequest.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/10/17.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ 好友请求
+ */
+@interface WFCCFriendRequest : NSObject
+
+/**
+ 方向
+ */
+@property(nonatomic, assign)int direction;
+
+/**
+ ID
+ */
+@property(nonatomic, strong)NSString *target;
+
+/**
+ 请求说明
+ */
+@property(nonatomic, strong)NSString *reason;
+
+/**
+ 接受状态
+ */
+@property(nonatomic, assign)int status;
+
+/**
+ 已读
+ */
+@property(nonatomic, assign)int readStatus;
+
+/**
+ 发起时间
+ */
+@property(nonatomic, assign)long long timestamp;
+
+@end

+ 13 - 0
wfclient/WFChatClient/Model/WFCCFriendRequest.m

@@ -0,0 +1,13 @@
+//
+//  WFCCFriendRequest.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/10/17.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCFriendRequest.h"
+
+@implementation WFCCFriendRequest
+
+@end

+ 64 - 0
wfclient/WFChatClient/Model/WFCCGroupInfo.h

@@ -0,0 +1,64 @@
+//
+//  WFCCGroupInfo.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ 群类型
+
+ - GroupType_Normal: 管理员和群主才能加人和退群,修改群信息
+ - GroupType_Free: 所有人都能加人、退群和修改群信息
+ - GroupType_Restricted: 普通成员只能退群,不能加人和修改群信息
+ */
+typedef NS_ENUM(NSInteger, WFCCGroupType) {
+    GroupType_Normal = 0,
+    GroupType_Free = 1,
+    GroupType_Restricted = 2,
+} ;
+
+/**
+ 群信息
+ */
+@interface WFCCGroupInfo : NSObject
+
+/**
+ 群类型
+ */
+@property (nonatomic, assign)WFCCGroupType type;
+
+/**
+ 群ID
+ */
+@property (nonatomic, strong)NSString *target;
+
+/**
+ 群名
+ */
+@property (nonatomic, strong)NSString *name;
+
+/**
+ 群头像
+ */
+@property (nonatomic, strong)NSString *portrait;
+
+/**
+ 成员数
+ */
+@property (nonatomic, assign)NSUInteger memberCount;
+
+/**
+ 群主
+ */
+@property (nonatomic, strong)NSString *owner;
+
+/**
+ 扩展信息
+ */
+@property (nonatomic, strong)NSData *extra;
+
+@end

+ 13 - 0
wfclient/WFChatClient/Model/WFCCGroupInfo.m

@@ -0,0 +1,13 @@
+//
+//  WFCCGroupInfo.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/8/16.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCGroupInfo.h"
+
+@implementation WFCCGroupInfo
+
+@end

+ 49 - 0
wfclient/WFChatClient/Model/WFCCGroupMember.h

@@ -0,0 +1,49 @@
+//
+//  WFCCGroupMember.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/10/30.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ 群成员类型
+
+ - Member_Type_Normal: 普通成员
+ - Member_Type_Manager: 管理员
+ - Member_Type_Owner: 群主
+ */
+typedef NS_ENUM(NSInteger, WFCCGroupMemberType) {
+    Member_Type_Normal = 0,
+    Member_Type_Manager,
+    Member_Type_Owner,
+} ;
+
+/**
+ 群成员信息
+ */
+@interface WFCCGroupMember : NSObject
+
+/**
+ 群ID
+ */
+@property(nonatomic, strong)NSString *groupId;
+
+/**
+ 群成员ID
+ */
+@property(nonatomic, strong)NSString *memberId;
+
+/**
+ 群昵称
+ */
+@property(nonatomic, strong)NSString *alias;
+
+/**
+ 群成员类型
+ */
+@property(nonatomic, assign)WFCCGroupMemberType type;
+
+@end

+ 13 - 0
wfclient/WFChatClient/Model/WFCCGroupMember.m

@@ -0,0 +1,13 @@
+//
+//  WFCCGroupMember.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/10/30.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCGroupMember.h"
+
+@implementation WFCCGroupMember
+
+@end

+ 37 - 0
wfclient/WFChatClient/Model/WFCCGroupSearchInfo.h

@@ -0,0 +1,37 @@
+//
+//  WFCCGroupSearchInfo.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/10/22.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "WFCCGroupInfo.h"
+
+/**
+ 群组搜索信息
+ */
+@interface WFCCGroupSearchInfo : NSObject
+
+/**
+ 命中的群组
+ */
+@property (nonatomic, strong)WFCCGroupInfo *groupInfo;
+
+/**
+ 命中的类型 0, 名字群组名字; 1,命中群成员名称;2,都命中
+ */
+@property (nonatomic, assign)int marchType;
+
+/**
+ 命中群成员名称
+ */
+@property (nonatomic, strong)NSArray *marchedMemberNames;
+
+/**
+ 搜索的关键字
+ */
+@property (nonatomic, strong)NSString *keyword;
+
+@end

+ 13 - 0
wfclient/WFChatClient/Model/WFCCGroupSearchInfo.m

@@ -0,0 +1,13 @@
+//
+//  WFCCGroupSearchInfo.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/10/22.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCGroupSearchInfo.h"
+
+@implementation WFCCGroupSearchInfo
+
+@end

+ 20 - 0
wfclient/WFChatClient/Model/WFCCUnreadCount.h

@@ -0,0 +1,20 @@
+//
+//  WFCCUnreadCount.h
+//  WFChatClient
+//
+//  Created by WF Chat on 2018/9/30.
+//  Copyright © 2018 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WFCCUnreadCount : NSObject
++(instancetype)countOf:(int)unread mention:(int)mention mentionAll:(int)mentionAll;
+@property(nonatomic, assign)int unread;
+@property(nonatomic, assign)int unreadMention;
+@property(nonatomic, assign)int unreadMentionAll;
+@end
+
+NS_ASSUME_NONNULL_END

+ 19 - 0
wfclient/WFChatClient/Model/WFCCUnreadCount.m

@@ -0,0 +1,19 @@
+//
+//  WFCCUnreadCount.m
+//  WFChatClient
+//
+//  Created by WF Chat on 2018/9/30.
+//  Copyright © 2018 WildFireChat. All rights reserved.
+//
+
+#import "WFCCUnreadCount.h"
+
+@implementation WFCCUnreadCount
++(instancetype)countOf:(int)unread mention:(int)mention mentionAll:(int)mentionAll {
+    WFCCUnreadCount *count = [[WFCCUnreadCount alloc] init];
+    count.unread = unread;
+    count.unreadMention = mention;
+    count.unreadMentionAll = mentionAll;
+    return count;
+}
+@end

+ 78 - 0
wfclient/WFChatClient/Model/WFCCUserInfo.h

@@ -0,0 +1,78 @@
+//
+//  WFCCUserInfo.h
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/29.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ 用户信息
+ */
+@interface WFCCUserInfo : NSObject
+
+/**
+ 用户ID
+ */
+@property (nonatomic, strong)NSString *userId;
+
+/**
+ 名称
+ */
+@property (nonatomic, strong)NSString *name;
+
+/**
+ 显示的名称
+ */
+@property (nonatomic, strong)NSString *displayName;
+
+/**
+ 性别
+ */
+@property (nonatomic, assign)int gender;
+
+/**
+ 头像
+ */
+@property (nonatomic, strong)NSString *portrait;
+
+/**
+ 手机号
+ */
+@property (nonatomic, strong)NSString *mobile;
+
+/**
+ 邮箱
+ */
+@property (nonatomic, strong)NSString *email;
+
+/**
+ 地址
+ */
+@property (nonatomic, strong)NSString *address;
+
+/**
+ 公司信息
+ */
+@property (nonatomic, strong)NSString *company;
+
+/**
+ 社交信息
+ */
+@property (nonatomic, strong)NSString *social;
+
+/**
+ 扩展信息
+ */
+@property (nonatomic, strong)NSString *extra;
+
+/**
+ 更新时间
+ */
+@property (nonatomic, assign)long long updateDt;
+
+- (void)cloneFrom:(WFCCUserInfo *)other;
+
+@end

+ 27 - 0
wfclient/WFChatClient/Model/WFCCUserInfo.m

@@ -0,0 +1,27 @@
+//
+//  WFCCUserInfo.m
+//  WFChatClient
+//
+//  Created by heavyrain on 2017/9/29.
+//  Copyright © 2017年 WildFireChat. All rights reserved.
+//
+
+#import "WFCCUserInfo.h"
+
+@implementation WFCCUserInfo
+- (void)cloneFrom:(WFCCUserInfo *)other {
+    self.userId = other.userId;
+    self.name = other.name;
+    self.displayName = other.displayName;
+    self.portrait = other.portrait;
+    self.gender = other.gender;
+    self.mobile = other.mobile;
+    self.email = other.email;
+    self.address = other.address;
+    self.company = other.company;
+    self.social = other.social;
+    self.extra = other.extra;
+    self.updateDt = other.updateDt;
+    self.social = other.social;
+}
+@end

+ 76 - 0
wfclient/WFChatClient/Proto/mars.framework/Headers/app/app.h

@@ -0,0 +1,76 @@
+// Tencent is pleased to support the open source community by making Mars available.
+// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+// Licensed under the MIT License (the "License"); you may not use this file except in 
+// compliance with the License. You may obtain a copy of the License at
+// http://opensource.org/licenses/MIT
+
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+ * appcomm.h
+ *
+ *  Created on: 2016年3月3日
+ *      Author: caoshaokun
+ */
+
+#ifndef APPCOMM_INTERFACE_APPCOMM_H_
+#define APPCOMM_INTERFACE_APPCOMM_H_
+
+#include <string>
+#include <stdint.h>
+
+#include "mars/comm/comm_data.h"
+
+namespace mars {
+namespace app {
+
+struct AccountInfo {
+	AccountInfo():uin(0), is_logoned(false){}
+	int64_t uin;
+	std::string username;
+	bool is_logoned;
+};
+
+    typedef enum {
+        PlatformType_UNSET = 0,
+        PlatformType_iOS = 1,
+        PlatformType_Android = 2,
+        PlatformType_Windows = 3,
+        PlatformType_OSX = 4,
+        PlatformType_WEB = 5
+    } PlatformType;
+    
+struct DeviceInfo {
+    //clientid
+    std::string clientid;
+    //platform  ios/android/web/osx/windows etc
+    PlatformType platform;
+    
+    std::string packagename;
+    int pushtype;
+    //设备型号
+    std::string device;
+    //设备版本号
+    std::string deviceversion;
+    //设备名称 某某的iphone
+    std::string phonename;
+    std::string language;
+    std::string carriername;
+    std::string appversion;
+    std::string sdkversion;
+};
+    
+extern mars::comm::ProxyInfo GetProxyInfo(const std::string& _host);
+extern std::string GetAppFilePath();
+extern AccountInfo GetAccountInfo();
+extern std::string GetUserName();
+extern std::string GetRecentUserName();
+extern unsigned int GetClientVersion();
+extern DeviceInfo GetDeviceInfo();
+}}
+
+#endif /* APPCOMM_INTERFACE_APPCOMM_H_ */

+ 53 - 0
wfclient/WFChatClient/Proto/mars.framework/Headers/app/app_logic.h

@@ -0,0 +1,53 @@
+// Tencent is pleased to support the open source community by making Mars available.
+// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+// Licensed under the MIT License (the "License"); you may not use this file except in 
+// compliance with the License. You may obtain a copy of the License at
+// http://opensource.org/licenses/MIT
+
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+ * app_logic.h
+ *
+ *  Created on: 2016/3/3
+ *      Author: caoshaokun
+ */
+
+#ifndef APPCOMM_INTERFACE_APPCOMM_LOGIC_H_
+#define APPCOMM_INTERFACE_APPCOMM_LOGIC_H_
+
+#include <string>
+
+#include "mars/app/app.h"
+#include "mars/comm/comm_data.h"
+
+class AutoBuffer;
+
+namespace mars {
+namespace app {
+
+	class Callback {
+	public:
+		virtual ~Callback() {};
+        
+        virtual bool GetProxyInfo(const std::string& _host, mars::comm::ProxyInfo& _proxy_info) { return false; }
+
+        virtual std::string GetAppFilePath() = 0;
+        
+		virtual AccountInfo GetAccountInfo() = 0;
+
+		virtual unsigned int GetClientVersion() = 0;
+
+		virtual DeviceInfo GetDeviceInfo() = 0;
+
+	};
+
+	void SetCallback(Callback* const callback);
+}}
+
+
+#endif /* APPCOMM_INTERFACE_APPCOMM_LOGIC_H_ */

+ 37 - 0
wfclient/WFChatClient/Proto/mars.framework/Headers/baseevent/base_logic.h

@@ -0,0 +1,37 @@
+// Tencent is pleased to support the open source community by making Mars available.
+// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+// Licensed under the MIT License (the "License"); you may not use this file except in 
+// compliance with the License. You may obtain a copy of the License at
+// http://opensource.org/licenses/MIT
+
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+ * baseprj.h
+ *
+ *  Created on: 2014-7-7
+ *      Author: yerungui
+ */
+
+#ifndef MARS_BASELOGIC_H_
+#define MARS_BASELOGIC_H_
+
+#include <stdint.h>
+
+namespace mars{
+namespace baseevent{
+    void OnCreate();
+    void OnDestroy();
+    void OnSingalCrash(int _sig);
+    void OnExceptionCrash();
+    void OnForeground(bool _isforeground);
+    void OnNetworkChange();
+    void OnNetworkDataChange(const char* _tag, int32_t _send, int32_t _recv);
+}
+}
+
+#endif /* MARS_BASELOGIC_H_ */

+ 36 - 0
wfclient/WFChatClient/Proto/mars.framework/Headers/comm/ThreadOperationQueue.h

@@ -0,0 +1,36 @@
+// Tencent is pleased to support the open source community by making Mars available.
+// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+// Licensed under the MIT License (the "License"); you may not use this file except in 
+// compliance with the License. You may obtain a copy of the License at
+// http://opensource.org/licenses/MIT
+
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+//  ThreadOperationQueue.h
+//  MicroMessenger
+//
+//  Created by yerungui on 12-12-18.
+//
+
+#ifndef __MicroMessenger__ThreadOperationQueue__
+#define __MicroMessenger__ThreadOperationQueue__
+
+#import <Foundation/Foundation.h>
+
+@interface ThreadQueue : NSObject
+{}
+
++(BOOL) RunWithTarget:(id)target selector:(SEL)sel object:(id)arg;
+@end
+
+
+extern "C" BOOL RunWithTarget(void (*_funp)(void*), void* _arg);
+extern "C" BOOL RunWithTargetNoParam(void (*_fun)());
+
+
+#endif /* defined(__MicroMessenger__ThreadOperationQueue__) */

+ 135 - 0
wfclient/WFChatClient/Proto/mars.framework/Headers/comm/autobuffer.h

@@ -0,0 +1,135 @@
+// Tencent is pleased to support the open source community by making Mars available.
+// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+// Licensed under the MIT License (the "License"); you may not use this file except in 
+// compliance with the License. You may obtain a copy of the License at
+// http://opensource.org/licenses/MIT
+
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+
+#ifndef COMM_AUTOBUFFER_H_
+#define COMM_AUTOBUFFER_H_
+
+#include <sys/types.h>
+#include <string.h>
+
+class AutoBuffer {
+  public:
+    enum TSeek {
+        ESeekStart,
+        ESeekCur,
+        ESeekEnd,
+    };
+
+  public:
+    explicit AutoBuffer(size_t _size = 128);
+    explicit AutoBuffer(void* _pbuffer, size_t _len, size_t _size = 128);
+    explicit AutoBuffer(const void* _pbuffer, size_t _len, size_t _size = 128);
+    ~AutoBuffer();
+
+    void AllocWrite(size_t _readytowrite, bool _changelength = true);
+    void AddCapacity(size_t _len);
+
+    template<class T> void Write(const T& _val)
+    { Write(&_val, sizeof(_val));}
+
+    template<class T> void Write(off_t& _pos, const T& _val)
+    { Write(_pos, &_val, sizeof(_val));}
+
+    template<class T> void Write(const off_t& _pos, const T& _val)
+    { Write(_pos, &_val, sizeof(_val));}
+
+    void Write(const char* const _val)
+    { Write(_val, strlen(_val));}
+
+    void Write(off_t& _pos, const char* const _val)
+    { Write(_pos, _val, strlen(_val));}
+
+    void Write(const off_t& _pos, const char* const _val)
+    { Write(_pos, _val, strlen(_val));}
+
+    void Write(const AutoBuffer& _buffer);
+    void Write(const void* _pbuffer, size_t _len);
+    void Write(off_t& _pos, const AutoBuffer& _buffer);
+    void Write(off_t& _pos, const void* _pbuffer, size_t _len);
+    void Write(const off_t& _pos, const AutoBuffer& _buffer);
+    void Write(const off_t& _pos, const void* _pbuffer, size_t _len);
+    void Write(TSeek _seek, const void* _pbuffer, size_t _len);
+
+    template<class T> size_t Read(T& _val)
+    { return Read(&_val, sizeof(_val)); }
+
+    template<class T> size_t Read(off_t& _pos, T& _val) const
+    { return Read(_pos, &_val, sizeof(_val)); }
+
+    template<class T> size_t Read(const off_t& _pos, T& _val) const
+    { return Read(_pos, &_val, sizeof(_val)); }
+
+    size_t Read(void* _pbuffer, size_t _len);
+    size_t Read(AutoBuffer& _rhs , size_t _len);
+
+    size_t Read(off_t& _pos, void* _pbuffer, size_t _len) const;
+    size_t Read(off_t& _pos, AutoBuffer& _rhs, size_t _len) const;
+
+    size_t Read(const off_t& _pos, void* _pbuffer, size_t _len) const;
+    size_t Read(const off_t& _pos, AutoBuffer& _rhs, size_t _len) const;
+
+    off_t Move(off_t _move_len);
+
+    void Seek(off_t _offset,  TSeek _eorigin);
+    void Length(off_t _pos, size_t _lenght);
+
+    void* Ptr(off_t _offset=0);
+    void* PosPtr();
+    const void* Ptr(off_t _offset=0) const;
+    const void* PosPtr() const;
+
+    off_t Pos() const;
+    size_t PosLength() const;
+    size_t Length() const;
+    size_t Capacity() const;
+
+    void Attach(void* _pbuffer, size_t _len);
+    void Attach(AutoBuffer& _rhs);
+    void* Detach(size_t* _plen = NULL);
+
+    void Reset();
+
+  private:
+    void __FitSize(size_t _len);
+
+  private:
+    AutoBuffer(const AutoBuffer& _rhs);
+    AutoBuffer& operator = (const AutoBuffer& _rhs);
+
+  private:
+    unsigned char* parray_;
+    off_t pos_;
+    size_t length_;
+    size_t capacity_;
+    size_t malloc_unitsize_;
+};
+
+extern const AutoBuffer KNullAtuoBuffer;
+
+template <class S> class copy_wrapper_helper;
+
+template <>
+class copy_wrapper_helper<AutoBuffer> {
+  public:
+    static void copy_constructor(AutoBuffer& _lhs, AutoBuffer& _rhs)
+    { _lhs.Attach(_rhs); }
+
+    static void copy_constructor(AutoBuffer& _lhs, const AutoBuffer& _rhs)
+    { _lhs.Attach(const_cast<AutoBuffer&>(_rhs)); }
+
+    static void destructor(AutoBuffer& _delobj) {}
+};
+
+#endif	//COMM_AUTOBUFFER_H_
+

+ 60 - 0
wfclient/WFChatClient/Proto/mars.framework/Headers/comm/comm_data.h

@@ -0,0 +1,60 @@
+
+// Tencent is pleased to support the open source community by making Mars available.
+// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+// Licensed under the MIT License (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://opensource.org/licenses/MIT
+
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+//  comm_data.h
+//  comm
+//
+//  Created by garry on 2017/2/17.
+//
+
+#ifndef comm_data_h
+#define comm_data_h
+
+#include <string>
+#include <stdint.h>
+
+namespace mars {
+    namespace comm {
+        
+enum ProxyType {
+    kProxyNone = 0,
+    kProxyHttpTunel,
+    kProxySocks5,
+    kProxyHttp,
+};
+        
+class ProxyInfo {
+public:
+    ProxyInfo():ProxyInfo(kProxyNone, "", "", 0, "", ""){}
+    ProxyInfo(ProxyType _type, const std::string& _host, const std::string& _ip, uint16_t _port, const std::string& _username, const std::string& _password)
+    :type(_type), host(_host), ip(_ip), port(_port), username(_username), password(_password){}
+    
+    bool IsValid() const {
+        return kProxyNone == type || ((!ip.empty() || !host.empty()) && port > 0);
+    }
+    
+public:
+    ProxyType type;
+    std::string host;
+    std::string ip;
+    uint16_t port;
+    std::string username;
+    std::string password;
+};
+        
+    
+    }
+}
+
+#endif /* comm_data_h */

+ 55 - 0
wfclient/WFChatClient/Proto/mars.framework/Headers/comm/has_member.h

@@ -0,0 +1,55 @@
+// Tencent is pleased to support the open source community by making Mars available.
+// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+// Licensed under the MIT License (the "License"); you may not use this file except in 
+// compliance with the License. You may obtain a copy of the License at
+// http://opensource.org/licenses/MIT
+
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+
+//============================================================================
+// Name        : has_member.h
+// Author      :
+// Version     :
+// Copyright   : Your copyright notice
+// Description : Hello World in C++, Ansi-style
+//============================================================================
+
+#ifndef COMM_HAS_MEMBER_H_
+#define COMM_HAS_MEMBER_H_
+
+template <bool TYPE>
+struct bool_type {
+};
+
+
+#define DEFINE_HAS_MEMBER_WITH_TYPE(member_name, member_type) \
+    template <typename T>\
+    class has_##member_name {\
+      private:\
+        struct yes_type { char x[1]; };\
+        struct no_type { char x[2]; };\
+        template <member_type (T::*)> struct tester;\
+        template <typename U> static yes_type test(tester<&U::member_name>*);\
+        template <typename U> static no_type test(...);\
+      public:\
+        static const bool value = (sizeof(test<T>(0)) == sizeof(yes_type));\
+    };
+
+#define DEFINE_HAS_MEMBER(member_name) \
+    template <typename T>\
+    class has_##member_name {\
+      private:\
+        struct yes_type { char x[1]; };\
+        struct no_type { char x[2]; };\
+        template <int> struct tester;\
+        template <typename U> static yes_type test(tester<sizeof(&U::member_name)>*);\
+        template <typename U> static no_type test(...);\
+      public:\
+        static const bool value = (sizeof(test<T>(0)) == sizeof(yes_type));\
+    };
+
+#endif

+ 356 - 0
wfclient/WFChatClient/Proto/mars.framework/Headers/comm/http.h

@@ -0,0 +1,356 @@
+// Tencent is pleased to support the open source community by making Mars available.
+// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+// Licensed under the MIT License (the "License"); you may not use this file except in 
+// compliance with the License. You may obtain a copy of the License at
+// http://opensource.org/licenses/MIT
+
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/*
+ * HttpRequest.h
+ *
+ *  Created on: 2013-12-5
+ *      Author: yerungui
+ */
+
+#ifndef HTTP_H_
+#define HTTP_H_
+
+#include <string>
+#include <map>
+
+#include "autobuffer.h"
+
+namespace http {
+
+struct less {
+	bool operator()(const std::string& __x, const std::string& __y) const;
+};
+
+enum THttpVersion {
+    kVersion_0_9,
+    kVersion_1_0,
+    kVersion_1_1,
+    kVersion_2_0,
+    kVersion_Unknow,
+};
+
+const char* const kHttpVersionString[] = {
+    "HTTP/0.9",
+    "HTTP/1.0",
+    "HTTP/1.1",
+    "HTTP/2",
+    "version_unknown",
+};
+
+enum TCsMode {
+    kRequest,
+    kRespond,
+};
+
+class RequestLine {
+  public:
+    enum THttpMethod {
+        kUnknown = 0,
+        kGet,
+        kPost,
+        kOptions,
+        kHead,
+        kPut,
+        kDelete,
+        kTrace,
+        kConnect,
+        kMax,
+    };
+
+    static const char* const kHttpMethodString[kMax];
+
+  public:
+    RequestLine();
+    RequestLine(THttpMethod _httpMethod, const char* _url, THttpVersion _httpVersion);
+    // RequestLine(const RequestLine&);
+    // RequestLine& operator=(const RequestLine&);
+
+  public:
+    void Method(THttpMethod _method);
+    THttpMethod Method() const;
+
+    void Version(THttpVersion _version);
+    THttpVersion Version() const;
+
+    void Url(const std::string& _url);
+    std::string Url() const;
+
+    std::string ToString() const;
+    bool FromString(const std::string& _requestline);
+
+  private:
+    THttpMethod http_method_;
+    std::string req_url_;
+    THttpVersion http_version_;
+};
+
+class StatusLine {
+  public:
+    StatusLine();
+    StatusLine(THttpVersion _httpversion, int _statuscode, const std::string& _reasonphrase);
+    // StatusLine(const StatusLine&);
+    // StatusLine& operator=(const StatusLine&);
+
+  public:
+    void Version(THttpVersion _version);
+    THttpVersion Version() const;
+
+    void StatusCode(int _statuscode);
+    int StatusCode() const;
+
+    void ReasonPhrase(const std::string& _reasonphrase);
+    std::string ReasonPhrase() const;
+
+    std::string ToString() const;
+    bool FromString(const std::string& _statusline);
+
+  private:
+    THttpVersion http_version_;
+    int statuscode_;
+    std::string reason_phrase_;
+};
+
+
+class HeaderFields {
+  public:
+    // HeaderFields(const HeaderFields&);
+    // HeaderFields& operator=(const HeaderFields&);
+
+  public:
+    static std::pair<const std::string, std::string> MakeContentLength(int _len);
+    static std::pair<const std::string, std::string> MakeTransferEncodingChunked();
+    static std::pair<const std::string, std::string> MakeConnectionClose();
+    static std::pair<const std::string, std::string> MakeConnectionKeepalive();
+    static std::pair<const std::string, std::string> MakeAcceptAll();
+    static std::pair<const std::string, std::string> MakeAcceptEncodingDefalte();
+    static std::pair<const std::string, std::string> MakeAcceptEncodingGzip();
+    static std::pair<const std::string, std::string> MakeCacheControlNoCache();
+    static std::pair<const std::string, std::string> MakeContentTypeOctetStream();
+
+    static const char* const KStringHost;
+    static const char* const KStringAccept;
+    static const char* const KStringUserAgent;
+    static const char* const KStringCacheControl;
+    static const char* const KStringConnection;
+    static const char* const kStringProxyConnection;
+    static const char* const kStringProxyAuthorization;
+    static const char* const KStringContentType;
+    static const char* const KStringContentLength;
+    static const char* const KStringTransferEncoding;
+    static const char* const kStringContentEncoding;
+    static const char* const KStringAcceptEncoding;
+    static const char* const KStringContentRange;
+    static const char* const KStringMicroMessenger;
+    static const char* const KStringRange;
+    static const char* const KStringLocation;
+    static const char* const KStringReferer;
+
+    void HeaderFiled(const char* _name, const char* _value);
+    void HeaderFiled(const std::pair<const std::string, std::string>& _headerfield);
+    void HeaderFiled(const HeaderFields& _headerfields);
+    const char* HeaderField(const char* _key) const;
+    std::map<const std::string, std::string, less>& GetHeaders() {return headers_;}
+
+    bool IsTransferEncodingChunked();
+    int ContentLength();
+
+    bool ContentRange(int* start, int* end, int* total);
+
+    const std::string ToString() const;
+
+  private:
+    std::map<const std::string, std::string, less> headers_;
+};
+
+class IBlockBodyProvider {
+  public:
+    virtual ~IBlockBodyProvider() {}
+
+    virtual bool Data(AutoBuffer& _body) = 0;
+    virtual bool FillData(AutoBuffer& _body) = 0;
+    virtual size_t Length() const = 0;
+};
+
+class BufferBodyProvider : public IBlockBodyProvider {
+  public:
+    bool Data(AutoBuffer& _body) {
+        if (!buffer_.Ptr()) return false;
+
+        _body.Write(buffer_.Ptr(), buffer_.Length());
+        buffer_.Reset();
+        return true;
+    }
+    bool FillData(AutoBuffer& _body) {
+        if (!buffer_.Ptr()) return false;
+
+        _body.Write(buffer_.Ptr(), buffer_.Length());
+        buffer_.Reset();
+        return true;
+    }
+    size_t Length() const {return buffer_.Length();}
+    AutoBuffer& Buffer() {return buffer_;}
+  private:
+    AutoBuffer buffer_;
+};
+
+class IStreamBodyProvider {
+  public:
+    virtual ~IStreamBodyProvider() {}
+
+    virtual bool HaveData() const = 0;
+    virtual bool Data(AutoBuffer& _body) = 0;
+
+    virtual bool Eof() const = 0;
+    const char* EofData();
+
+  protected:
+    static void AppendHeader(AutoBuffer& _body, size_t _length);
+    static void AppendTail(AutoBuffer& _body);
+};
+
+class Builder {
+  public:
+    Builder(TCsMode _csmode);
+    ~Builder();
+
+  private:
+    Builder(const Builder&);
+    Builder& operator=(const Builder&);
+
+  public:
+    RequestLine& Request();
+    StatusLine& Status();
+    const RequestLine& Request() const;
+    const StatusLine& Status() const;
+
+    HeaderFields& Fields();
+    const HeaderFields& Fields() const;
+
+    void BlockBody(IBlockBodyProvider* _body, bool _manage);
+    void StreamBody(IStreamBodyProvider* _body, bool _manage);
+    IBlockBodyProvider* BlockBody();
+    IStreamBodyProvider* StreamBody();
+    const IBlockBodyProvider* BlockBody() const;
+    const IStreamBodyProvider* StreamBody() const;
+
+    bool HeaderToBuffer(AutoBuffer& _header);
+    bool HttpToBuffer(AutoBuffer& _http);
+
+  private:
+    TCsMode csmode_;
+
+    StatusLine statusline_;
+    RequestLine requestline_;
+
+    HeaderFields headfields_;
+
+    IBlockBodyProvider* blockbody_;
+    IStreamBodyProvider* streambody_;
+    bool is_manage_body_;
+};
+
+class BodyReceiver {
+  public:
+    BodyReceiver(): total_length_(0) {}
+    virtual ~BodyReceiver() {}
+
+    virtual void AppendData(const void* _body, size_t _length) { total_length_ += _length;}
+    virtual void EndData() {}
+    size_t Length() const {return total_length_;}
+
+  private:
+    size_t total_length_;
+};
+
+class MemoryBodyReceiver : public BodyReceiver {
+  public:
+	MemoryBodyReceiver(AutoBuffer& _buf)
+    : body_(_buf) {}
+    virtual void AppendData(const void* _body, size_t _length) {
+        BodyReceiver::AppendData(_body, _length);
+        body_.Write(_body, _length);
+    }
+    virtual void EndData() {}
+
+  private:
+    AutoBuffer& body_;
+};
+
+class Parser {
+  public:
+    enum TRecvStatus {
+        kStart,
+        kFirstLine,
+        kFirstLineError,
+        kHeaderFields,
+        kHeaderFieldsError,
+        kBody,
+        kBodyError,
+        kEnd,
+    };
+
+  public:
+    Parser(BodyReceiver* _body = new BodyReceiver(), bool _manage = true);
+    ~Parser();
+
+  private:
+    Parser(const Parser&);
+    Parser& operator=(const Parser&);
+
+  public:
+    TRecvStatus Recv(const void* _buffer, size_t _length);
+    TRecvStatus Recv(AutoBuffer& _recv_buffer);
+    TRecvStatus RecvStatus() const;
+
+    TCsMode CsMode() const;
+    bool FirstLineReady() const;
+    const RequestLine& Request() const;
+    const StatusLine& Status() const;
+    const AutoBuffer& HeaderBuffer() const;
+
+    bool FieldsReady() const;
+    HeaderFields& Fields();
+    const HeaderFields& Fields() const;
+    size_t HeaderLength() const;
+
+    bool BodyReady() const;
+    bool BodyRecving() const;
+    BodyReceiver& Body();
+    const BodyReceiver& Body() const;
+
+    bool Error() const;
+    bool Success() const;
+
+  private:
+    TRecvStatus recvstatus_;
+    AutoBuffer  recvbuf_;
+    AutoBuffer  headerbuf_;
+    bool response_header_ready_;
+    TCsMode csmode_;
+
+    StatusLine statusline_;
+    RequestLine requestline_;
+
+    HeaderFields headfields_;
+
+    BodyReceiver* bodyreceiver_;
+    bool is_manage_body_;
+    size_t headerlength_;
+};
+
+// void testChunk();
+
+
+} /* namespace http */
+#endif /* HTTPREQUEST_H_ */

+ 51 - 0
wfclient/WFChatClient/Proto/mars.framework/Headers/comm/local_ipstack.h

@@ -0,0 +1,51 @@
+// Tencent is pleased to support the open source community by making Mars available.
+// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+
+// Licensed under the MIT License (the "License"); you may not use this file except in 
+// compliance with the License. You may obtain a copy of the License at
+// http://opensource.org/licenses/MIT
+
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+//  IPv6_only.hpp
+//  comm
+//
+//  Created by yerungui on 16/1/14.
+//
+
+#ifndef __ip_type__
+#define __ip_type__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum TLocalIPStack {
+    ELocalIPStack_None = 0,
+    ELocalIPStack_IPv4 = 1,
+    ELocalIPStack_IPv6 = 2,
+    ELocalIPStack_Dual = 3,
+};
+    
+const char* const TLocalIPStackStr[] = {
+    "ELocalIPStack_None",
+    "ELocalIPStack_IPv4",
+    "ELocalIPStack_IPv6",
+    "ELocalIPStack_Dual",
+};
+
+TLocalIPStack local_ipstack_detect();
+    
+#ifdef __cplusplus
+}
+#endif
+
+#include <string>
+TLocalIPStack local_ipstack_detect_log(std::string& _log);
+
+
+#endif /* __ip_type__ */

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików