/******************************************************************** Copyright (C) 2000 Bassoukos Tassos This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "guiprefs.h" #include "connection.h" #include "protocol.h" #include "messages.h" #include "transaction.h" #include "users.h" #include "main.h" #include "guiutils.h" #include "chat.h" #include "userwidget.h" #include "privs.h" #include "privchat.h" #include "hldat.h" #include "pixmap.h" #define PRVCHAT "PrivChat" typedef struct { Connection *c; int counter; GList *chats; } PrivChatData; typedef struct { Connection *c; PrivChatData *pcd; guint32 chatwindowid; ChatWindowWidgets cww; NotebookPage *nb; char *subject; } PrivChat; static PrivChat *privchat_find_or_create(Connection *c,guint32 chatwindow); /* ============================ */ static int find_chat_func(PrivChat *pc,gpointer data){ return pc->chatwindowid - GPOINTER_TO_INT(data); } static PrivChat *get_chat(Connection *c, gint32 cwid){ PrivChatData *pcd=connection_get_data(c,PRVCHAT); GList *l; if(pcd==NULL) return NULL; l=g_list_find_custom(pcd->chats,GINT_TO_POINTER(cwid),(GCompareFunc)find_chat_func); return l==NULL?NULL:l->data; } static void privchat_destroy(PrivChat *pc){ pc->pcd->chats=g_list_remove(pc->pcd->chats,pc); userwidget_destroy(pc->cww.userwidget); gutils_nbpage_destroy(pc->nb); free(pc->subject); free(pc); } static void privchat_destroy_all(Connection *c,gpointer data){ PrivChatData *pcd=connection_get_data(c,PRVCHAT); if(pcd==NULL) return; connection_set_data(c,PRVCHAT,NULL); while(pcd->chats!=NULL) privchat_destroy(pcd->chats->data); gtk_signal_disconnect_by_data(GTK_OBJECT(pcd->c),pcd); free(pcd); } static PrivChatData *privchatdata_get_or_create(Connection *c){ PrivChatData *pcd=connection_get_data(c,PRVCHAT); if(pcd==NULL){ pcd=malloc(sizeof(PrivChatData)); pcd->c=c; pcd->counter=0; pcd->chats=NULL; connection_set_data(c,PRVCHAT,pcd); gtk_signal_connect(GTK_OBJECT(c),"destroy",GTK_SIGNAL_FUNC(privchat_destroy_all),pcd); } return pcd; } void privchat_handle_other_leave(Connection *c,Message *m,gpointer data){ HLObject *cwid=message_find_object(m,HLO_CHATWINDOW); HLObject *who=message_find_object(m,HLO_SOCKET); PrivChat *pc; if(cwid!=NULL && who!=NULL && (pc=get_chat(c,cwid->data.number))!=NULL) userwidget_remove(pc->cww.userwidget,who->data.number); message_unref(m); } void privchat_handle_other_join(Connection *c,Message *m,gpointer data){ HLObject *cwid=message_find_object(m,HLO_CHATWINDOW); HLObject *who=message_find_object(m,HLO_SOCKET); PrivChat *pc; if(cwid!=NULL && who!=NULL && (pc=get_chat(c,cwid->data.number))!=NULL) userwidget_add(pc->cww.userwidget,who->data.number); message_unref(m); } void privchat_handle_subject_change(Connection *c,Message *m,gpointer data){ HLObject *cwid=message_find_object(m,HLO_CHATWINDOW); HLObject *subject=message_find_object(m,HLO_SUBJECT); PrivChat *pc; if(cwid!=NULL && subject!=NULL && (pc=get_chat(c,cwid->data.number))!=NULL){ gtk_entry_set_text(GTK_ENTRY(pc->cww.subject),subject->data.string); free(pc->subject); pc->subject=strdup(subject->data.string); } message_unref(m); } void privchat_handle_chat(Connection *c,Message *m,gpointer data){ HLObject *cwid=message_find_object(m,HLO_CHATWINDOW); PrivChat *pc=NULL; if(cwid!=NULL && (pc=get_chat(c,cwid->data.number))!=NULL){ play_sound(HL_SOUND_DOORBELL); chat_pane_handle_chat(&pc->cww,m); } else { message_unref(m); } } void privchat_handle_privchat(Connection *c,Message *m,gpointer data){ ConnectionMsgFunc func=data; func(c,m,NULL); } static void privchat_change_subject(GtkEntry *e,PrivChat *pc){ char *text; Message *m=message_new(pc->c,HLCT_CHANGESUBJECT); text=gtk_editable_get_chars(GTK_EDITABLE(pc->cww.subject),0,-1); gtk_entry_set_text(GTK_ENTRY(pc->cww.subject),""); message_add_object(m,create_string(HLO_SUBJECT,text)); message_add_object(m,create_number(HLO_CHATWINDOW,pc->chatwindowid)); message_fire_and_forget(m); free(m); } static void privchat_say(ChatWindowWidgets *cww, gpointer data,int as_emote){ PrivChat *pc=data; chat_pane_send_chat(pc->c,cww,create_number(HLO_CHATWINDOW,pc->chatwindowid),as_emote); } static void privchat_leave(GtkWidget *w,PrivChat *pc){ Message *m=message_new(pc->c,HLCT_LEAVEPCHAT); message_add_object(m,create_number(HLO_CHATWINDOW,pc->chatwindowid)); message_fire_and_forget(m); privchat_destroy(pc); } static GnomeUIInfo privchat_toolbar[] = { GNOMEUIINFO_ITEM_STOCK(N_("Leave"),N_("Leave this chat"), privchat_leave, HL_STOCK_PIXMAP_CLOSE_PAGE), GNOMEUIINFO_END }; static PrivChat *privchat_find_or_create(Connection *c,guint32 chatwindow){ PrivChatData *pcd=privchatdata_get_or_create(c); PrivChat *pc; char buf[128]; if((pc=get_chat(c,chatwindow))!=NULL) return pc; pc=malloc(sizeof(PrivChat)); pcd->counter++; pc->pcd=pcd; pc->c=c; pc->chatwindowid=chatwindow; sprintf(buf,_("Chat #%d"),pcd->counter); pc->nb=gutils_nbpage_new("PrivChat",privchat_toolbar,c,buf,"privchat",pc); pc->subject=strdup(buf); pc->cww.sendmsg=privchat_say; pc->cww.user_data=pc; chat_pane_create(pc->nb,&pc->cww,TRUE); gtk_signal_connect(GTK_OBJECT(pc->cww.subject),"activate", GTK_SIGNAL_FUNC(privchat_change_subject),(gpointer)pc); pcd->chats=g_list_prepend(pcd->chats,pc); return pc; } /* ======================================= */ static void privchat_do_accept_privchat(Transaction *t,Message *m,gpointer dummy){ HLObject *cwid=message_find_object(m,HLO_CHATWINDOW); HLObject *subject=message_find_object(m,HLO_SUBJECT); int count; HLObject **users=message_extract_objects(m,HLO_USERLISTENTRY,&count); PrivChat *pc; Connection *c=t->c; if(users!=NULL && cwid!=NULL){ int i; pc=privchat_find_or_create(c,cwid->data.number); for(i=0;icww.userwidget,users[i]->data.userlistentry->u.socket); } if(subject!=NULL){ gtk_entry_set_text(GTK_ENTRY(pc->cww.subject),subject->data.string); } } if(users!=NULL) objects_destroy(users); } static void privchat_invite_accept(GtkButton *but,gpointer data){ Message *m=data; Connection *c=m->c; HLObject *cwid=message_find_object(m,HLO_CHATWINDOW); if(cwid!=NULL){ Transaction *r=transaction_new(c,HLCT_REQJOINPCHAT); message_add_object(r->request,create_number(HLO_CHATWINDOW,cwid->data.number)); transaction_set_error_check(r,strdup(_("Could not join chat channel:"))); gtk_signal_connect(GTK_OBJECT(r),"response-received", GTK_SIGNAL_FUNC(privchat_do_accept_privchat),NULL); transaction_start(r); } } static void privchat_invite_reject(GtkButton *but,gpointer data){ Message *m=data; Connection *c=m->c; HLObject *cwid=message_find_object(m,HLO_CHATWINDOW); if(cwid!=NULL){ Message *r=message_new(c,HLCT_REJECTPCHAT); message_add_object(r,create_number(HLO_CHATWINDOW,cwid->data.number)); message_fire_and_forget(r); } } static void privchat_dialog_invite(Message *m){ char buf[256]; GtkWidget *top; UserlistEntry *ue; HLObject *sock=message_find_object(m,HLO_SOCKET); Connection *c=m->c; char *uname; int socket; socket=sock->data.number; ue=get_user_by_socket(c,socket); uname=(ue!=NULL && ue->name!=NULL)?ue->name:NULL; if(uname!=NULL) sprintf(buf,_("Invitation from %s"),uname); else sprintf(buf,_("Invitation from socket %d ???"),socket); top=gnome_dialog_new(buf,_("Accept"),_("Decline"),NULL); gnome_dialog_button_connect(GNOME_DIALOG(top),0, GTK_SIGNAL_FUNC(privchat_invite_accept), (gpointer)m); gnome_dialog_button_connect(GNOME_DIALOG(top),1, GTK_SIGNAL_FUNC(privchat_invite_reject), (gpointer)m); if(uname!=NULL) sprintf(buf,"%s has invited you to a chat channel",uname); else sprintf(buf,"Socked %d has invited tou a chat channel",socket); gtk_box_pack_end(GTK_BOX(GNOME_DIALOG(top)->vbox),gtk_label_new(buf),FALSE,FALSE,0); gtk_signal_connect_object(GTK_OBJECT(top),"destroy", GTK_SIGNAL_FUNC(gtk_object_destroy), GTK_OBJECT(m)); gnome_dialog_button_connect_object(GNOME_DIALOG(top),0, GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(top)); gnome_dialog_button_connect_object(GNOME_DIALOG(top),1, GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(top)); gtk_widget_show_all(top); } void privchat_handle_invite(Connection *c,Message *m,gpointer data){ HLObject *cwid=message_find_object(m,HLO_CHATWINDOW); HLObject *who=message_find_object(m,HLO_SOCKET); if(cwid!=NULL && who!=NULL){ if(privchat_auto_join){ privchat_invite_accept(NULL,m); } else { privchat_dialog_invite(m); } } message_unref(m); } /* ======================================= */ static void privchat_do_start_privchat(Transaction *t,Message *m,gpointer dummy){ HLObject *sock=message_find_object(m,HLO_SOCKET); HLObject *cw=message_find_object(m,HLO_CHATWINDOW); if(sock!=NULL && cw!=NULL){ privchat_find_or_create(t->c,cw->data.number); message_ref(m); /* this is needed since privchat_handle_other_join unref()'s the massage passed */ privchat_handle_other_join(t->c,m,NULL); } } void privchat_start_privchat_with_user(Connection *c,int socket){ PrivChatData *pcd=privchatdata_get_or_create(c); Transaction *t=transaction_new(pcd->c,HLCT_CREATEPCHAT); message_add_object(t->request,create_number(HLO_SOCKET,socket)); transaction_set_error_check(t,strdup(_("Could not invite to chat channel:"))); gtk_signal_connect(GTK_OBJECT(t),"response-received",GTK_SIGNAL_FUNC(privchat_do_start_privchat),NULL); transaction_start(t); } /* ======================================= */ static void privchat_invite_ok(Transaction *t,Message *m,UserWidget *uw){ HLObject *socket=message_find_object(m,HLO_SOCKET); HLObject *cwid=message_find_object(m,HLO_CHATWINDOW); PrivChat *pc; if(socket!=NULL && cwid !=NULL) { pc=privchat_find_or_create(uw->c,cwid->data.number); userwidget_add(pc->cww.userwidget,socket->data.number); } } static void privchat_invite_new(GtkWidget *w,gpointer cwid){ Transaction *t; UserWidget *uw=gtk_object_get_user_data(GTK_OBJECT(w)); t=transaction_new(uw->c,HLCT_CREATEPCHAT); message_add_object(t->request,create_number(HLO_SOCKET,userwidget_get_seluser(uw))); transaction_set_error_check(t,strdup(_("Could not invite to chat channel:"))); gtk_signal_connect(GTK_OBJECT(t),"response-received",GTK_SIGNAL_FUNC(privchat_invite_ok),uw); transaction_start(t); } static void privchat_invite_exists(GtkWidget *w,gpointer cwid){ Message *m; UserWidget *uw=gtk_object_get_user_data(GTK_OBJECT(w)); m=message_new(uw->c,HLCT_ADDTOPCHAT); message_add_object(m,create_number(HLO_CHATWINDOW,GPOINTER_TO_INT(cwid))); message_add_object(m,create_number(HLO_SOCKET,userwidget_get_seluser(uw))); message_fire_and_forget(m); } void privchat_make_invite_menu(UserWidget *uw, GtkMenu *menu){ GtkWidget *mi,*m; GList *gl; gboolean need_separator=TRUE; PrivChatData *pcd=privchatdata_get_or_create(uw->c); m=gtk_menu_new(); mi=gtk_menu_item_new_with_label(_("New Chat")); gtk_object_set_user_data(GTK_OBJECT(mi),uw); gtk_signal_connect(GTK_OBJECT(mi),"activate",GTK_SIGNAL_FUNC(privchat_invite_new),NULL); gtk_menu_append(GTK_MENU(m),mi); for(gl=pcd->chats;gl!=NULL;gl=gl->next){ if(need_separator==TRUE){ need_separator=FALSE; gtk_menu_append(GTK_MENU(m),gtk_menu_item_new()); } mi=gtk_menu_item_new_with_label(((PrivChat *)gl->data)->subject); gtk_object_set_user_data(GTK_OBJECT(mi),uw); gtk_signal_connect(GTK_OBJECT(mi),"activate",GTK_SIGNAL_FUNC(privchat_invite_exists), GINT_TO_POINTER(((PrivChat *)gl->data)->chatwindowid)); gtk_menu_append(GTK_MENU(m),mi); } gtk_widget_show_all(m); mi=gtk_object_get_data(GTK_OBJECT(menu),"privchat_id"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mi),m); } void privchat_attach_to_menu(Connection *c, GtkMenu *menu, GtkWidget *mi){ gtk_object_set_data(GTK_OBJECT(menu),"privchat_id",mi); }