| 693 } |
682 } |
| 694 |
683 |
| 695 return c; |
684 return c; |
| 696 } |
685 } |
| 697 |
686 |
| 698 static void gaim_odc_disconnect(aim_session_t *sess, aim_conn_t *conn) { |
687 /***************************************************************************** |
| |
688 * Begin scary direct im stuff |
| |
689 *****************************************************************************/ |
| |
690 |
| |
691 static struct oscar_direct_im *oscar_direct_im_find(OscarData *od, const char *who) { |
| |
692 GSList *d = od->direct_ims; |
| |
693 struct oscar_direct_im *m = NULL; |
| |
694 |
| |
695 while (d) { |
| |
696 m = (struct oscar_direct_im *)d->data; |
| |
697 if (!aim_sncmp(who, m->name)) |
| |
698 return m; |
| |
699 d = d->next; |
| |
700 } |
| |
701 |
| |
702 return NULL; |
| |
703 } |
| |
704 |
| |
705 static void oscar_direct_im_destroy(OscarData *od, struct oscar_direct_im *dim) |
| |
706 { |
| |
707 gaim_debug_info("oscar", |
| |
708 "destroying Direct IM for %s.\n", dim->name); |
| |
709 |
| |
710 od->direct_ims = g_slist_remove(od->direct_ims, dim); |
| |
711 if (dim->watcher) |
| |
712 gaim_input_remove(dim->watcher); |
| |
713 if (dim->conn) { |
| |
714 aim_conn_close(dim->conn); |
| |
715 aim_conn_kill(od->sess, &dim->conn); |
| |
716 } |
| |
717 g_free(dim); |
| |
718 } |
| |
719 |
| |
720 /* the only difference between this and destroy is this writes a conv message */ |
| |
721 static void oscar_direct_im_disconnect(OscarData *od, struct oscar_direct_im *dim) |
| |
722 { |
| |
723 GaimConversation *conv; |
| |
724 char buf[256]; |
| |
725 |
| |
726 gaim_debug_info("oscar", |
| |
727 "%s disconnected Direct IM.\n", dim->name); |
| |
728 |
| |
729 if (dim->connected) |
| |
730 g_snprintf(buf, sizeof buf, _("Direct IM with %s closed"), dim->name); |
| |
731 else |
| |
732 g_snprintf(buf, sizeof buf, _("Direct IM with %s failed"), dim->name); |
| |
733 |
| |
734 conv = gaim_find_conversation_with_account(dim->name, gaim_connection_get_account(dim->gc)); |
| |
735 if (conv) { |
| |
736 gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL)); |
| |
737 gaim_conversation_update_progress(conv, 0); |
| |
738 } else { |
| |
739 gaim_notify_error(dim->gc, NULL, _("Direct Connect failed"), buf); |
| |
740 } |
| |
741 |
| |
742 oscar_direct_im_destroy(od, dim); |
| |
743 |
| |
744 return; |
| |
745 } |
| |
746 |
| |
747 /* oops i made two of these. this one just calls the other one. */ |
| |
748 static void gaim_odc_disconnect(aim_session_t *sess, aim_conn_t *conn) |
| |
749 { |
| |
750 GaimConnection *gc = sess->aux_data; |
| |
751 OscarData *od = (OscarData *)gc->proto_data; |
| |
752 struct oscar_direct_im *dim; |
| |
753 char *sn; |
| |
754 |
| |
755 sn = g_strdup(aim_odc_getsn(conn)); |
| |
756 dim = oscar_direct_im_find(od, sn); |
| |
757 oscar_direct_im_disconnect(od, dim); |
| |
758 g_free(sn); |
| |
759 } |
| |
760 |
| |
761 static void destroy_direct_im_request(struct ask_direct *d) { |
| |
762 gaim_debug_info("oscar", "Freeing DirectIM prompts.\n"); |
| |
763 |
| |
764 g_free(d->sn); |
| |
765 g_free(d); |
| |
766 } |
| |
767 |
| |
768 /* this is just a gaim_proxy_connect cb that sets up the rest of the cbs */ |
| |
769 static void oscar_odc_callback(gpointer data, gint source, GaimInputCondition condition) { |
| |
770 struct oscar_direct_im *dim = data; |
| |
771 GaimConnection *gc = dim->gc; |
| |
772 OscarData *od = gc->proto_data; |
| |
773 GaimConversation *conv; |
| |
774 char buf[256]; |
| |
775 struct sockaddr name; |
| |
776 socklen_t name_len = 1; |
| |
777 |
| |
778 g_return_if_fail(gc != NULL); |
| |
779 |
| |
780 if (!g_list_find(gaim_connections_get_all(), gc)) { |
| |
781 oscar_direct_im_destroy(od, dim); |
| |
782 return; |
| |
783 } |
| |
784 |
| |
785 if (source < 0) { |
| |
786 oscar_direct_im_disconnect(od, dim); |
| |
787 return; |
| |
788 } |
| |
789 |
| |
790 dim->conn->fd = source; |
| |
791 aim_conn_completeconnect(od->sess, dim->conn); |
| |
792 conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, dim->name); |
| |
793 |
| |
794 /* This is the best way to see if we're connected or not */ |
| |
795 if (getpeername(source, &name, &name_len) == 0) { |
| |
796 g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), dim->name); |
| |
797 dim->connected = TRUE; |
| |
798 gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL)); |
| |
799 } |
| |
800 |
| |
801 dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); |
| |
802 } |
| |
803 |
| |
804 static void accept_direct_im_request(struct ask_direct *d) { |
| |
805 GaimConnection *gc = d->gc; |
| |
806 OscarData *od; |
| |
807 struct oscar_direct_im *dim; |
| |
808 char *host; int port = 5190; |
| |
809 int i, rc; |
| |
810 |
| |
811 if (!g_list_find(gaim_connections_get_all(), gc)) { |
| |
812 destroy_direct_im_request(d); |
| |
813 return; |
| |
814 } |
| |
815 |
| |
816 od = (OscarData *)gc->proto_data; |
| |
817 gaim_debug_info("oscar", "Accepted DirectIM.\n"); |
| |
818 |
| |
819 dim = oscar_direct_im_find(od, d->sn); |
| |
820 if (dim && dim->connected) { |
| |
821 destroy_direct_im_request(d); /* 40 */ /* what does that 40 mean? */ |
| |
822 gaim_debug_info("oscar", "Wait, we're already connected, ignoring DirectIM.\n"); |
| |
823 return; |
| |
824 } |
| |
825 dim = g_new0(struct oscar_direct_im, 1); |
| |
826 dim->gc = d->gc; |
| |
827 g_snprintf(dim->name, sizeof dim->name, "%s", d->sn); |
| |
828 |
| |
829 dim->conn = aim_odc_connect(od->sess, d->sn, NULL, d->cookie); |
| |
830 od->direct_ims = g_slist_append(od->direct_ims, dim); |
| |
831 if (!dim->conn) { |
| |
832 oscar_direct_im_disconnect(od, dim); |
| |
833 destroy_direct_im_request(d); |
| |
834 return; |
| |
835 } |
| |
836 |
| |
837 aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, |
| |
838 gaim_odc_incoming, 0); |
| |
839 aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, |
| |
840 gaim_odc_typing, 0); |
| |
841 aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER, |
| |
842 gaim_odc_update_ui, 0); |
| |
843 |
| |
844 gaim_debug_info("oscar", "ip is %s.\n", d->ip); |
| |
845 for (i = 0; i < (int)strlen(d->ip); i++) { |
| |
846 if (d->ip[i] == ':') { |
| |
847 port = atoi(&(d->ip[i+1])); |
| |
848 break; |
| |
849 } |
| |
850 } |
| |
851 host = g_strndup(d->ip, i); |
| |
852 dim->conn->status |= AIM_CONN_STATUS_INPROGRESS; |
| |
853 rc = gaim_proxy_connect(gc->account, host, port, oscar_odc_callback, dim); |
| |
854 g_free(host); |
| |
855 if (rc < 0) { |
| |
856 oscar_direct_im_disconnect(od, dim); |
| |
857 destroy_direct_im_request(d); |
| |
858 return; |
| |
859 } |
| |
860 |
| |
861 destroy_direct_im_request(d); |
| |
862 |
| |
863 return; |
| |
864 } |
| |
865 |
| |
866 /* |
| |
867 * We have just established a socket with the other dude, so set up some handlers. |
| |
868 */ |
| |
869 static int gaim_odc_initiate(aim_session_t *sess, aim_frame_t *fr, ...) { |
| 699 GaimConnection *gc = sess->aux_data; |
870 GaimConnection *gc = sess->aux_data; |
| 700 OscarData *od = (OscarData *)gc->proto_data; |
871 OscarData *od = (OscarData *)gc->proto_data; |
| 701 GaimConversation *conv; |
872 GaimConversation *conv; |
| 702 struct direct_im *dim; |
873 struct oscar_direct_im *dim; |
| |
874 char buf[256]; |
| 703 char *sn; |
875 char *sn; |
| 704 char buf[256]; |
876 va_list ap; |
| 705 |
877 aim_conn_t *newconn, *listenerconn; |
| 706 sn = g_strdup(aim_odc_getsn(conn)); |
878 |
| |
879 va_start(ap, fr); |
| |
880 newconn = va_arg(ap, aim_conn_t *); |
| |
881 listenerconn = va_arg(ap, aim_conn_t *); |
| |
882 va_end(ap); |
| |
883 |
| |
884 aim_conn_close(listenerconn); |
| |
885 aim_conn_kill(sess, &listenerconn); |
| |
886 |
| |
887 sn = g_strdup(aim_odc_getsn(newconn)); |
| 707 |
888 |
| 708 gaim_debug_info("oscar", |
889 gaim_debug_info("oscar", |
| 709 "%s disconnected Direct IM.\n", sn); |
890 "DirectIM: initiate success to %s\n", sn); |
| 710 |
891 dim = oscar_direct_im_find(od, sn); |
| 711 dim = find_direct_im(od, sn); |
892 |
| 712 od->direct_ims = g_slist_remove(od->direct_ims, dim); |
893 conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, sn); |
| 713 gaim_input_remove(dim->watcher); |
894 gaim_input_remove(dim->watcher); |
| 714 |
895 dim->conn = newconn; |
| 715 if (dim->connected) |
896 dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); |
| 716 g_snprintf(buf, sizeof buf, _("Direct IM with %s closed"), sn); |
897 dim->connected = TRUE; |
| 717 else |
898 g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), sn); |
| 718 g_snprintf(buf, sizeof buf, _("Direct IM with %s failed"), sn); |
|
| 719 |
|
| 720 conv = gaim_find_conversation_with_account(sn, gaim_connection_get_account(gc)); |
|
| 721 if (conv) |
|
| 722 gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL)); |
|
| 723 |
|
| 724 gaim_conversation_update_progress(conv, 0); |
|
| 725 |
|
| 726 g_free(dim); /* I guess? I don't see it anywhere else... -- mid */ |
|
| 727 g_free(sn); |
899 g_free(sn); |
| 728 |
900 gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL)); |
| |
901 |
| |
902 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_odc_incoming, 0); |
| |
903 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_odc_typing, 0); |
| |
904 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER, gaim_odc_update_ui, 0); |
| |
905 |
| |
906 return 1; |
| |
907 } |
| |
908 |
| |
909 /* |
| |
910 * This is called when each chunk of an image is received. It can be used to |
| |
911 * update a progress bar, or to eat lots of dry cat food. Wet cat food is |
| |
912 * nasty, you sicko. |
| |
913 */ |
| |
914 static int gaim_odc_update_ui(aim_session_t *sess, aim_frame_t *fr, ...) { |
| |
915 va_list ap; |
| |
916 char *sn; |
| |
917 double percent; |
| |
918 GaimConnection *gc = sess->aux_data; |
| |
919 OscarData *od = (OscarData *)gc->proto_data; |
| |
920 GaimConversation *c; |
| |
921 struct oscar_direct_im *dim; |
| |
922 |
| |
923 va_start(ap, fr); |
| |
924 sn = va_arg(ap, char *); |
| |
925 percent = va_arg(ap, double); |
| |
926 va_end(ap); |
| |
927 |
| |
928 if (!sn || !(dim = oscar_direct_im_find(od, sn))) |
| |
929 return 1; |
| |
930 if (dim->watcher) { |
| |
931 gaim_input_remove(dim->watcher); /* Otherwise, the callback will callback */ |
| |
932 /* The callback will callback? I don't get how that would happen here. */ |
| |
933 dim->watcher = 0; |
| |
934 } |
| |
935 |
| |
936 c = gaim_find_conversation_with_account(sn, gaim_connection_get_account(gc)); |
| |
937 if (c != NULL) |
| |
938 gaim_conversation_update_progress(c, percent); |
| |
939 dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, |
| |
940 oscar_callback, dim->conn); |
| |
941 |
| |
942 return 1; |
| |
943 } |
| |
944 |
| |
945 /* |
| |
946 * This is called after a direct IM has been received in its entirety. This |
| |
947 * function is passed a long chunk of data which contains the IM with any |
| |
948 * data chunks (images) appended to it. |
| |
949 * |
| |
950 * This function rips out all the data chunks and creates an imgstore for |
| |
951 * each one. In order to do this, it first goes through the IM and takes |
| |
952 * out all the IMG tags. When doing so, it rewrites the original IMG tag |
| |
953 * with one compatible with the imgstore Gaim core code. For each one, we |
| |
954 * then read in chunks of data from the end of the message and actually |
| |
955 * create the img store using the given data. |
| |
956 * |
| |
957 * For somewhat easy reference, here's a sample message |
| |
958 * (without the whitespace and asterisks): |
| |
959 * |
| |
960 * <HTML><BODY BGCOLOR="#ffffff"> |
| |
961 * <FONT LANG="0"> |
| |
962 * This is a really stupid picture:<BR> |
| |
963 * <IMG SRC="Sample.jpg" ID="1" WIDTH="283" HEIGHT="212" DATASIZE="9894"><BR> |
| |
964 * Yeah it is<BR> |
| |
965 * Here is another one:<BR> |
| |
966 * <IMG SRC="Soap Bubbles.bmp" ID="2" WIDTH="256" HEIGHT="256" DATASIZE="65978"> |
| |
967 * </FONT> |
| |
968 * </BODY></HTML> |
| |
969 * <BINARY> |
| |
970 * <DATA ID="1" SIZE="9894">datadatadatadata</DATA> |
| |
971 * <DATA ID="2" SIZE="65978">datadatadatadata</DATA> |
| |
972 * </BINARY> |
| |
973 */ |
| |
974 static int gaim_odc_incoming(aim_session_t *sess, aim_frame_t *fr, ...) { |
| |
975 GaimConnection *gc = sess->aux_data; |
| |
976 GaimConvImFlags imflags = 0; |
| |
977 gchar *utf8; |
| |
978 GString *newmsg = g_string_new(""); |
| |
979 GSList *images = NULL; |
| |
980 va_list ap; |
| |
981 const char *sn, *msg, *msgend, *binary; |
| |
982 size_t len; |
| |
983 int encoding, isawaymsg; |
| |
984 |
| |
985 va_start(ap, fr); |
| |
986 sn = va_arg(ap, const char *); |
| |
987 msg = va_arg(ap, const char *); |
| |
988 len = va_arg(ap, size_t); |
| |
989 encoding = va_arg(ap, int); |
| |
990 isawaymsg = va_arg(ap, int); |
| |
991 va_end(ap); |
| |
992 msgend = msg + len; |
| |
993 |
| |
994 gaim_debug_info("oscar", |
| |
995 "Got DirectIM message from %s\n", sn); |
| |
996 |
| |
997 if (isawaymsg) |
| |
998 imflags |= GAIM_CONV_IM_AUTO_RESP; |
| |
999 |
| |
1000 /* message has a binary trailer */ |
| |
1001 if ((binary = gaim_strcasestr(msg, "<binary>"))) { |
| |
1002 GData *attribs; |
| |
1003 const char *tmp, *start, *end, *last = NULL; |
| |
1004 |
| |
1005 tmp = msg; |
| |
1006 |
| |
1007 /* for each valid image tag... */ |
| |
1008 while (gaim_markup_find_tag("img", tmp, &start, &end, &attribs)) { |
| |
1009 const char *id, *src, *datasize; |
| |
1010 const char *tag = NULL, *data = NULL; |
| |
1011 size_t size; |
| |
1012 int imgid = 0; |
| |
1013 |
| |
1014 /* update the location of the last img tag */ |
| |
1015 last = end; |
| |
1016 |
| |
1017 /* grab attributes */ |
| |
1018 id = g_datalist_get_data(&attribs, "id"); |
| |
1019 src = g_datalist_get_data(&attribs, "src"); |
| |
1020 datasize = g_datalist_get_data(&attribs, "datasize"); |
| |
1021 |
| |
1022 /* if we have id & datasize, build the data tag */ |
| |
1023 if (id && datasize) |
| |
1024 tag = g_strdup_printf("<data id=\"%s\" size=\"%s\">", id, datasize); |
| |
1025 |
| |
1026 /* if we have a tag, find the start of the data */ |
| |
1027 if (tag && (data = gaim_strcasestr(binary, tag))) |
| |
1028 data += strlen(tag); |
| |
1029 |
| |
1030 /* check the data is here and store it */ |
| |
1031 if (data + (size = atoi(datasize)) <= msgend) |
| |
1032 imgid = gaim_imgstore_add(data, size, src); |
| |
1033 |
| |
1034 /* |
| |
1035 * XXX - The code below contains some calls to oscar_encoding_to_utf8 |
| |
1036 * The hardcoded "us-ascii" value REALLY needs to be removed. |
| |
1037 */ |
| |
1038 /* if we have a stored image... */ |
| |
1039 if (imgid) { |
| |
1040 /* append the message up to the tag */ |
| |
1041 utf8 = oscar_encoding_to_utf8("us-ascii", tmp, start - tmp); |
| |
1042 if (utf8 != NULL) { |
| |
1043 newmsg = g_string_append(newmsg, utf8); |
| |
1044 g_free(utf8); |
| |
1045 } |
| |
1046 |
| |
1047 /* write the new image tag */ |
| |
1048 g_string_append_printf(newmsg, "<IMG ID=\"%d\">", imgid); |
| |
1049 |
| |
1050 /* and record the image number */ |
| |
1051 images = g_slist_append(images, GINT_TO_POINTER(imgid)); |
| |
1052 } else { |
| |
1053 /* otherwise, copy up to the end of the tag */ |
| |
1054 utf8 = oscar_encoding_to_utf8("us-ascii", tmp, (end + 1) - tmp); |
| |
1055 if (utf8 != NULL) { |
| |
1056 newmsg = g_string_append(newmsg, utf8); |
| |
1057 g_free(utf8); |
| |
1058 } |
| |
1059 } |
| |
1060 |
| |
1061 /* clear the attribute list */ |
| |
1062 g_datalist_clear(&attribs); |
| |
1063 |
| |
1064 /* continue from the end of the tag */ |
| |
1065 tmp = end + 1; |
| |
1066 } |
| |
1067 |
| |
1068 /* append any remaining message data (without the > :-) */ |
| |
1069 if (last++ && (last < binary)) |
| |
1070 newmsg = g_string_append_len(newmsg, last, binary - last); |
| |
1071 |
| |
1072 /* set the flag if we caught any images */ |
| |
1073 if (images) |
| |
1074 imflags |= GAIM_CONV_IM_IMAGES; |
| |
1075 } else { |
| |
1076 g_string_append_len(newmsg, msg, len); |
| |
1077 } |
| |
1078 |
| |
1079 /* XXX - I imagine Paco-Paco will want to do some voodoo with the encoding here */ |
| |
1080 serv_got_im(gc, sn, newmsg->str, imflags, time(NULL)); |
| |
1081 |
| |
1082 /* free up the message */ |
| |
1083 g_string_free(newmsg, TRUE); |
| |
1084 |
| |
1085 /* unref any images we allocated */ |
| |
1086 if (images) { |
| |
1087 GSList *tmp; |
| |
1088 int id; |
| |
1089 |
| |
1090 for (tmp = images; tmp != NULL; tmp = tmp->next) { |
| |
1091 id = GPOINTER_TO_INT(tmp->data); |
| |
1092 gaim_imgstore_unref(id); |
| |
1093 } |
| |
1094 |
| |
1095 g_slist_free(images); |
| |
1096 } |
| |
1097 |
| |
1098 return 1; |
| |
1099 } |
| |
1100 |
| |
1101 static int gaim_odc_typing(aim_session_t *sess, aim_frame_t *fr, ...) { |
| |
1102 va_list ap; |
| |
1103 char *sn; |
| |
1104 int typing; |
| |
1105 GaimConnection *gc = sess->aux_data; |
| |
1106 |
| |
1107 va_start(ap, fr); |
| |
1108 sn = va_arg(ap, char *); |
| |
1109 typing = va_arg(ap, int); |
| |
1110 va_end(ap); |
| |
1111 |
| |
1112 if (typing == 0x0002) { |
| |
1113 /* I had to leave this. It's just too funny. It reminds me of my sister. */ |
| |
1114 gaim_debug_info("oscar", |
| |
1115 "ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn); |
| |
1116 serv_got_typing(gc, sn, 0, GAIM_TYPING); |
| |
1117 } else if (typing == 0x0001) |
| |
1118 serv_got_typing(gc, sn, 0, GAIM_TYPED); |
| |
1119 else |
| |
1120 serv_got_typing_stopped(gc, sn); |
| |
1121 return 1; |
| |
1122 } |
| |
1123 |
| |
1124 static int gaim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *message, GaimConvImFlags imflags) { |
| |
1125 char *buf; |
| |
1126 size_t len; |
| |
1127 int ret; |
| |
1128 GString *msg = g_string_new("<HTML><BODY>"); |
| |
1129 GString *data = g_string_new("</BODY></HTML><BINARY>"); |
| |
1130 GData *attribs; |
| |
1131 const char *start, *end, *last; |
| |
1132 int oscar_id = 0; |
| |
1133 |
| |
1134 last = message; |
| |
1135 |
| |
1136 /* for each valid IMG tag... */ |
| |
1137 while (last && *last && gaim_markup_find_tag("img", last, &start, &end, &attribs)) { |
| |
1138 GaimStoredImage *image = NULL; |
| |
1139 const char *id; |
| |
1140 |
| |
1141 if (start - last) { |
| |
1142 g_string_append_len(msg, last, start - last); |
| |
1143 } |
| |
1144 |
| |
1145 id = g_datalist_get_data(&attribs, "id"); |
| |
1146 |
| |
1147 /* ... if it refers to a valid gaim image ... */ |
| |
1148 if (id && (image = gaim_imgstore_get(atoi(id)))) { |
| |
1149 /* ... append the message from start to the tag ... */ |
| |
1150 size_t size = gaim_imgstore_get_size(image); |
| |
1151 const char *filename = gaim_imgstore_get_filename(image); |
| |
1152 gpointer imgdata = gaim_imgstore_get_data(image); |
| |
1153 |
| |
1154 oscar_id++; |
| |
1155 |
| |
1156 /* ... insert a new img tag with the oscar id ... */ |
| |
1157 if (filename) |
| |
1158 g_string_append_printf(msg, |
| |
1159 "<IMG SRC=\"%s\" ID=\"%d\" DATASIZE=\"%zu\">", |
| |
1160 filename, oscar_id, size); |
| |
1161 else |
| |
1162 g_string_append_printf(msg, |
| |
1163 "<IMG ID=\"%d\" DATASIZE=\"%zu\">", |
| |
1164 oscar_id, size); |
| |
1165 |
| |
1166 /* ... and append the data to the binary section ... */ |
| |
1167 g_string_append_printf(data, "<DATA ID=\"%d\" SIZE=\"%zu\">", |
| |
1168 oscar_id, size); |
| |
1169 data = g_string_append_len(data, imgdata, size); |
| |
1170 data = g_string_append(data, "</DATA>"); |
| |
1171 } |
| |
1172 /* If the tag is invalid, skip it, thus no else here */ |
| |
1173 |
| |
1174 g_datalist_clear(&attribs); |
| |
1175 |
| |
1176 /* continue from the end of the tag */ |
| |
1177 last = end + 1; |
| |
1178 } |
| |
1179 |
| |
1180 /* append any remaining message data (without the > :-) */ |
| |
1181 if (last && *last) |
| |
1182 msg = g_string_append(msg, last); |
| |
1183 |
| |
1184 /* if we inserted any images in the binary section, append it */ |
| |
1185 if (oscar_id) { |
| |
1186 msg = g_string_append_len(msg, data->str, data->len); |
| |
1187 msg = g_string_append(msg, "</BINARY>"); |
| |
1188 } |
| |
1189 |
| |
1190 len = msg->len; |
| |
1191 buf = msg->str; |
| |
1192 g_string_free(msg, FALSE); |
| |
1193 g_string_free(data, TRUE); |
| |
1194 |
| |
1195 |
| |
1196 /* XXX - The last parameter below is the encoding. Let Paco-Paco do something with it. */ |
| |
1197 if (imflags & GAIM_CONV_IM_AUTO_RESP) |
| |
1198 ret = aim_odc_send_im(sess, conn, buf, len, 0, 1); |
| |
1199 else |
| |
1200 ret = aim_odc_send_im(sess, conn, buf, len, 0, 0); |
| |
1201 |
| |
1202 g_free(buf); |
| |
1203 |
| |
1204 return ret; |
| |
1205 } |
| |
1206 |
| |
1207 struct ask_do_dir_im { |
| |
1208 char *who; |
| |
1209 GaimConnection *gc; |
| |
1210 }; |
| |
1211 |
| |
1212 static void oscar_cancel_direct_im(struct ask_do_dir_im *data) { |
| |
1213 g_free(data->who); |
| |
1214 g_free(data); |
| |
1215 } |
| |
1216 |
| |
1217 static void oscar_direct_im(struct ask_do_dir_im *data) { |
| |
1218 GaimConnection *gc = data->gc; |
| |
1219 OscarData *od; |
| |
1220 struct oscar_direct_im *dim; |
| |
1221 int listenfd; |
| |
1222 |
| |
1223 if (!g_list_find(gaim_connections_get_all(), gc)) { |
| |
1224 g_free(data->who); |
| |
1225 g_free(data); |
| |
1226 return; |
| |
1227 } |
| |
1228 |
| |
1229 od = (OscarData *)gc->proto_data; |
| |
1230 |
| |
1231 dim = oscar_direct_im_find(od, data->who); |
| |
1232 if (dim) { |
| |
1233 if (!(dim->connected)) { /* We'll free the old, unconnected dim, and start over */ |
| |
1234 oscar_direct_im_disconnect(od, dim); |
| |
1235 gaim_debug_info("oscar", |
| |
1236 "Gave up on old direct IM, trying again\n"); |
| |
1237 } else { |
| |
1238 gaim_notify_error(gc, NULL, "DirectIM already open.", NULL); |
| |
1239 g_free(data->who); |
| |
1240 g_free(data); |
| 729 return; |
1241 return; |
| 730 } |
1242 } |
| |
1243 } |
| |
1244 dim = g_new0(struct oscar_direct_im, 1); |
| |
1245 dim->gc = gc; |
| |
1246 g_snprintf(dim->name, sizeof dim->name, "%s", data->who); |
| |
1247 |
| |
1248 listenfd = gaim_network_listen_range(5190, 5199); |
| |
1249 dim->conn = aim_odc_initiate(od->sess, data->who, listenfd, gaim_network_get_port_from_fd(listenfd)); |
| |
1250 if (dim->conn != NULL) { |
| |
1251 od->direct_ims = g_slist_append(od->direct_ims, dim); |
| |
1252 dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, |
| |
1253 oscar_callback, dim->conn); |
| |
1254 aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIM_ESTABLISHED, |
| |
1255 gaim_odc_initiate, 0); |
| |
1256 } else { |
| |
1257 gaim_notify_error(gc, NULL, _("Unable to open Direct IM"), NULL); |
| |
1258 oscar_direct_im_destroy(od, dim); |
| |
1259 } |
| |
1260 |
| |
1261 g_free(data->who); |
| |
1262 g_free(data); |
| |
1263 } |
| |
1264 |
| |
1265 /* this is the right click menu cb thingy */ |
| |
1266 static void oscar_ask_direct_im(GaimConnection *gc, const char *who) { |
| |
1267 gchar *buf; |
| |
1268 struct ask_do_dir_im *data = g_new0(struct ask_do_dir_im, 1); |
| |
1269 data->who = g_strdup(who); |
| |
1270 data->gc = gc; |
| |
1271 buf = g_strdup_printf(_("You have selected to open a Direct IM connection with %s."), who); |
| |
1272 |
| |
1273 gaim_request_action(gc, NULL, buf, |
| |
1274 _("Because this reveals your IP address, it " |
| |
1275 "may be considered a privacy risk. Do you " |
| |
1276 "wish to continue?"), |
| |
1277 0, data, 2, |
| |
1278 _("Connect"), G_CALLBACK(oscar_direct_im), |
| |
1279 _("Cancel"), G_CALLBACK(oscar_cancel_direct_im)); |
| |
1280 g_free(buf); |
| |
1281 } |
| |
1282 |
| |
1283 /***************************************************************************** |
| |
1284 * End scary direct im stuff |
| |
1285 *****************************************************************************/ |
| 731 |
1286 |
| 732 static void oscar_callback(gpointer data, gint source, GaimInputCondition condition) { |
1287 static void oscar_callback(gpointer data, gint source, GaimInputCondition condition) { |
| 733 aim_conn_t *conn = (aim_conn_t *)data; |
1288 aim_conn_t *conn = (aim_conn_t *)data; |
| 734 aim_session_t *sess = aim_conn_getsess(conn); |
1289 aim_session_t *sess = aim_conn_getsess(conn); |
| 735 GaimConnection *gc = sess ? sess->aux_data : NULL; |
1290 GaimConnection *gc = sess ? sess->aux_data : NULL; |
| 5892 va_end(ap); |
6362 va_end(ap); |
| 5893 |
6363 |
| 5894 return 0; |
6364 return 0; |
| 5895 } |
6365 } |
| 5896 |
6366 |
| 5897 /* |
|
| 5898 * We have just established a socket with the other dude, so set up some handlers. |
|
| 5899 */ |
|
| 5900 static int gaim_odc_initiate(aim_session_t *sess, aim_frame_t *fr, ...) { |
|
| 5901 GaimConnection *gc = sess->aux_data; |
|
| 5902 OscarData *od = (OscarData *)gc->proto_data; |
|
| 5903 GaimConversation *conv; |
|
| 5904 struct direct_im *dim; |
|
| 5905 char buf[256]; |
|
| 5906 char *sn; |
|
| 5907 va_list ap; |
|
| 5908 aim_conn_t *newconn, *listenerconn; |
|
| 5909 |
|
| 5910 va_start(ap, fr); |
|
| 5911 newconn = va_arg(ap, aim_conn_t *); |
|
| 5912 listenerconn = va_arg(ap, aim_conn_t *); |
|
| 5913 va_end(ap); |
|
| 5914 |
|
| 5915 aim_conn_close(listenerconn); |
|
| 5916 aim_conn_kill(sess, &listenerconn); |
|
| 5917 |
|
| 5918 sn = g_strdup(aim_odc_getsn(newconn)); |
|
| 5919 |
|
| 5920 gaim_debug_info("oscar", |
|
| 5921 "DirectIM: initiate success to %s\n", sn); |
|
| 5922 dim = find_direct_im(od, sn); |
|
| 5923 |
|
| 5924 conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, sn); |
|
| 5925 gaim_input_remove(dim->watcher); |
|
| 5926 dim->conn = newconn; |
|
| 5927 dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); |
|
| 5928 dim->connected = TRUE; |
|
| 5929 g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), sn); |
|
| 5930 g_free(sn); |
|
| 5931 gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL)); |
|
| 5932 |
|
| 5933 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_odc_incoming, 0); |
|
| 5934 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_odc_typing, 0); |
|
| 5935 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER, gaim_odc_update_ui, 0); |
|
| 5936 |
|
| 5937 return 1; |
|
| 5938 } |
|
| 5939 |
|
| 5940 /* |
|
| 5941 * This is called when each chunk of an image is received. It can be used to |
|
| 5942 * update a progress bar, or to eat lots of dry cat food. Wet cat food is |
|
| 5943 * nasty, you sicko. |
|
| 5944 */ |
|
| 5945 static int gaim_odc_update_ui(aim_session_t *sess, aim_frame_t *fr, ...) { |
|
| 5946 va_list ap; |
|
| 5947 char *sn; |
|
| 5948 double percent; |
|
| 5949 GaimConnection *gc = sess->aux_data; |
|
| 5950 OscarData *od = (OscarData *)gc->proto_data; |
|
| 5951 GaimConversation *c; |
|
| 5952 struct direct_im *dim; |
|
| 5953 |
|
| 5954 va_start(ap, fr); |
|
| 5955 sn = va_arg(ap, char *); |
|
| 5956 percent = va_arg(ap, double); |
|
| 5957 va_end(ap); |
|
| 5958 |
|
| 5959 if (!sn || !(dim = find_direct_im(od, sn))) |
|
| 5960 return 1; |
|
| 5961 if (dim->watcher) { |
|
| 5962 gaim_input_remove(dim->watcher); /* Otherwise, the callback will callback */ |
|
| 5963 dim->watcher = 0; |
|
| 5964 } |
|
| 5965 |
|
| 5966 c = gaim_find_conversation_with_account(sn, gaim_connection_get_account(gc)); |
|
| 5967 if (c != NULL) |
|
| 5968 gaim_conversation_update_progress(c, percent); |
|
| 5969 dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, |
|
| 5970 oscar_callback, dim->conn); |
|
| 5971 |
|
| 5972 return 1; |
|
| 5973 } |
|
| 5974 |
|
| 5975 /* |
|
| 5976 * This is called after a direct IM has been received in its entirety. This |
|
| 5977 * function is passed a long chunk of data which contains the IM with any |
|
| 5978 * data chunks (images) appended to it. |
|
| 5979 * |
|
| 5980 * This function rips out all the data chunks and creates an imgstore for |
|
| 5981 * each one. In order to do this, it first goes through the IM and takes |
|
| 5982 * out all the IMG tags. When doing so, it rewrites the original IMG tag |
|
| 5983 * with one compatible with the imgstore Gaim core code. For each one, we |
|
| 5984 * then read in chunks of data from the end of the message and actually |
|
| 5985 * create the img store using the given data. |
|
| 5986 * |
|
| 5987 * For somewhat easy reference, here's a sample message |
|
| 5988 * (without the whitespace and asterisks): |
|
| 5989 * |
|
| 5990 * <HTML><BODY BGCOLOR="#ffffff"> |
|
| 5991 * <FONT LANG="0"> |
|
| 5992 * This is a really stupid picture:<BR> |
|
| 5993 * <IMG SRC="Sample.jpg" ID="1" WIDTH="283" HEIGHT="212" DATASIZE="9894"><BR> |
|
| 5994 * Yeah it is<BR> |
|
| 5995 * Here is another one:<BR> |
|
| 5996 * <IMG SRC="Soap Bubbles.bmp" ID="2" WIDTH="256" HEIGHT="256" DATASIZE="65978"> |
|
| 5997 * </FONT> |
|
| 5998 * </BODY></HTML> |
|
| 5999 * <BINARY> |
|
| 6000 * <DATA ID="1" SIZE="9894">datadatadatadata</DATA> |
|
| 6001 * <DATA ID="2" SIZE="65978">datadatadatadata</DATA> |
|
| 6002 * </BINARY> |
|
| 6003 */ |
|
| 6004 static int gaim_odc_incoming(aim_session_t *sess, aim_frame_t *fr, ...) { |
|
| 6005 GaimConnection *gc = sess->aux_data; |
|
| 6006 GaimConvImFlags imflags = 0; |
|
| 6007 gchar *utf8; |
|
| 6008 GString *newmsg = g_string_new(""); |
|
| 6009 GSList *images = NULL; |
|
| 6010 va_list ap; |
|
| 6011 const char *sn, *msg, *msgend, *binary; |
|
| 6012 size_t len; |
|
| 6013 int encoding, isawaymsg; |
|
| 6014 |
|
| 6015 va_start(ap, fr); |
|
| 6016 sn = va_arg(ap, const char *); |
|
| 6017 msg = va_arg(ap, const char *); |
|
| 6018 len = va_arg(ap, size_t); |
|
| 6019 encoding = va_arg(ap, int); |
|
| 6020 isawaymsg = va_arg(ap, int); |
|
| 6021 va_end(ap); |
|
| 6022 msgend = msg + len; |
|
| 6023 |
|
| 6024 gaim_debug_info("oscar", |
|
| 6025 "Got DirectIM message from %s\n", sn); |
|
| 6026 |
|
| 6027 if (isawaymsg) |
|
| 6028 imflags |= GAIM_CONV_IM_AUTO_RESP; |
|
| 6029 |
|
| 6030 /* message has a binary trailer */ |
|
| 6031 if ((binary = gaim_strcasestr(msg, "<binary>"))) { |
|
| 6032 GData *attribs; |
|
| 6033 const char *tmp, *start, *end, *last = NULL; |
|
| 6034 |
|
| 6035 tmp = msg; |
|
| 6036 |
|
| 6037 /* for each valid image tag... */ |
|
| 6038 while (gaim_markup_find_tag("img", tmp, &start, &end, &attribs)) { |
|
| 6039 const char *id, *src, *datasize; |
|
| 6040 const char *tag = NULL, *data = NULL; |
|
| 6041 size_t size; |
|
| 6042 int imgid = 0; |
|
| 6043 |
|
| 6044 /* update the location of the last img tag */ |
|
| 6045 last = end; |
|
| 6046 |
|
| 6047 /* grab attributes */ |
|
| 6048 id = g_datalist_get_data(&attribs, "id"); |
|
| 6049 src = g_datalist_get_data(&attribs, "src"); |
|
| 6050 datasize = g_datalist_get_data(&attribs, "datasize"); |
|
| 6051 |
|
| 6052 /* if we have id & datasize, build the data tag */ |
|
| 6053 if (id && datasize) |
|
| 6054 tag = g_strdup_printf("<data id=\"%s\" size=\"%s\">", id, datasize); |
|
| 6055 |
|
| 6056 /* if we have a tag, find the start of the data */ |
|
| 6057 if (tag && (data = gaim_strcasestr(binary, tag))) |
|
| 6058 data += strlen(tag); |
|
| 6059 |
|
| 6060 /* check the data is here and store it */ |
|
| 6061 if (data + (size = atoi(datasize)) <= msgend) |
|
| 6062 imgid = gaim_imgstore_add(data, size, src); |
|
| 6063 |
|
| 6064 /* |
|
| 6065 * XXX - The code below contains some calls to oscar_encoding_to_utf8 |
|
| 6066 * The hardcoded "us-ascii" value REALLY needs to be removed. |
|
| 6067 */ |
|
| 6068 /* if we have a stored image... */ |
|
| 6069 if (imgid) { |
|
| 6070 /* append the message up to the tag */ |
|
| 6071 utf8 = oscar_encoding_to_utf8("us-ascii", tmp, start - tmp); |
|
| 6072 if (utf8 != NULL) { |
|
| 6073 newmsg = g_string_append(newmsg, utf8); |
|
| 6074 g_free(utf8); |
|
| 6075 } |
|
| 6076 |
|
| 6077 /* write the new image tag */ |
|
| 6078 g_string_append_printf(newmsg, "<IMG ID=\"%d\">", imgid); |
|
| 6079 |
|
| 6080 /* and record the image number */ |
|
| 6081 images = g_slist_append(images, GINT_TO_POINTER(imgid)); |
|
| 6082 } else { |
|
| 6083 /* otherwise, copy up to the end of the tag */ |
|
| 6084 utf8 = oscar_encoding_to_utf8("us-ascii", tmp, (end + 1) - tmp); |
|
| 6085 if (utf8 != NULL) { |
|
| 6086 newmsg = g_string_append(newmsg, utf8); |
|
| 6087 g_free(utf8); |
|
| 6088 } |
|
| 6089 } |
|
| 6090 |
|
| 6091 /* clear the attribute list */ |
|
| 6092 g_datalist_clear(&attribs); |
|
| 6093 |
|
| 6094 /* continue from the end of the tag */ |
|
| 6095 tmp = end + 1; |
|
| 6096 } |
|
| 6097 |
|
| 6098 /* append any remaining message data (without the > :-) */ |
|
| 6099 if (last++ && (last < binary)) |
|
| 6100 newmsg = g_string_append_len(newmsg, last, binary - last); |
|
| 6101 |
|
| 6102 /* set the flag if we caught any images */ |
|
| 6103 if (images) |
|
| 6104 imflags |= GAIM_CONV_IM_IMAGES; |
|
| 6105 } else { |
|
| 6106 g_string_append_len(newmsg, msg, len); |
|
| 6107 } |
|
| 6108 |
|
| 6109 /* XXX - I imagine Paco-Paco will want to do some voodoo with the encoding here */ |
|
| 6110 serv_got_im(gc, sn, newmsg->str, imflags, time(NULL)); |
|
| 6111 |
|
| 6112 /* free up the message */ |
|
| 6113 g_string_free(newmsg, TRUE); |
|
| 6114 |
|
| 6115 /* unref any images we allocated */ |
|
| 6116 if (images) { |
|
| 6117 GSList *tmp; |
|
| 6118 int id; |
|
| 6119 |
|
| 6120 for (tmp = images; tmp != NULL; tmp = tmp->next) { |
|
| 6121 id = GPOINTER_TO_INT(tmp->data); |
|
| 6122 gaim_imgstore_unref(id); |
|
| 6123 } |
|
| 6124 |
|
| 6125 g_slist_free(images); |
|
| 6126 } |
|
| 6127 |
|
| 6128 return 1; |
|
| 6129 } |
|
| 6130 |
|
| 6131 static int gaim_odc_typing(aim_session_t *sess, aim_frame_t *fr, ...) { |
|
| 6132 va_list ap; |
|
| 6133 char *sn; |
|
| 6134 int typing; |
|
| 6135 GaimConnection *gc = sess->aux_data; |
|
| 6136 |
|
| 6137 va_start(ap, fr); |
|
| 6138 sn = va_arg(ap, char *); |
|
| 6139 typing = va_arg(ap, int); |
|
| 6140 va_end(ap); |
|
| 6141 |
|
| 6142 if (typing == 0x0002) { |
|
| 6143 /* I had to leave this. It's just too funny. It reminds me of my sister. */ |
|
| 6144 gaim_debug_info("oscar", |
|
| 6145 "ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn); |
|
| 6146 serv_got_typing(gc, sn, 0, GAIM_TYPING); |
|
| 6147 } else if (typing == 0x0001) |
|
| 6148 serv_got_typing(gc, sn, 0, GAIM_TYPED); |
|
| 6149 else |
|
| 6150 serv_got_typing_stopped(gc, sn); |
|
| 6151 return 1; |
|
| 6152 } |
|
| 6153 |
|
| 6154 static int gaim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *message, GaimConvImFlags imflags) { |
|
| 6155 char *buf; |
|
| 6156 size_t len; |
|
| 6157 int ret; |
|
| 6158 GString *msg = g_string_new(""); |
|
| 6159 GString *data = g_string_new("<BINARY>"); |
|
| 6160 GData *attribs; |
|
| 6161 const char *start, *end, *last; |
|
| 6162 int oscar_id = 0; |
|
| 6163 |
|
| 6164 last = message; |
|
| 6165 |
|
| 6166 /* for each valid IMG tag... */ |
|
| 6167 while (last && *last && gaim_markup_find_tag("img", last, &start, &end, &attribs)) { |
|
| 6168 GaimStoredImage *image = NULL; |
|
| 6169 const char *id; |
|
| 6170 |
|
| 6171 if (start - last) { |
|
| 6172 g_string_append_len(msg, last, start - last); |
|
| 6173 } |
|
| 6174 |
|
| 6175 id = g_datalist_get_data(&attribs, "id"); |
|
| 6176 |
|
| 6177 /* ... if it refers to a valid gaim image ... */ |
|
| 6178 if (id && (image = gaim_imgstore_get(atoi(id)))) { |
|
| 6179 /* ... append the message from start to the tag ... */ |
|
| 6180 size_t size = gaim_imgstore_get_size(image); |
|
| 6181 const char *filename = gaim_imgstore_get_filename(image); |
|
| 6182 gpointer imgdata = gaim_imgstore_get_data(image); |
|
| 6183 |
|
| 6184 oscar_id++; |
|
| 6185 |
|
| 6186 /* ... insert a new img tag with the oscar id ... */ |
|
| 6187 if (filename) |
|
| 6188 g_string_append_printf(msg, |
|
| 6189 "<IMG SRC=\"file://%s\" ID=\"%d\" DATASIZE=\"%zu\">", |
|
| 6190 filename, oscar_id, size); |
|
| 6191 else |
|
| 6192 g_string_append_printf(msg, |
|
| 6193 "<IMG ID=\"%d\" DATASIZE=\"%zu\">", |
|
| 6194 oscar_id, size); |
|
| 6195 |
|
| 6196 /* ... and append the data to the binary section ... */ |
|
| 6197 g_string_append_printf(data, "<DATA ID=\"%d\" SIZE=\"%zu\">", |
|
| 6198 oscar_id, size); |
|
| 6199 data = g_string_append_len(data, imgdata, size); |
|
| 6200 data = g_string_append(data, "</DATA>"); |
|
| 6201 } |
|
| 6202 /* If the tag is invalid, skip it, thus no else here */ |
|
| 6203 |
|
| 6204 g_datalist_clear(&attribs); |
|
| 6205 |
|
| 6206 /* continue from the end of the tag */ |
|
| 6207 last = end + 1; |
|
| 6208 } |
|
| 6209 |
|
| 6210 /* append any remaining message data (without the > :-) */ |
|
| 6211 if (last && *last) |
|
| 6212 msg = g_string_append(msg, last); |
|
| 6213 |
|
| 6214 /* if we inserted any images in the binary section, append it */ |
|
| 6215 if (oscar_id) { |
|
| 6216 msg = g_string_append_len(msg, data->str, data->len); |
|
| 6217 msg = g_string_append(msg, "</BINARY>"); |
|
| 6218 } |
|
| 6219 |
|
| 6220 len = msg->len; |
|
| 6221 buf = msg->str; |
|
| 6222 g_string_free(msg, FALSE); |
|
| 6223 g_string_free(data, TRUE); |
|
| 6224 |
|
| 6225 |
|
| 6226 /* XXX - The last parameter below is the encoding. Let Paco-Paco do something with it. */ |
|
| 6227 if (imflags & GAIM_CONV_IM_AUTO_RESP) |
|
| 6228 ret = aim_odc_send_im(sess, conn, buf, len, 0, 1); |
|
| 6229 else |
|
| 6230 ret = aim_odc_send_im(sess, conn, buf, len, 0, 0); |
|
| 6231 |
|
| 6232 g_free(buf); |
|
| 6233 |
|
| 6234 return ret; |
|
| 6235 } |
|
| 6236 |
|
| 6237 struct ask_do_dir_im { |
|
| 6238 char *who; |
|
| 6239 GaimConnection *gc; |
|
| 6240 }; |
|
| 6241 |
|
| 6242 static void oscar_cancel_direct_im(struct ask_do_dir_im *data) { |
|
| 6243 g_free(data->who); |
|
| 6244 g_free(data); |
|
| 6245 } |
|
| 6246 |
|
| 6247 static void oscar_direct_im(struct ask_do_dir_im *data) { |
|
| 6248 GaimConnection *gc = data->gc; |
|
| 6249 OscarData *od; |
|
| 6250 struct direct_im *dim; |
|
| 6251 int listenfd; |
|
| 6252 |
|
| 6253 if (!g_list_find(gaim_connections_get_all(), gc)) { |
|
| 6254 g_free(data->who); |
|
| 6255 g_free(data); |
|
| 6256 return; |
|
| 6257 } |
|
| 6258 |
|
| 6259 od = (OscarData *)gc->proto_data; |
|
| 6260 |
|
| 6261 dim = find_direct_im(od, data->who); |
|
| 6262 if (dim) { |
|
| 6263 if (!(dim->connected)) { /* We'll free the old, unconnected dim, and start over */ |
|
| 6264 od->direct_ims = g_slist_remove(od->direct_ims, dim); |
|
| 6265 gaim_input_remove(dim->watcher); |
|
| 6266 g_free(dim); |
|
| 6267 gaim_debug_info("oscar", |
|
| 6268 "Gave up on old direct IM, trying again\n"); |
|
| 6269 } else { |
|
| 6270 gaim_notify_error(gc, NULL, "DirectIM already open.", NULL); |
|
| 6271 g_free(data->who); |
|
| 6272 g_free(data); |
|
| 6273 return; |
|
| 6274 } |
|
| 6275 } |
|
| 6276 dim = g_new0(struct direct_im, 1); |
|
| 6277 dim->gc = gc; |
|
| 6278 g_snprintf(dim->name, sizeof dim->name, "%s", data->who); |
|
| 6279 |
|
| 6280 listenfd = gaim_network_listen_range(5190, 5199); |
|
| 6281 dim->conn = aim_odc_initiate(od->sess, data->who, listenfd, gaim_network_get_port_from_fd(listenfd)); |
|
| 6282 if (dim->conn != NULL) { |
|
| 6283 od->direct_ims = g_slist_append(od->direct_ims, dim); |
|
| 6284 dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, |
|
| 6285 oscar_callback, dim->conn); |
|
| 6286 aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIM_ESTABLISHED, |
|
| 6287 gaim_odc_initiate, 0); |
|
| 6288 } else { |
|
| 6289 gaim_notify_error(gc, NULL, _("Unable to open Direct IM"), NULL); |
|
| 6290 g_free(dim); |
|
| 6291 } |
|
| 6292 |
|
| 6293 g_free(data->who); |
|
| 6294 g_free(data); |
|
| 6295 } |
|
| 6296 |
|
| 6297 static void oscar_ask_direct_im(GaimConnection *gc, const char *who) { |
|
| 6298 gchar *buf; |
|
| 6299 struct ask_do_dir_im *data = g_new0(struct ask_do_dir_im, 1); |
|
| 6300 data->who = g_strdup(who); |
|
| 6301 data->gc = gc; |
|
| 6302 buf = g_strdup_printf(_("You have selected to open a Direct IM connection with %s."), who); |
|
| 6303 |
|
| 6304 gaim_request_action(gc, NULL, buf, |
|
| 6305 _("Because this reveals your IP address, it " |
|
| 6306 "may be considered a privacy risk. Do you " |
|
| 6307 "wish to continue?"), |
|
| 6308 0, data, 2, |
|
| 6309 _("Connect"), G_CALLBACK(oscar_direct_im), |
|
| 6310 _("Cancel"), G_CALLBACK(oscar_cancel_direct_im)); |
|
| 6311 g_free(buf); |
|
| 6312 } |
|
| 6313 |
|
| 6314 static void oscar_set_permit_deny(GaimConnection *gc) { |
6367 static void oscar_set_permit_deny(GaimConnection *gc) { |
| 6315 GaimAccount *account = gaim_connection_get_account(gc); |
6368 GaimAccount *account = gaim_connection_get_account(gc); |
| 6316 OscarData *od = (OscarData *)gc->proto_data; |
6369 OscarData *od = (OscarData *)gc->proto_data; |
| 6317 #ifdef NOSSI |
6370 #ifdef NOSSI |
| 6318 GSList *list; |
6371 GSList *list; |