comparison src/protocols/yahoo/yahoochat.c @ 8113:d60272410bd5

[gaim-migrate @ 8817] Tim 'marv' Ringenbach wrote us a wonderful core/ui split chat room list thing-a-ma-jig. I've taken the liberty of adding jabber support to it as well. committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Thu, 15 Jan 2004 22:20:29 +0000
parents fa6395637e2c
children 1f56ea865926
comparison
equal deleted inserted replaced
8112:67387ec77301 8113:d60272410bd5
1002 yahoo_chat_invite(gc, gaim_connection_get_display_name(gc), name, 1002 yahoo_chat_invite(gc, gaim_connection_get_display_name(gc), name,
1003 gaim_conversation_get_name(c), msg); 1003 gaim_conversation_get_name(c), msg);
1004 } 1004 }
1005 } 1005 }
1006 1006
1007
1008 struct yahoo_roomlist {
1009 int fd;
1010 int inpa;
1011 guchar *rxqueue;
1012 int rxlen;
1013 gboolean started;
1014 char *path;
1015 char *host;
1016 GaimRoomlist *list;
1017 GaimRoomlistRoom *cat;
1018 GaimRoomlistRoom *ucat;
1019 GMarkupParseContext *parse;
1020
1021 };
1022
1023 static void yahoo_roomlist_destroy(struct yahoo_roomlist *yrl)
1024 {
1025 if (yrl->inpa)
1026 gaim_input_remove(yrl->inpa);
1027 if (yrl->rxqueue)
1028 g_free(yrl->rxqueue);
1029 if (yrl->path)
1030 g_free(yrl->path);
1031 if (yrl->host)
1032 g_free(yrl->host);
1033 if (yrl->parse)
1034 g_markup_parse_context_free(yrl->parse);
1035 }
1036
1037 enum yahoo_room_type {
1038 yrt_yahoo,
1039 yrt_user,
1040 };
1041
1042 struct yahoo_chatxml_state {
1043 GaimRoomlist *list;
1044 struct yahoo_roomlist *yrl;
1045 GQueue *q;
1046 struct {
1047 enum yahoo_room_type type;
1048 char *name;
1049 char *topic;
1050 char *id;
1051 int users, voices, webcams;
1052 } room;
1053 };
1054
1055 struct yahoo_lobby {
1056 int count, users, voices, webcams;
1057 };
1058
1059 static struct yahoo_chatxml_state *yahoo_chatxml_state_new(GaimRoomlist *list, struct yahoo_roomlist *yrl)
1060 {
1061 struct yahoo_chatxml_state *s;
1062
1063 s = g_new0(struct yahoo_chatxml_state, 1);
1064
1065 s->list = list;
1066 s->yrl = yrl;
1067 s->q = g_queue_new();
1068
1069 return s;
1070 }
1071
1072 static void yahoo_chatxml_state_destroy(struct yahoo_chatxml_state *s)
1073 {
1074 g_queue_free(s->q);
1075 if (s->room.name)
1076 g_free(s->room.name);
1077 if (s->room.topic)
1078 g_free(s->room.topic);
1079 if (s->room.id)
1080 g_free(s->room.id);
1081 g_free(s);
1082 }
1083
1084 static void yahoo_chatlist_start_element(GMarkupParseContext *context, const gchar *ename,
1085 const gchar **anames, const gchar **avalues,
1086 gpointer user_data, GError **error)
1087 {
1088 struct yahoo_chatxml_state *s = user_data;
1089 GaimRoomlist *list = s->list;
1090 GaimRoomlistRoom *r;
1091 GaimRoomlistRoom *parent;
1092 int i;
1093
1094 if (!strcmp(ename, "category")) {
1095 const gchar *name = NULL, *id = NULL;
1096
1097 for (i = 0; anames[i]; i++) {
1098 if (!strcmp(anames[i], "id"))
1099 id = avalues[i];
1100 if (!strcmp(anames[i], "name"))
1101 name = avalues[i];
1102 }
1103 if (!name || !id)
1104 return;
1105
1106 parent = g_queue_peek_head(s->q);
1107 r = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_CATAGORY, name, parent);
1108 gaim_roomlist_room_add_field(list, r, (gpointer)name);
1109 gaim_roomlist_room_add_field(list, r, (gpointer)id);
1110 gaim_roomlist_room_add(list, r);
1111 g_queue_push_head(s->q, r);
1112 } else if (!strcmp(ename, "room")) {
1113 s->room.users = s->room.voices = s->room.webcams = 0;
1114
1115 for (i = 0; anames[i]; i++) {
1116 if (!strcmp(anames[i], "id")) {
1117 if (s->room.id)
1118 g_free(s->room.id);
1119 s->room.id = g_strdup(avalues[i]);
1120 } else if (!strcmp(anames[i], "name")) {
1121 if (s->room.name)
1122 g_free(s->room.name);
1123 s->room.name = g_strdup(avalues[i]);
1124 } else if (!strcmp(anames[i], "topic")) {
1125 if (s->room.topic)
1126 g_free(s->room.topic);
1127 s->room.topic = g_strdup(avalues[i]);
1128 } else if (!strcmp(anames[i], "type")) {
1129 if (!strcmp("yahoo", avalues[i]))
1130 s->room.type = yrt_yahoo;
1131 else
1132 s->room.type = yrt_user;
1133 }
1134 }
1135
1136 } else if (!strcmp(ename, "lobby")) {
1137 struct yahoo_lobby *lob = g_new0(struct yahoo_lobby, 1);
1138
1139 for (i = 0; anames[i]; i++) {
1140 if (!strcmp(anames[i], "count")) {
1141 lob->count = strtol(avalues[i], NULL, 10);
1142 } else if (!strcmp(anames[i], "users")) {
1143 s->room.users += lob->users = strtol(avalues[i], NULL, 10);
1144 } else if (!strcmp(anames[i], "voices")) {
1145 s->room.voices += lob->voices = strtol(avalues[i], NULL, 10);
1146 } else if (!strcmp(anames[i], "webcams")) {
1147 s->room.webcams += lob->webcams = strtol(avalues[i], NULL, 10);
1148 }
1149 }
1150
1151 g_queue_push_head(s->q, lob);
1152 }
1153
1154 }
1155
1156 static void yahoo_chatlist_end_element(GMarkupParseContext *context, const gchar *ename,
1157 gpointer user_data, GError **error)
1158 {
1159 struct yahoo_chatxml_state *s = user_data;
1160
1161 if (!strcmp(ename, "category")) {
1162 g_queue_pop_head(s->q);
1163 } else if (!strcmp(ename, "room")) {
1164 struct yahoo_lobby *lob;
1165 GaimRoomlistRoom *r, *l;
1166
1167 if (s->room.type == yrt_yahoo)
1168 r = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_CATAGORY|GAIM_ROOMLIST_ROOMTYPE_ROOM,
1169 s->room.name, s->yrl->cat);
1170 else
1171 r = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_CATAGORY|GAIM_ROOMLIST_ROOMTYPE_ROOM,
1172 s->room.name, s->yrl->ucat);
1173
1174 gaim_roomlist_room_add_field(s->list, r, s->room.name);
1175 gaim_roomlist_room_add_field(s->list, r, s->room.id);
1176 gaim_roomlist_room_add_field(s->list, r, GINT_TO_POINTER(s->room.users));
1177 gaim_roomlist_room_add_field(s->list, r, GINT_TO_POINTER(s->room.voices));
1178 gaim_roomlist_room_add_field(s->list, r, GINT_TO_POINTER(s->room.webcams));
1179 gaim_roomlist_room_add_field(s->list, r, s->room.topic);
1180 gaim_roomlist_room_add(s->list, r);
1181
1182 while ((lob = g_queue_pop_head(s->q))) {
1183 char *name = g_strdup_printf("%s:%d", s->room.name, lob->count);
1184 l = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, name, r);
1185
1186 gaim_roomlist_room_add_field(s->list, l, name);
1187 gaim_roomlist_room_add_field(s->list, l, s->room.id);
1188 gaim_roomlist_room_add_field(s->list, l, GINT_TO_POINTER(lob->users));
1189 gaim_roomlist_room_add_field(s->list, l, GINT_TO_POINTER(lob->voices));
1190 gaim_roomlist_room_add_field(s->list, l, GINT_TO_POINTER(lob->webcams));
1191 gaim_roomlist_room_add_field(s->list, l, s->room.topic);
1192 gaim_roomlist_room_add(s->list, l);
1193
1194 g_free(name);
1195 g_free(lob);
1196 }
1197
1198 }
1199
1200 }
1201
1202 static GMarkupParser parser = {
1203 yahoo_chatlist_start_element,
1204 yahoo_chatlist_end_element,
1205 NULL,
1206 NULL,
1207 NULL
1208 };
1209
1210 static void yahoo_roomlist_cleanup(GaimRoomlist *list, struct yahoo_roomlist *yrl)
1211 {
1212 gaim_roomlist_set_in_progress(list, FALSE);
1213
1214 if (yrl) {
1215 list->proto_data = g_list_remove(list->proto_data, yrl);
1216 yahoo_roomlist_destroy(yrl);
1217 }
1218
1219 gaim_roomlist_unref(list);
1220 }
1221
1222 static void yahoo_roomlist_pending(gpointer data, gint source, GaimInputCondition cond)
1223 {
1224 struct yahoo_roomlist *yrl = data;
1225 GaimRoomlist *list = yrl->list;
1226 char buf[1024];
1227 int len;
1228 guchar *start;
1229 struct yahoo_chatxml_state *s;
1230
1231 len = read(yrl->fd, buf, sizeof(buf));
1232
1233 if (len <= 0) {
1234 if (yrl->parse)
1235 g_markup_parse_context_end_parse(yrl->parse, NULL);
1236 yahoo_roomlist_cleanup(list, yrl);
1237 return;
1238 }
1239
1240
1241 yrl->rxqueue = g_realloc(yrl->rxqueue, len + yrl->rxlen);
1242 memcpy(yrl->rxqueue + yrl->rxlen, buf, len);
1243 yrl->rxlen += len;
1244
1245 if (!yrl->started) {
1246 yrl->started = TRUE;
1247 start = g_strstr_len(yrl->rxqueue, yrl->rxlen, "\r\n\r\n");
1248 if (!start || (start - yrl->rxqueue + 4) >= yrl->rxlen)
1249 return;
1250 start += 4;
1251 } else {
1252 start = yrl->rxqueue;
1253 }
1254
1255 if (yrl->parse == NULL) {
1256 s = yahoo_chatxml_state_new(list, yrl);
1257 yrl->parse = g_markup_parse_context_new(&parser, 0, s,
1258 (GDestroyNotify)yahoo_chatxml_state_destroy);
1259 }
1260
1261 if (!g_markup_parse_context_parse(yrl->parse, start, (yrl->rxlen - (start - yrl->rxqueue)), NULL)) {
1262
1263 yahoo_roomlist_cleanup(list, yrl);
1264 return;
1265 }
1266
1267 yrl->rxlen = 0;
1268 }
1269
1270 static void yahoo_roomlist_got_connected(gpointer data, gint source, GaimInputCondition cond)
1271 {
1272 struct yahoo_roomlist *yrl = data;
1273 GaimRoomlist *list = yrl->list;
1274 char *buf, *cookie;
1275 struct yahoo_data *yd = gaim_account_get_connection(list->account)->proto_data;
1276
1277 if (source < 0) {
1278 gaim_notify_error(gaim_account_get_connection(list->account), NULL, _("Unable to connect"), _("Fetching the room list failed."));
1279 yahoo_roomlist_cleanup(list, yrl);
1280 return;
1281 }
1282
1283 yrl->fd = source;
1284
1285 cookie = g_strdup_printf("Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
1286 buf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\nCookie: %s\r\n\r\n", yrl->path, yrl->host, cookie);
1287 write(yrl->fd, buf, strlen(buf));
1288 g_free(cookie);
1289 g_free(buf);
1290 yrl->inpa = gaim_input_add(yrl->fd, GAIM_INPUT_READ, yahoo_roomlist_pending, yrl);
1291
1292 }
1293
1294 GaimRoomlist *yahoo_roomlist_get_list(GaimConnection *gc)
1295 {
1296 struct yahoo_roomlist *yrl;
1297 GaimRoomlist *rl;
1298 char *url;
1299 GList *fields = NULL;
1300 GaimRoomlistField *f;
1301
1302 url = g_strdup_printf("%s?chatcat=0",
1303 gaim_account_get_string(
1304 gaim_connection_get_account(gc),
1305 "room_list", YAHOO_ROOMLIST_URL));
1306
1307 yrl = g_new0(struct yahoo_roomlist, 1);
1308 rl = gaim_roomlist_new(gaim_connection_get_account(gc));
1309 yrl->list = rl;
1310
1311 gaim_url_parse(url, &(yrl->host), NULL, &(yrl->path));
1312 g_free(url);
1313
1314 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, "", "room", TRUE);
1315 fields = g_list_append(fields, f);
1316
1317 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, "", "id", TRUE);
1318 fields = g_list_append(fields, f);
1319
1320 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_INT, _("Users"), "users", FALSE);
1321 fields = g_list_append(fields, f);
1322
1323 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_INT, _("Voices"), "voices", FALSE);
1324 fields = g_list_append(fields, f);
1325
1326 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_INT, _("Webcams"), "webcams", FALSE);
1327 fields = g_list_append(fields, f);
1328
1329 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, _("Topic"), "topic", FALSE);
1330 fields = g_list_append(fields, f);
1331
1332 gaim_roomlist_set_fields(rl, fields);
1333
1334 if (gaim_proxy_connect(gaim_connection_get_account(gc),
1335 yrl->host, 80, yahoo_roomlist_got_connected, yrl) != 0)
1336 {
1337 gaim_notify_error(gc, NULL, _("Connection problem"), _("Unable to fetch room list."));
1338 yahoo_roomlist_cleanup(rl, yrl);
1339 return NULL;
1340 }
1341
1342 rl->proto_data = g_list_append(rl->proto_data, yrl);
1343
1344 gaim_roomlist_set_in_progress(rl, TRUE);
1345 return rl;
1346 }
1347
1348 void yahoo_roomlist_cancel(GaimRoomlist *list)
1349 {
1350 GList *l, *k;
1351
1352 k = l = list->proto_data;
1353 list->proto_data = NULL;
1354
1355 gaim_roomlist_set_in_progress(list, FALSE);
1356
1357 for (; l; l = l->next) {
1358 yahoo_roomlist_destroy(l->data);
1359 gaim_roomlist_unref(l->data);
1360 }
1361 g_list_free(k);
1362 }
1363
1364 void yahoo_roomlist_expand_catagory(GaimRoomlist *list, GaimRoomlistRoom *catagory)
1365 {
1366 struct yahoo_roomlist *yrl;
1367 char *url;
1368 char *id;
1369
1370 if (catagory->type != GAIM_ROOMLIST_ROOMTYPE_CATAGORY)
1371 return;
1372
1373 if (!(id = g_list_nth_data(catagory->fields, 1))) {
1374 gaim_roomlist_set_in_progress(list, FALSE);
1375 return;
1376 }
1377
1378 url = g_strdup_printf("%s?chatroom_%s=0",
1379 gaim_account_get_string(
1380 list->account,
1381 "room_list", YAHOO_ROOMLIST_URL), id);
1382
1383 yrl = g_new0(struct yahoo_roomlist, 1);
1384 yrl->list = list;
1385 yrl->cat = catagory;
1386 list->proto_data = g_list_append(list->proto_data, yrl);
1387
1388 gaim_url_parse(url, &(yrl->host), NULL, &(yrl->path));
1389 g_free(url);
1390
1391 yrl->ucat = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_CATAGORY, _("User Rooms"), yrl->cat);
1392 gaim_roomlist_room_add(list, yrl->ucat);
1393
1394 if (gaim_proxy_connect(list->account,
1395 yrl->host, 80, yahoo_roomlist_got_connected, yrl) != 0)
1396 {
1397 gaim_notify_error(gaim_account_get_connection(list->account),
1398 NULL, _("Connection problem"), _("Unable to fetch room list."));
1399 yahoo_roomlist_cleanup(list, yrl);
1400 return;
1401 }
1402
1403 gaim_roomlist_set_in_progress(list, TRUE);
1404 gaim_roomlist_ref(list);
1405 }
1406