/******************************************************************** 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 #ifdef HAVE_STRINGS_H #include #endif #include #include "tasks.h" #include "bookmarks.h" #include "connection.h" #include "protocol.h" #include "smalltrans.h" #include "userlist.h" #include "userwidget.h" #include "hldat.h" #include "pixmap.h" #define USERLIST "UserList" typedef struct { Connection *c; int numusers; Transaction *transaction; UserlistEntry **users; GList *hooks; } UserlistData; #define forallhooks(u,l) for(l=g_list_first(u->hooks);l!=NULL;l=g_list_next(l)) static UserlistData *get_uld(Connection *c); static void userlist_clear(UserlistData *u){ if(u->users) { int i; for(i = 0; i < u->numusers; i++) { free(u->users[i]->name); free(u->users[i]); } free(u->users); u->users=NULL; } u->numusers=0; } static void userlist_destroy(Connection *c,gpointer data){ UserlistData *u=(UserlistData *)data; while(u->hooks){ UserlistOps *ops=u->hooks->data; if(ops->destroy==NULL) free(ops); else ops->destroy(ops->c,ops,ops->data); u->hooks=g_list_remove(u->hooks,ops); } connection_set_data(c,USERLIST,NULL); userlist_clear(u); if(u->transaction) gtk_object_destroy(GTK_OBJECT(u->transaction)); free(u); } static int *get_socks(UserlistData *u){ int i; int *sockets=NULL; if(u->numusers!=0){ sockets=malloc(sizeof(int)*u->numusers); for(i=0;inumusers;i++) sockets[i]=u->users[i]->u.socket; } return sockets; } void userlist_add_ops(Connection *c,UserlistOps *ops,gpointer data){ UserlistData *u=get_uld(c); ops->c=c; ops->data=data; u->hooks=g_list_prepend(u->hooks,ops); if(ops->refresh!=NULL){ int *s=get_socks(u); ops->refresh(ops->c,u->numusers,s,ops->data); if(s!=NULL) free(s); } } void userlist_rm_ops(Connection *c,UserlistOps *ops){ UserlistData *u=get_uld(c); u->hooks=g_list_remove(u->hooks,ops); free(ops); } static void userlist_fill(UserlistData *u){ int *sockets=NULL; GList *l; UserlistOps *ops; sockets=get_socks(u); forallhooks(u,l){ ops=l->data; if(ops->refresh!=NULL) ops->refresh(ops->c,u->numusers,sockets,ops->data); } if(sockets!=NULL) free(sockets); } static void userlist_process_reply(Transaction *t,Message *m,UserlistData *u){ int count,i; HLObject **o; if(message_is_error(m)) return; o=message_extract_objects(m,HLO_USERLISTENTRY,&count); if(count>0 && o!=NULL){ userlist_clear(u); u->users=(UserlistEntry **)malloc(sizeof(UserlistEntry *)*count); for(i=0;iusers[i]=o[i]->data.userlistentry; o[i]->data.userlistentry=NULL; } u->numusers=count; } objects_destroy(o); u->transaction=NULL; userlist_fill(u); } static void userlist_fetch(UserlistData *u){ Transaction *t; if(u->transaction!=NULL) return; t=transaction_new(u->c,HLCT_GETUSERLIST); transaction_add_task(t,_("Receiving userlist..."),HL_STOCK_PIXMAP_USERS,0.5); transaction_set_error_check(t,strdup(_("Could not list users:"))); gtk_signal_connect(GTK_OBJECT(t),"response-received",GTK_SIGNAL_FUNC(userlist_process_reply),u); u->transaction=t; transaction_start(t); } void userlist_refresh(Connection *c){ UserlistData *u=get_uld(c); userlist_fetch(u); } static UserlistData *userlist_init(Connection *c){ UserlistData *u=(UserlistData *)calloc(sizeof(UserlistData),1); u->c=c; u->numusers=0; u->users=NULL; u->transaction=NULL; connection_set_data(c,USERLIST,u); gtk_signal_connect(GTK_OBJECT(c),"destroy",GTK_SIGNAL_FUNC(userlist_destroy),u); return u; } static UserlistData *get_uld(Connection *c){ UserlistData *u=(UserlistData *)connection_get_data(c,USERLIST); if(u==NULL) u=userlist_init(c); return u; } void check_userlist(Connection *c){ UserlistData *u=get_uld(c); if(u->users==NULL) userlist_fetch(u); } UserlistEntry *get_user_by_socket(Connection *c,int sock){ UserlistData *u=get_uld(c); int i; for(i=0;inumusers;i++) if(u->users[i]->u.socket==sock) return u->users[i]; return NULL; } void handle_user_change(Connection *c,Message *m,gpointer data){ UserlistData *u=(UserlistData *)connection_get_data(c,USERLIST); HLObject *socket,*nick,*status,*icon; UserlistEntry *ul; gboolean is_new=FALSE; int i,is_ignored=0; GList *l; UserlistOps *ops; if(u!=NULL && u->users!=NULL){ socket=message_find_object(m,HLO_SOCKET); icon=message_find_object(m,HLO_ICON); status=message_find_object(m,HLO_STATUS); nick=message_find_object(m,HLO_NICK); ul=NULL; for(i=0;inumusers;i++) if(u->users[i]->u.socket==socket->data.number){ ul=u->users[i]; break; } if(ul==NULL){ play_sound(HL_SOUND_LOGIN); u->users=(UserlistEntry **)realloc(u->users,sizeof(UserlistData *)*(u->numusers+1)); ul=(UserlistEntry *)calloc(sizeof(UserlistEntry),1); u->users[u->numusers]=ul; u->numusers++; ul->name=NULL; is_new=TRUE; } else { is_ignored=ul->u.status&ULE_FIDELIO_IGNORED; } if(nick!=NULL){ if(ul->name!=NULL) free(ul->name); ul->name=strdup(nick->data.string); } else if(ul->name==NULL) ul->name=strdup(_("Anonymous Coward")); if(socket!=NULL) ul->u.socket=socket->data.number; if(status!=NULL) ul->u.status=status->data.number; else ul->u.status=0; ul->u.status|=is_ignored; if(icon!=NULL) ul->u.icon=icon->data.number; else ul->u.icon=0; forallhooks(u,l){ ops=(UserlistOps *)l->data; if(ops->add_user!=NULL && is_new==TRUE) ops->add_user(ops->c,socket->data.number,ops->data); else if(ops->update_user!=NULL && is_new==FALSE) ops->update_user(ops->c,socket->data.number,ops->data); } } message_unref(m); } void handle_user_leave(Connection *c,Message *m,gpointer data){ UserlistData *u=(UserlistData *)connection_get_data(c,USERLIST); HLObject *o; int i; UserlistEntry *ul; GList *l; UserlistOps *ops; o=message_find_object(m,HLO_SOCKET); if(u!=NULL && o!=NULL){ forallhooks(u,l){ ops=(UserlistOps *)l->data; if(ops->rm_user!=NULL) ops->rm_user(ops->c,o->data.number,ops->data); } if(u->users!=NULL) for(i=0;inumusers;i++) if(u->users[i]->u.socket==o->data.number){ ul=u->users[i]; u->numusers--; for(;inumusers;i++) u->users[i]=u->users[i+1]; if(ul->name!=NULL) free(ul->name); free(ul); break; } } message_unref(m); play_sound(HL_SOUND_LOGOUT); } void userlist_set_ignored(Connection *c, int socket, gboolean ignored){ UserlistData *u=(UserlistData *)connection_get_data(c,USERLIST); UserlistEntry *ule=get_user_by_socket(c,socket); UserlistOps *ops; gboolean is_ignored; GList *l; if(ule==NULL) return; is_ignored=(ule->u.status&ULE_FIDELIO_IGNORED)?TRUE:FALSE; if(is_ignored==ignored) return; ule->u.status&=~ULE_FIDELIO_IGNORED; if(ignored) ule->u.status|=ULE_FIDELIO_IGNORED; forallhooks(u,l){ ops=(UserlistOps *)l->data; if(ops->update_user!=NULL) ops->update_user(ops->c,socket,ops->data); } } gboolean userlist_get_ignored(Connection *c,int socket){ UserlistEntry *ule=get_user_by_socket(c,socket); if(ule==NULL) return FALSE; return (ule->u.status&ULE_FIDELIO_IGNORED)?TRUE:FALSE; } gboolean userlist_get_ignored_by_string(Connection *c,char *string){ UserlistData *u=(UserlistData *)connection_get_data(c,USERLIST); int i; int max_match=0,len; if(strncmp(string," *** ",5)==0){ for(i=0;inumusers;i++){ if(u->users[i]->u.status&ULE_FIDELIO_IGNORED){ len=strlen(u->users[i]->name); if(len>max_match && strncmp(u->users[i]->name,string,len)==0) max_match=len; } } } if(max_match>0) return TRUE; for(i=0;inumusers;i++){ if(u->users[i]->u.status&ULE_FIDELIO_IGNORED){ len=strlen(u->users[i]->name); if(len>12) len=12; if(len>=max_match && strncmp(u->users[i]->name,string+12-len,len)==0) max_match=len; } } if(max_match>0) return TRUE; return FALSE; }