| 30 #include "char_conv.h" |
30 #include "char_conv.h" |
| 31 #include "group_find.h" |
31 #include "group_find.h" |
| 32 #include "group_internal.h" |
32 #include "group_internal.h" |
| 33 #include "group_info.h" |
33 #include "group_info.h" |
| 34 #include "buddy_list.h" |
34 #include "buddy_list.h" |
| 35 #include "group_network.h" |
35 #include "header_info.h" |
| |
36 #include "packet_parse.h" |
| |
37 #include "qq_network.h" |
| |
38 #include "utils.h" |
| 36 |
39 |
| 37 /* we check who needs to update member info every minutes |
40 /* we check who needs to update member info every minutes |
| 38 * this interval determines if their member info is outdated */ |
41 * this interval determines if their member info is outdated */ |
| 39 #define QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL 180 |
42 #define QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL 180 |
| 40 |
43 |
| 57 while (list != NULL) { |
60 while (list != NULL) { |
| 58 member = (qq_buddy *) list->data; |
61 member = (qq_buddy *) list->data; |
| 59 member->status = QQ_BUDDY_ONLINE_OFFLINE; |
62 member->status = QQ_BUDDY_ONLINE_OFFLINE; |
| 60 list = list->next; |
63 list = list->next; |
| 61 } |
64 } |
| 62 } |
|
| 63 |
|
| 64 /* send packet to get detailed information of one group */ |
|
| 65 void qq_send_cmd_group_get_group_info(PurpleConnection *gc, qq_group *group) |
|
| 66 { |
|
| 67 guint8 raw_data[16] = {0}; |
|
| 68 gint bytes = 0; |
|
| 69 |
|
| 70 g_return_if_fail(group != NULL); |
|
| 71 |
|
| 72 bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_GET_GROUP_INFO); |
|
| 73 bytes += qq_put32(raw_data + bytes, group->internal_group_id); |
|
| 74 |
|
| 75 qq_send_group_cmd(gc, group, raw_data, bytes); |
|
| 76 } |
65 } |
| 77 |
66 |
| 78 /* send packet to get online group member, called by keep_alive */ |
67 /* send packet to get online group member, called by keep_alive */ |
| 79 void qq_send_cmd_group_all_get_online_members(PurpleConnection *gc) |
68 void qq_send_cmd_group_all_get_online_members(PurpleConnection *gc) |
| 80 { |
69 { |
| 97 } |
86 } |
| 98 } |
87 } |
| 99 |
88 |
| 100 void qq_send_cmd_group_get_online_members(PurpleConnection *gc, qq_group *group) |
89 void qq_send_cmd_group_get_online_members(PurpleConnection *gc, qq_group *group) |
| 101 { |
90 { |
| 102 guint8 raw_data[16] = {0}; |
|
| 103 gint bytes = 0; |
|
| 104 |
|
| 105 g_return_if_fail(group != NULL); |
91 g_return_if_fail(group != NULL); |
| 106 |
92 |
| 107 /* only get online members when conversation window is on */ |
93 /* only get online members when conversation window is on */ |
| 108 if (NULL == purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,group->group_name_utf8, purple_connection_get_account(gc))) { |
94 if (NULL == purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,group->group_name_utf8, purple_connection_get_account(gc))) { |
| 109 purple_debug(PURPLE_DEBUG_WARNING, "QQ", |
95 purple_debug(PURPLE_DEBUG_WARNING, "QQ", |
| 110 "Conversation \"%s\" is not open, ignore to get online members\n", group->group_name_utf8); |
96 "Conversation \"%s\" is not open, ignore to get online members\n", group->group_name_utf8); |
| 111 return; |
97 return; |
| 112 } |
98 } |
| 113 |
99 |
| 114 bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_GET_ONLINE_MEMBER); |
100 qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_ONLINES, group->id); |
| 115 bytes += qq_put32(raw_data + bytes, group->internal_group_id); |
|
| 116 |
|
| 117 qq_send_group_cmd(gc, group, raw_data, bytes); |
|
| 118 } |
101 } |
| 119 |
102 |
| 120 /* send packet to get info for each group member */ |
103 /* send packet to get info for each group member */ |
| 121 void qq_send_cmd_group_get_members_info(PurpleConnection *gc, qq_group *group) |
104 void qq_send_cmd_group_get_members_info(PurpleConnection *gc, qq_group *group) |
| 122 { |
105 { |
| 123 guint8 *raw_data; |
106 guint8 *raw_data; |
| 124 gint bytes, num, data_len; |
107 gint bytes, num; |
| 125 GList *list; |
108 GList *list; |
| 126 qq_buddy *member; |
109 qq_buddy *member; |
| 127 |
110 |
| 128 g_return_if_fail(group != NULL); |
111 g_return_if_fail(group != NULL); |
| 129 for (num = 0, list = group->members; list != NULL; list = list->next) { |
112 for (num = 0, list = group->members; list != NULL; list = list->next) { |
| 135 if (num <= 0) { |
118 if (num <= 0) { |
| 136 purple_debug(PURPLE_DEBUG_INFO, "QQ", "No group member info needs to be updated now.\n"); |
119 purple_debug(PURPLE_DEBUG_INFO, "QQ", "No group member info needs to be updated now.\n"); |
| 137 return; |
120 return; |
| 138 } |
121 } |
| 139 |
122 |
| 140 data_len = 5 + 4 * num; |
123 raw_data = g_newa(guint8, 4 * num); |
| 141 raw_data = g_newa(guint8, data_len); |
|
| 142 |
124 |
| 143 bytes = 0; |
125 bytes = 0; |
| 144 bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_GET_MEMBER_INFO); |
|
| 145 bytes += qq_put32(raw_data + bytes, group->internal_group_id); |
|
| 146 |
126 |
| 147 list = group->members; |
127 list = group->members; |
| 148 while (list != NULL) { |
128 while (list != NULL) { |
| 149 member = (qq_buddy *) list->data; |
129 member = (qq_buddy *) list->data; |
| 150 if (_is_group_member_need_update_info(member)) |
130 if (_is_group_member_need_update_info(member)) |
| 151 bytes += qq_put32(raw_data + bytes, member->uid); |
131 bytes += qq_put32(raw_data + bytes, member->uid); |
| 152 list = list->next; |
132 list = list->next; |
| 153 } |
133 } |
| 154 |
134 |
| 155 if (bytes != data_len) { |
135 qq_send_room_cmd(gc, QQ_ROOM_CMD_GET_MEMBER_INFO, group->id, raw_data, bytes); |
| 156 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
136 } |
| 157 "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_GET_MEMBER_INFO)); |
137 |
| 158 return; |
138 void qq_process_room_cmd_get_info(guint8 *data, gint data_len, PurpleConnection *gc) |
| 159 } |
|
| 160 |
|
| 161 qq_send_group_cmd(gc, group, raw_data, bytes); |
|
| 162 } |
|
| 163 |
|
| 164 void qq_process_group_cmd_get_group_info(guint8 *data, gint len, PurpleConnection *gc) |
|
| 165 { |
139 { |
| 166 qq_group *group; |
140 qq_group *group; |
| 167 qq_buddy *member; |
141 qq_buddy *member; |
| 168 qq_data *qd; |
142 qq_data *qd; |
| 169 PurpleConversation *purple_conv; |
143 PurpleConversation *purple_conv; |
| 170 guint8 organization, role; |
144 guint8 organization, role; |
| 171 guint16 unknown, max_members; |
145 guint16 unknown, max_members; |
| 172 guint32 member_uid, internal_group_id, external_group_id; |
146 guint32 member_uid, id, ext_id; |
| 173 GSList *pending_id; |
147 GSList *pending_id; |
| 174 guint32 unknown4; |
148 guint32 unknown4; |
| 175 guint8 unknown1; |
149 guint8 unknown1; |
| 176 gint bytes, num; |
150 gint bytes, num; |
| 177 gchar *notice; |
151 gchar *notice; |
| 178 |
152 |
| 179 g_return_if_fail(data != NULL && len > 0); |
153 g_return_if_fail(data != NULL && data_len > 0); |
| 180 qd = (qq_data *) gc->proto_data; |
154 qd = (qq_data *) gc->proto_data; |
| 181 |
155 |
| 182 bytes = 0; |
156 bytes = 0; |
| 183 bytes += qq_get32(&(internal_group_id), data + bytes); |
157 bytes += qq_get32(&id, data + bytes); |
| 184 g_return_if_fail(internal_group_id > 0); |
158 g_return_if_fail(id > 0); |
| 185 |
159 |
| 186 bytes += qq_get32(&(external_group_id), data + bytes); |
160 bytes += qq_get32(&ext_id, data + bytes); |
| 187 g_return_if_fail(external_group_id > 0); |
161 g_return_if_fail(ext_id > 0); |
| 188 |
162 |
| 189 pending_id = qq_get_pending_id(qd->adding_groups_from_server, internal_group_id); |
163 pending_id = qq_get_pending_id(qd->adding_groups_from_server, id); |
| 190 if (pending_id != NULL) { |
164 if (pending_id != NULL) { |
| 191 qq_set_pending_id(&qd->adding_groups_from_server, internal_group_id, FALSE); |
165 qq_set_pending_id(&qd->adding_groups_from_server, id, FALSE); |
| 192 qq_group_create_internal_record(gc, internal_group_id, external_group_id, NULL); |
166 qq_group_create_internal_record(gc, id, ext_id, NULL); |
| 193 } |
167 } |
| 194 |
168 |
| 195 group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); |
169 group = qq_room_search_id(gc, id); |
| 196 g_return_if_fail(group != NULL); |
170 g_return_if_fail(group != NULL); |
| 197 |
171 |
| 198 bytes += qq_get8(&(group->group_type), data + bytes); |
172 bytes += qq_get8(&(group->type8), data + bytes); |
| 199 bytes += qq_get32(&unknown4, data + bytes); /* unknown 4 bytes */ |
173 bytes += qq_get32(&unknown4, data + bytes); /* unknown 4 bytes */ |
| 200 bytes += qq_get32(&(group->creator_uid), data + bytes); |
174 bytes += qq_get32(&(group->creator_uid), data + bytes); |
| 201 bytes += qq_get8(&(group->auth_type), data + bytes); |
175 bytes += qq_get8(&(group->auth_type), data + bytes); |
| 202 bytes += qq_get32(&unknown4, data + bytes); /* oldCategory */ |
176 bytes += qq_get32(&unknown4, data + bytes); /* oldCategory */ |
| 203 bytes += qq_get16(&unknown, data + bytes); |
177 bytes += qq_get16(&unknown, data + bytes); |
| 208 * 4(unk), 4(verID), 1(nameLen), nameLen(qunNameContent), 1(0x00), |
182 * 4(unk), 4(verID), 1(nameLen), nameLen(qunNameContent), 1(0x00), |
| 209 * 2(qunNoticeLen), qunNoticeLen(qunNoticeContent, 1(qunDescLen), |
183 * 2(qunNoticeLen), qunNoticeLen(qunNoticeContent, 1(qunDescLen), |
| 210 * qunDestLen(qunDestcontent)) */ |
184 * qunDestLen(qunDestcontent)) */ |
| 211 bytes += qq_get8(&unknown1, data + bytes); |
185 bytes += qq_get8(&unknown1, data + bytes); |
| 212 purple_debug(PURPLE_DEBUG_INFO, "QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n", |
186 purple_debug(PURPLE_DEBUG_INFO, "QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n", |
| 213 group->group_type, group->creator_uid, group->group_category, max_members); |
187 group->type8, group->creator_uid, group->group_category, max_members); |
| 214 |
188 |
| 215 /* strlen + <str content> */ |
189 /* strlen + <str content> */ |
| 216 bytes += convert_as_pascal_string(data + bytes, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); |
190 bytes += convert_as_pascal_string(data + bytes, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); |
| 217 purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\"\n", group->group_name_utf8); |
191 purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\"\n", group->group_name_utf8); |
| 218 bytes += qq_get16(&unknown, data + bytes); /* 0x0000 */ |
192 bytes += qq_get16(&unknown, data + bytes); /* 0x0000 */ |
| 221 bytes += convert_as_pascal_string(data + bytes, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); |
195 bytes += convert_as_pascal_string(data + bytes, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); |
| 222 purple_debug(PURPLE_DEBUG_INFO, "QQ", "group_desc \"%s\"\n", group->group_desc_utf8); |
196 purple_debug(PURPLE_DEBUG_INFO, "QQ", "group_desc \"%s\"\n", group->group_desc_utf8); |
| 223 |
197 |
| 224 num = 0; |
198 num = 0; |
| 225 /* now comes the member list separated by 0x00 */ |
199 /* now comes the member list separated by 0x00 */ |
| 226 while (bytes < len) { |
200 while (bytes < data_len) { |
| 227 bytes += qq_get32(&member_uid, data + bytes); |
201 bytes += qq_get32(&member_uid, data + bytes); |
| 228 num++; |
202 num++; |
| 229 bytes += qq_get8(&organization, data + bytes); |
203 bytes += qq_get8(&organization, data + bytes); |
| 230 bytes += qq_get8(&role, data + bytes); |
204 bytes += qq_get8(&role, data + bytes); |
| 231 |
205 |
| 232 /* |
206 #if 0 |
| 233 if(organization != 0 || role != 0) { |
207 if(organization != 0 || role != 0) { |
| 234 purple_debug(PURPLE_DEBUG_INFO, "QQ_GRP", "%d, organization=%d, role=%d\n", member_uid, organization, role); |
208 purple_debug(PURPLE_DEBUG_INFO, "QQ_GRP", "%d, organization=%d, role=%d\n", member_uid, organization, role); |
| 235 } |
209 } |
| 236 */ |
210 #endif |
| |
211 |
| 237 member = qq_group_find_or_add_member(gc, group, member_uid); |
212 member = qq_group_find_or_add_member(gc, group, member_uid); |
| 238 if (member != NULL) |
213 if (member != NULL) |
| 239 member->role = role; |
214 member->role = role; |
| 240 } |
215 } |
| 241 if(bytes > len) { |
216 if(bytes > data_len) { |
| 242 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "group_cmd_get_group_info: Dangerous error! maybe protocol changed, notify me!"); |
217 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
| |
218 "group_cmd_get_group_info: Dangerous error! maybe protocol changed, notify me!"); |
| 243 } |
219 } |
| 244 |
220 |
| 245 purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\" has %d members\n", group->group_name_utf8, num); |
221 purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\" has %d members\n", group->group_name_utf8, num); |
| 246 |
222 |
| 247 if (group->creator_uid == qd->uid) |
223 if (group->creator_uid == qd->uid) |
| 279 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Invalid group online member reply, discard it!\n"); |
255 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Invalid group online member reply, discard it!\n"); |
| 280 return; |
256 return; |
| 281 } |
257 } |
| 282 |
258 |
| 283 bytes = 0; |
259 bytes = 0; |
| 284 bytes += qq_get32(&internal_group_id, data + bytes); |
260 bytes += qq_get32(&id, data + bytes); |
| 285 bytes += qq_get8(&unknown, data + bytes); /* 0x3c ?? */ |
261 bytes += qq_get8(&unknown, data + bytes); /* 0x3c ?? */ |
| 286 g_return_if_fail(internal_group_id > 0); |
262 g_return_if_fail(id > 0); |
| 287 |
263 |
| 288 group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); |
264 group = qq_room_search_id(gc, id); |
| 289 if (group == NULL) { |
265 if (group == NULL) { |
| 290 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
266 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
| 291 "We have no group info for internal id [%d]\n", internal_group_id); |
267 "We have no group info for internal id [%d]\n", id); |
| 292 return; |
268 return; |
| 293 } |
269 } |
| 294 |
270 |
| 295 /* set all offline first, then update those online */ |
271 /* set all offline first, then update those online */ |
| 296 _qq_group_set_members_all_offline(group); |
272 _qq_group_set_members_all_offline(group); |
| 309 |
285 |
| 310 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" has %d online members\n", group->group_name_utf8, num); |
286 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" has %d online members\n", group->group_name_utf8, num); |
| 311 } |
287 } |
| 312 |
288 |
| 313 /* process the reply to get_members_info packet */ |
289 /* process the reply to get_members_info packet */ |
| 314 void qq_process_group_cmd_get_members_info(guint8 *data, gint len, PurpleConnection *gc) |
290 void qq_process_room_cmd_get_members(guint8 *data, gint len, PurpleConnection *gc) |
| 315 { |
291 { |
| 316 gint bytes; |
292 gint bytes; |
| 317 gint num; |
293 gint num; |
| 318 guint32 internal_group_id, member_uid; |
294 guint32 id, member_uid; |
| 319 guint16 unknown; |
295 guint16 unknown; |
| 320 qq_group *group; |
296 qq_group *group; |
| 321 qq_buddy *member; |
297 qq_buddy *member; |
| 322 gchar *nick; |
298 gchar *nick; |
| 323 |
299 |
| 324 g_return_if_fail(data != NULL && len > 0); |
300 g_return_if_fail(data != NULL && len > 0); |
| 325 |
301 |
| |
302 #if 0 |
| |
303 qq_show_packet("qq_process_room_cmd_get_members", data, len); |
| |
304 #endif |
| |
305 |
| 326 bytes = 0; |
306 bytes = 0; |
| 327 bytes += qq_get32(&internal_group_id, data + bytes); |
307 bytes += qq_get32(&id, data + bytes); |
| 328 g_return_if_fail(internal_group_id > 0); |
308 g_return_if_fail(id > 0); |
| 329 |
309 |
| 330 group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); |
310 group = qq_room_search_id(gc, id); |
| 331 g_return_if_fail(group != NULL); |
311 g_return_if_fail(group != NULL); |
| 332 |
312 |
| 333 num = 0; |
313 num = 0; |
| 334 /* now starts the member info, as get buddy list reply */ |
314 /* now starts the member info, as get buddy list reply */ |
| 335 while (bytes < len) { |
315 while (bytes < len) { |
| 350 /* filter \r\n in nick */ |
330 /* filter \r\n in nick */ |
| 351 qq_filter_str(nick); |
331 qq_filter_str(nick); |
| 352 member->nickname = g_strdup(nick); |
332 member->nickname = g_strdup(nick); |
| 353 g_free(nick); |
333 g_free(nick); |
| 354 |
334 |
| 355 /* |
335 #if 0 |
| 356 if (QQ_DEBUG) { |
336 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
| 357 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
337 "member [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", |
| 358 "member [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", |
338 member_uid, member->ext_flag, member->comm_flag, member->nickname); |
| 359 member_uid, member->ext_flag, member->comm_flag, member->nickname); |
339 #endif |
| 360 } |
|
| 361 */ |
|
| 362 |
340 |
| 363 member->last_refresh = time(NULL); |
341 member->last_refresh = time(NULL); |
| 364 } |
342 } |
| 365 if(bytes > len) { |
343 if (bytes > len) { |
| 366 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
344 purple_debug(PURPLE_DEBUG_ERROR, "QQ", |
| 367 "group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!"); |
345 "group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!"); |
| 368 } |
346 } |
| 369 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" obtained %d member info\n", group->group_name_utf8, num); |
347 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" obtained %d member info\n", group->group_name_utf8, num); |
| 370 } |
348 } |
| |
349 |