User *user_get_by_jid(const char *jid){ User *u; char *njid; njid=jid_normalized(jid,0); if (njid==NULL) return NULL; u=(User *)g_hash_table_lookup(users_jid,(gpointer)njid); g_free(njid); if (u==NULL) u=user_load(jid); return u; }
int presence_subscribe(struct stream_s *stream,const char *from,const char *to){ User *u; Session *s; char *bare; uin_t uin; Contact *c; u=user_get_by_jid(from); if (jid_is_me(to)){ debug(L_("Presence subscribe request sent to me")); if (!u) { presence_send_unsubscribed(stream,to,from); return 0; } presence_send_subscribed(stream,to,from); if (u->subscribe==SUB_UNDEFINED || u->subscribe==SUB_NONE) u->subscribe=SUB_TO; else if (u->subscribe==SUB_FROM) u->subscribe=SUB_BOTH; if (u->subscribe!=SUB_FROM && u->subscribe!=SUB_BOTH){ presence_send_subscribe(stream,to,from); } user_save(u); return 0; } if (!u){ g_warning(N_("Presence subscription from unknown user (%s)"),from); presence_send_unsubscribed(stream,to,from); return -1; } if (!jid_has_uin(to) || !jid_is_my(to)){ g_warning(N_("Bad 'to': %s"),to); return -1; } s=session_get_by_jid(from,stream,0); debug(L_("Subscribing %s to %s..."),from,to); uin=jid_get_uin(to); c=user_get_contact(u,uin,TRUE); if (!c) { presence_send_error(stream,to,from,500,_("Subscription failed")); return -1; } if (c->subscribe==SUB_UNDEFINED || c->subscribe==SUB_NONE) c->subscribe=SUB_TO; else if (c->subscribe==SUB_FROM) c->subscribe=SUB_BOTH; user_save(u); if (s) session_update_contact(s,c); debug(L_("Subscribed.")); presence_send_subscribed(stream,to,from); bare=jid_normalized(from,FALSE); if (c->subscribe!=SUB_FROM && c->subscribe!=SUB_BOTH) { presence_send_subscribe(stream,to,bare); } g_free(bare); return 0; }
User *user_create(const char *jid,uin_t uin,const char * password){ User *u; char *p,*njid; g_message(L_("Creating user '%s'"),jid); njid=jid_normalized(jid,0); if (njid==NULL){ g_warning(L_("Bad JID: '%s'"),jid); return NULL; } u=(User *)g_hash_table_lookup(users_jid,(gpointer)njid); if (u){ g_warning(L_("User '%s' already exists"),jid); g_free(njid); return NULL; } if (uin<1){ g_warning(L_("Bad UIN")); g_free(njid); return NULL; } if (!password){ g_warning(L_("Password not given")); g_free(njid); return NULL; } if (!jid){ g_warning(L_("JID not given")); g_free(njid); return NULL; } u=g_new0(User,1); u->uin=uin; u->jid=g_strdup(jid); p=strchr(u->jid,'/'); if (p) *p=0; u->password=g_strdup(password); u->confirmed=0; u->invisible=0; u->friends_only=1; g_hash_table_insert(users_jid,(gpointer)njid,(gpointer)u); u->refcount=0; u->deleted=FALSE; return u; }
int session_remove(Session *s){ gpointer key,value; char *njid; if (s==NULL) return 1; g_assert(sessions_jid!=NULL); njid=jid_normalized(s->jid,0); g_assert(njid!=NULL); if (g_hash_table_lookup_extended(sessions_jid,(gpointer)njid,&key,&value)){ g_hash_table_remove(sessions_jid,(gpointer)njid); g_free(key); } g_free(njid); session_destroy(s); return 0; }
int user_free(User *u){ gpointer key,value; char *njid; g_assert(u->refcount==0); g_assert(users_jid!=NULL); njid=jid_normalized(u->jid,0); g_assert(njid!=NULL); if (g_hash_table_lookup_extended(users_jid,(gpointer)njid,&key,&value)){ g_assert(u==value); g_hash_table_remove(users_jid,(gpointer)njid); g_free(key); } else debug(L_("user_remove: user '%s' not found in hash table"),njid); g_free(njid); return user_destroy(u); }
Session *session_get_by_jid(const char *jid,Stream *stream,int delay_login){ Session *s; User *u; char *njid; GList *it; g_assert(sessions_jid!=NULL); debug(L_("Looking up session for '%s'"),jid); njid=jid_normalized(jid,0); if (njid==NULL){ g_message(L_("Bad JID: '%s'"),jid); return NULL; } debug(L_("Using '%s' as key"),njid); s=(Session *)g_hash_table_lookup(sessions_jid,(gpointer)njid); g_free(njid); if (s) return s; debug(L_("Session not found")); if (!stream) return NULL; u=user_get_by_jid(jid); if (!u) return NULL; debug(L_("User loaded, processing his subscriptions.")); for(it=g_list_first(u->contacts);it;it=g_list_next(it)){ Contact *c; char *c_jid; c=(Contact *)it->data; if (c->subscribe == SUB_UNDEFINED) { c_jid=jid_build(c->uin); presence_send_subscribe(stream,c_jid,u->jid); g_free(c_jid); } else if (c->subscribe == SUB_FROM || c->subscribe == SUB_BOTH){ c_jid=jid_build(c->uin); presence_send_probe(stream,c_jid,u->jid); g_free(c_jid); } } debug(L_("Creating new session")); return session_create(u,jid,NULL,NULL,stream,delay_login); }
Session * session_create(User *user,const char *jid,const char *req_id, const xmlnode query,struct stream_s *stream,int delay_login){ Session *s; char *njid; g_message(L_("Creating session for '%s'"),jid); njid=jid_normalized(jid,0); if (njid==NULL){ g_message(L_("Bad JID: '%s'"),jid); return NULL; } g_assert(user!=NULL); if (user->deleted){ g_message(L_("User deleted: '%s'"),user->jid); return NULL; } s=g_new0(Session,1); s->user=user; user_ref(user); s->gg_status=-1; s->jid=g_strdup(jid); if (req_id) s->req_id=g_strdup(req_id); s->query=xmlnode_dup(query); s->current_server=g_list_first(gg_servers); s->g_pollfd.fd=-1; if (!delay_login && session_try_login(s)){ session_destroy(s); return NULL; } s->s=stream; g_assert(sessions_jid!=NULL); g_hash_table_insert(sessions_jid,(gpointer)njid,(gpointer)s); return s; }
void session_print(Session *s,int indent){ char *space,*space1; GList *it; Resource *r,*cr; char *njid; space=g_strnfill(indent*2,' '); space1=g_strnfill((indent+1)*2,' '); njid=jid_normalized(s->jid,0); g_message(L_("%sSession: %p"),space,s); g_message("%sJID: %s",space,s->jid); g_message(L_("%sUser:"******"%sResources:"),space); cr=session_get_cur_resource(s); for(it=g_list_first(s->resources);it;it=g_list_next(it)){ r=(Resource *)it->data; g_message(L_("%sResource: %p%s"),space1,r,(r==cr)?N_(" (current)"):""); if (njid && r->name) g_message("%sJID: %s/%s",space1,njid,r->name); else g_message("%sJID: %s",space1,s->jid); g_message(L_("%sPriority: %i"),space1,r->priority); g_message(L_("%sAvailable: %i"),space1,r->available); if (r->show) g_message(L_("%sShow: %s"),space1,r->show); if (r->status) g_message(L_("%sStatus: %s"),space1,r->status); } g_message(L_("%sGG session: %p"),space,s->ggs); g_message(L_("%sGSource: %p"),space,s->g_source); g_message(L_("%sStream: %p"),space,s->s); g_message(L_("%sConnected: %i"),space,s->connected); g_message(L_("%sRequest id: %s"),space,s->req_id?s->req_id:"(null)"); g_message(L_("%sRequest query: %s"),space,s->query?xmlnode2str(s->query):"(null)"); g_message(L_("%sWaiting for ping: %i"),space,(int)s->waiting_for_pong); g_free(njid); g_free(space1); g_free(space); }
int user_delete(User *u){ int r; char *njid; g_assert(u!=NULL); njid=jid_normalized(u->jid,0); g_assert(njid!=NULL); r=unlink(njid); if (r && errno!=ENOENT){ g_warning(L_("Couldn't unlink '%s': %s"),njid,g_strerror(errno)); r=-1; } else r=0; g_free(njid); u->deleted=TRUE; users_gc(); return r; }
User *user_load(const char *jid){ char *fn,*njid; xmlnode xml,tag,t; char *uin,*ujid,*name,*password,*email,*locale; char *status; int last_sys_msg=0,invisible=0,friends_only=0,ignore_unknown=0; unsigned int file_format_version=0; SubscriptionType subscribe; User *u; GList *contacts; char *p; char *data; uin=ujid=name=password=email=NULL; debug(L_("Loading user '%s'"),jid); fn=jid_normalized(jid,0); if (fn==NULL){ g_warning(L_("Bad JID: %s"),jid); return NULL; } errno=0; xml=xmlnode_file(fn); if (xml==NULL){ debug(L_("Couldn't read or parse '%s': %s"),fn,errno?g_strerror(errno):N_("XML parse error")); g_free(fn); return NULL; } g_free(fn); tag=xmlnode_get_tag(xml,"version"); if (tag!=NULL) { p=xmlnode_get_attrib(tag,"file_format"); if (p!=NULL) file_format_version=(unsigned int)strtol(p,NULL,16); } tag=xmlnode_get_tag(xml,"jid"); if (tag!=NULL) { ujid=xmlnode_get_data(tag); subscribe=get_subscribe(tag, file_format_version); } if (ujid==NULL){ g_warning(L_("Couldn't find JID in %s's file"),jid); return NULL; } tag=xmlnode_get_tag(xml,"uin"); if (tag!=NULL) uin=xmlnode_get_data(tag); if (uin==NULL){ g_warning(L_("Couldn't find UIN in %s's file"),jid); return NULL; } tag=xmlnode_get_tag(xml,"password"); if (tag!=NULL) password=xmlnode_get_data(tag); if (password==NULL){ g_warning(L_("Couldn't find password in %s's file"),jid); return NULL; } tag=xmlnode_get_tag(xml,"email"); if (tag!=NULL) email=xmlnode_get_data(tag); tag=xmlnode_get_tag(xml,"name"); if (tag!=NULL) name=xmlnode_get_data(tag); tag=xmlnode_get_tag(xml,"last_sys_msg"); if (tag!=NULL){ data=xmlnode_get_data(tag); if (data!=NULL) last_sys_msg=atoi(data); } tag=xmlnode_get_tag(xml,"friendsonly"); if (tag!=NULL) friends_only=1; tag=xmlnode_get_tag(xml,"invisible"); if (tag!=NULL) invisible=1; tag=xmlnode_get_tag(xml,"ignore_unknown"); if (tag!=NULL) ignore_unknown=1; tag=xmlnode_get_tag(xml,"locale"); if (tag!=NULL) locale=xmlnode_get_data(tag); else locale=NULL; tag=xmlnode_get_tag(xml,"status"); if (tag!=NULL) { status=xmlnode_get_data(tag); if (status==NULL) status=""; } else status=NULL; tag=xmlnode_get_tag(xml,"userlist"); contacts=NULL; if (tag!=NULL){ Contact *c; for(t=xmlnode_get_firstchild(tag);t;t=xmlnode_get_nextsibling(t)){ char *node_name; node_name=xmlnode_get_name(t); if (!node_name) continue; if (!strcmp(node_name,"uin")){ char *d; int uin; d=xmlnode_get_data(t); if (d==NULL) continue; uin=atoi(d); if (uin<=0) continue; c=g_new0(Contact,1); c->status=-1; c->uin=uin; contacts=g_list_append(contacts,c); continue; } if (!strcmp(node_name,"contact")){ char *d; int uin; d=xmlnode_get_attrib(t,"uin"); if (d==NULL) continue; uin=atoi(d); if (uin<=0) continue; c=g_new0(Contact,1); c->status=-1; c->uin=uin; d=xmlnode_get_attrib(t,"ignored"); if (d!=NULL && d[0]!='\000') c->ignored=1; else c->ignored=0; d=xmlnode_get_attrib(t,"blocked"); if (d!=NULL && d[0]!='\000') c->blocked=1; else c->blocked=0; c->subscribe=get_subscribe(t, file_format_version); contacts=g_list_append(contacts,c); } } } u=g_new0(User,1); u->uin=atoi(uin); u->jid=g_strdup(jid); p=strchr(u->jid,'/'); if (p) *p=0; u->password=g_strdup(password); u->last_sys_msg=last_sys_msg; u->friends_only=friends_only; u->invisible=invisible; u->ignore_unknown=ignore_unknown; u->locale=g_strdup(locale); u->status=g_strdup(from_utf8(status)); u->contacts=contacts; xmlnode_free(xml); g_assert(users_jid!=NULL); njid=jid_normalized(u->jid,0); g_assert(njid!=NULL); g_hash_table_insert(users_jid,(gpointer)njid,(gpointer)u); u->confirmed=1; u->subscribe=subscribe; return u; }
int user_save(User *u){ FILE *f; char *fn; char *str; char *njid; int r; xmlnode xml,tag,ctag,userlist; g_assert(u!=NULL); str=strchr(u->jid,'/'); g_assert(str==NULL); if (!u->confirmed){ g_message(L_("Not saving user '%s' - account not confirmed."),u->jid); return -1; } g_debug(L_("Saving user '%s'"),u->jid); njid=jid_normalized(u->jid,0); g_assert(njid!=NULL); fn=g_strdup_printf("%s.new",njid); f=fopen(fn,"w"); if (!f){ g_warning(L_("Couldn't open '%s': %s"),fn,g_strerror(errno)); g_free(fn); g_free(njid); return -1; } xml=xmlnode_new_tag("user"); tag=xmlnode_insert_tag(xml,"version"); str=g_strdup_printf("%08x",USER_FILE_FORMAT_VERSION); xmlnode_put_attrib(tag,"file_format",str); g_free(str); tag=xmlnode_insert_tag(xml,"jid"); xmlnode_insert_cdata(tag,u->jid,-1); set_subscribe(tag, u->subscribe); tag=xmlnode_insert_tag(xml,"uin"); str=g_strdup_printf("%lu",(unsigned long)u->uin); xmlnode_insert_cdata(tag,str,-1); g_free(str); tag=xmlnode_insert_tag(xml,"password"); xmlnode_insert_cdata(tag,u->password,-1); if (u->last_sys_msg>0){ tag=xmlnode_insert_tag(xml,"last_sys_msg"); str=g_strdup_printf("%i",u->last_sys_msg); xmlnode_insert_cdata(tag,str,-1); g_free(str); } if (u->invisible) tag=xmlnode_insert_tag(xml,"invisible"); if (u->friends_only) tag=xmlnode_insert_tag(xml,"friendsonly"); if (u->ignore_unknown) tag=xmlnode_insert_tag(xml,"ignore_unknown"); if (u->locale){ tag=xmlnode_insert_tag(xml,"locale"); xmlnode_insert_cdata(tag,u->locale,-1); } if (u->status){ tag=xmlnode_insert_tag(xml,"status"); xmlnode_insert_cdata(tag,to_utf8(u->status),-1); } if (u->contacts){ GList *it; Contact *c; userlist=xmlnode_insert_tag(xml,"userlist"); for(it=g_list_first(u->contacts);it;it=it->next){ c=(Contact *)it->data; ctag=xmlnode_insert_tag(userlist,"contact"); str=g_strdup_printf("%lu",(unsigned long)c->uin); xmlnode_put_attrib(ctag,"uin",str); if (c->ignored) xmlnode_put_attrib(ctag,"ignored","ignored"); if (c->blocked) xmlnode_put_attrib(ctag,"blocked","blocked"); set_subscribe(ctag, c->subscribe); g_free(str); } } str=xmlnode2str(xml); r=fputs(str,f); if (r<0){ g_warning(L_("Couldn't save '%s': %s"),u->jid,g_strerror(errno)); fclose(f); unlink(fn); xmlnode_free(xml); g_free(fn); g_free(njid); return -1; } fclose(f); r=unlink(njid); if (r && errno!=ENOENT){ g_warning(L_("Couldn't unlink '%s': %s"),njid,g_strerror(errno)); xmlnode_free(xml); g_free(fn); g_free(njid); return -1; } r=rename(fn,njid); if (r){ g_warning(L_("Couldn't rename '%s' to '%s': %s"),fn,u->jid,g_strerror(errno)); xmlnode_free(xml); g_free(fn); g_free(njid); return -1; } xmlnode_free(xml); g_free(fn); g_free(njid); return 0; }