int rsdb_init(rsdb_error_cb * ecb) { const char *bandb_dbpath_env; char dbpath[PATH_MAX]; char errbuf[128]; error_cb = ecb; /* try a path from the environment first, useful for basedir overrides */ bandb_dbpath_env = getenv("BANDB_DBPATH"); if(bandb_dbpath_env != NULL) rb_strlcpy(dbpath, bandb_dbpath_env, sizeof(dbpath)); else rb_strlcpy(dbpath, DBPATH, sizeof(dbpath)); if(sqlite3_open(dbpath, &rb_bandb) != SQLITE_OK) { snprintf(errbuf, sizeof(errbuf), "Unable to open sqlite database: %s", sqlite3_errmsg(rb_bandb)); mlog(errbuf); return -1; } if(access(dbpath, W_OK)) { snprintf(errbuf, sizeof(errbuf), "Unable to open sqlite database for write: %s", strerror(errno)); mlog(errbuf); return -1; } return 0; }
static int do_local_user(struct Client *client_p, struct Client *source_p, const char *username, const char *realname) { s_assert(NULL != source_p); s_assert(source_p->username != username); make_user(source_p); lookup_blacklists(source_p); source_p->flags |= FLAGS_SENTUSER; rb_strlcpy(source_p->info, realname, sizeof(source_p->info)); if(!IsGotId(source_p)) rb_strlcpy(source_p->username, username, sizeof(source_p->username)); if(source_p->name[0]) { /* NICK already received, now I have USER... */ return register_local_user(client_p, source_p); } return 0; }
static int do_local_user(struct Client *client_p, struct Client *source_p, const char *username, const char *realname) { s_assert(NULL != source_p); s_assert(source_p->username != username); make_user(source_p); if (!(source_p->flags & FLAGS_SENTUSER)) { lookup_blacklists(source_p); source_p->flags |= FLAGS_SENTUSER; } rb_strlcpy(source_p->info, realname, sizeof(source_p->info)); if(!IsGotId(source_p)) { /* This is in this location for a reason..If there is no identd * and ping cookies are enabled..we need to have a copy of this */ rb_strlcpy(source_p->username, username, sizeof(source_p->username)); } if(source_p->name[0]) { /* NICK already received, now I have USER... */ return register_local_user(client_p, source_p, username); } return 0; }
/* * match_ips() * * Input - cidr ip mask, address */ int match_ips(const char *s1, const char *s2) { struct rb_sockaddr_storage ipaddr, maskaddr; char mask[IRCD_BUFSIZE]; char address[HOSTLEN + 1]; char *len; void *ipptr, *maskptr; int cidrlen, aftype; rb_strlcpy(mask, s1, sizeof(mask)); rb_strlcpy(address, s2, sizeof(address)); len = strrchr(mask, '/'); if(len == NULL) return 0; *len++ = '\0'; cidrlen = atoi(len); if(cidrlen <= 0) return 0; #ifdef RB_IPV6 if(strchr(mask, ':') && strchr(address, ':')) { if(cidrlen > 128) return 0; aftype = AF_INET6; ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr; maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr; } else #endif if(!strchr(mask, ':') && !strchr(address, ':')) { if(cidrlen > 32) return 0; aftype = AF_INET; ipptr = &((struct sockaddr_in *)&ipaddr)->sin_addr; maskptr = &((struct sockaddr_in *)&maskaddr)->sin_addr; } else return 0; if(rb_inet_pton(aftype, address, ipptr) <= 0) return 0; if(rb_inet_pton(aftype, mask, maskptr) <= 0) return 0; if(comp_with_mask(ipptr, maskptr, cidrlen)) return 1; else return 0; }
/* ** m_part ** parv[1] = channel ** parv[2] = reason */ static int m_part(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { char *p, *name; char reason[REASONLEN + 1]; char *s = LOCAL_COPY(parv[1]); reason[0] = '\0'; if(parc > 2) rb_strlcpy(reason, parv[2], sizeof(reason)); name = rb_strtok_r(s, ",", &p); /* Finish the flood grace period... */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); while(name) { part_one_client(client_p, source_p, name, reason); name = rb_strtok_r(NULL, ",", &p); } return 0; }
static void h_can_send(void *vdata) { char *text, *filtered; hook_data_channel_approval *data = (hook_data_channel_approval *) vdata; if(data->chptr->mode.mode & mymode && ((strchr(ConfigChannel.exemptchanops, 'c') == NULL) || !is_any_op(data->msptr))) { /* colour == 3 */ text = ((char **)data->data)[3]; /* Filtered == 0 */ filtered = ((char **)data->data)[0]; if (EmptyString(text)) { if(data->cmd == COMMAND_PRIVMSG) sendto_one(data->client, form_str(ERR_NOTEXTTOSEND), me.name, data->client->name); data->approved = CAN_SEND_NO_NONOTIFY; return; } /* Copy coloured into filtered */ rb_strlcpy(filtered, text, BUFSIZE); } return; }
static int mr_pong(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(parc == 2 && !EmptyString(parv[1])) { if(ConfigFileEntry.ping_cookie && source_p->flags & FLAGS_SENTUSER && source_p->name[0]) { unsigned long incoming_ping = strtoul(parv[1], NULL, 16); if(incoming_ping) { if(source_p->localClient->random_ping == incoming_ping) { char buf[USERLEN + 1]; rb_strlcpy(buf, source_p->username, sizeof(buf)); source_p->flags |= FLAGS_PING_COOKIE; register_local_user(client_p, source_p, buf); } else { sendto_one(source_p, form_str(ERR_WRONGPONG), me.name, source_p->name, source_p->localClient->random_ping); return 0; } } } } else sendto_one(source_p, form_str(ERR_NOORIGIN), me.name, source_p->name); source_p->flags &= ~FLAGS_PINGSENT; return 0; }
/* ** m_away ** parv[1] = away message */ static int m_away(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(MyClient(source_p) && source_p->localClient->next_away && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsClient(source_p)) return 0; if(parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if(source_p->user->away != NULL) { /* we now send this only if they were away before --is */ sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY", use_id(source_p)); free_away(source_p); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, NOCAPS, ":%s!%s@%s AWAY", source_p->name, source_p->username, source_p->host); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_UNAWAY, form_str(RPL_UNAWAY)); return 0; } /* Rate limit this because it is sent to common channels. */ if (MyClient(source_p)) { if(!IsOper(source_p) && source_p->localClient->next_away > rb_current_time()) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "AWAY"); return 0; } if(source_p->localClient->next_away < rb_current_time() - ConfigFileEntry.away_interval) source_p->localClient->next_away = rb_current_time(); else source_p->localClient->next_away = rb_current_time() + ConfigFileEntry.away_interval; } if(source_p->user->away == NULL) allocate_away(source_p); if(strncmp(source_p->user->away, parv[1], AWAYLEN - 1)) { rb_strlcpy(source_p->user->away, parv[1], AWAYLEN); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY :%s", use_id(source_p), source_p->user->away); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_NOWAWAY, form_str(RPL_NOWAWAY)); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, NOCAPS, ":%s!%s@%s AWAY :%s", source_p->name, source_p->username, source_p->host, source_p->user->away); return 0; }
char * rb_strerror(int error) { static char buf[128]; rb_strlcpy(buf, _rb_strerror(error), sizeof(buf)); return buf; }
static struct scache_entry * find_or_add(const char *name) { int hash_index; struct scache_entry *ptr; ptr = scache_hash[hash_index = sc_hash(name)]; for (; ptr; ptr = ptr->next) { if(!irccmp(ptr->name, name)) return ptr; } ptr = (struct scache_entry *) rb_malloc(sizeof(struct scache_entry)); s_assert(0 != ptr); rb_strlcpy(ptr->name, name, sizeof(ptr->name)); ptr->info[0] = '\0'; ptr->flags = 0; ptr->known_since = rb_current_time(); ptr->last_connect = 0; ptr->last_split = 0; ptr->next = scache_hash[hash_index]; scache_hash[hash_index] = ptr; return ptr; }
/* ** m_quit ** parv[1] = comment */ static int m_quit(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { char comment[REASONLEN + 1]; /* Better safe than sorry */ char reason[REASONLEN + 1]; source_p->flags |= FLAGS_NORMALEX; strip_colour((parc > 1 && parv[1]) ? parv[1] : client_p->name, comment, REASONLEN); if(ConfigFileEntry.client_exit && comment[0]) { rb_snprintf(reason, sizeof(reason), "Quit: %s", comment); rb_strlcpy(comment, reason, REASONLEN + 1); } if(!IsOper(source_p) && !EmptyString(ConfigFileEntry.static_quit)) { exit_client(client_p, source_p, source_p, ConfigFileEntry.static_quit); return 0; } if(!IsOper(source_p) && (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) > rb_current_time()) { exit_client(client_p, source_p, source_p, "Client Quit"); return 0; } exit_client(client_p, source_p, source_p, comment); return 0; }
/* parse_resvconf() * * inputs - NONE * output - -1 if failure 0 if success * side effects - fills in irc_nsaddr_list */ static int parse_resvconf(void) { char *p; char *opt; char *arg; char input[DNS_MAXLINE]; FILE *file; /* XXX "/etc/resolv.conf" should be from a define in setup.h perhaps * for cygwin support etc. this hardcodes it to unix for now -db */ if ((file = fopen("/etc/resolv.conf", "r")) == NULL) return -1; while (fgets(input, sizeof(input), file) != NULL) { /* blow away any newline */ if ((p = strpbrk(input, "\r\n")) != NULL) *p = '\0'; p = input; /* skip until something thats not a space is seen */ while (IsSpace(*p)) p++; /* if at this point, have a '\0' then continue */ if (*p == '\0') continue; /* Ignore comment lines immediately */ if (*p == '#' || *p == ';') continue; /* skip until a space is found */ opt = p; while (!IsSpace(*p) && *p != '\0') p++; if (*p == '\0') continue; /* no arguments?.. ignore this line */ /* blow away the space character */ *p++ = '\0'; /* skip these spaces that are before the argument */ while (IsSpace(*p)) p++; /* Now arg should be right where p is pointing */ arg = p; if ((p = strpbrk(arg, " \t")) != NULL) *p = '\0'; /* take the first word */ if (irccmp(opt, "domain") == 0) rb_strlcpy(irc_domain, arg, sizeof(irc_domain)); else if (irccmp(opt, "nameserver") == 0) add_nameserver(arg); } fclose(file); return 0; }
static int me_mechlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { rb_strlcpy(mechlist_buf, parv[1], sizeof mechlist_buf); return 0; }
/* ** m_away ** parv[0] = sender prefix ** parv[1] = away message */ static int m_away(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsClient(source_p)) return 0; if(parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if(source_p->user->away != NULL) { /* we now send this only if they were away before --is */ sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY", use_id(source_p)); sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s AWAY", source_p->name); free_away(source_p); } if(MyConnect(source_p)) sendto_one(source_p, form_str(RPL_UNAWAY), me.name, source_p->name); return 0; } if(source_p->user->away == NULL) { allocate_away(source_p); rb_strlcpy(source_p->user->away, parv[1], AWAYLEN); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY :%s", use_id(source_p), source_p->user->away); sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s AWAY :%s", source_p->name, source_p->user->away); } else { rb_strlcpy(source_p->user->away, parv[1], AWAYLEN); } if(MyConnect(source_p)) sendto_one(source_p, form_str(RPL_NOWAWAY), me.name, source_p->name); return 0; }
static void substitute_reject_reason(void) { rb_dlink_list subs = {0}; substitution_append_var(&subs, "network-name", ServerInfo.network_name?: "${network-name}"); substitution_append_var(&subs, "admin-email", AdminInfo.email?: "${admin-email}"); const char *const substituted = substitution_parse(reject_reason, &subs); rb_strlcpy(reject_reason, substituted, sizeof(reject_reason)); substitution_free(&subs); }
/* * part_one_client * * inputs - pointer to server * - pointer to source client to remove * - char pointer of name of channel to remove from * output - none * side effects - remove ONE client given the channel name */ static void part_one_client(struct Client *client_p, struct Client *source_p, char *name, char *reason) { struct Channel *chptr; struct membership *msptr; char reason2[BUFSIZE]; if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return; } msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return; } if(MyConnect(source_p) && !IsOper(source_p) && !IsExemptSpambot(source_p)) check_spambot_warning(source_p, NULL); /* * Remove user from the old channel (if any) * only allow /part reasons in -m chans */ if(reason[0] && (is_chanop(msptr) || !MyConnect(source_p) || ((can_send(chptr, source_p, msptr) > 0 && (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) < rb_current_time())))) { if(chptr->mode.mode & MODE_NOCOLOR) { rb_strlcpy(reason2, reason, BUFSIZE); strip_colour(reason2); reason = reason2; } sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s :%s", use_id(source_p), chptr->chname, reason); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, reason); } else { sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s", use_id(source_p), chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s", source_p->name, source_p->username, source_p->host, chptr->chname); } remove_user_from_channel(msptr); }
/* clicap_find() * Used iteratively over a buffer, extracts individual cap tokens. * * Inputs: buffer to start iterating over (NULL to iterate over existing buf) * int pointer to whether the cap token is negated * int pointer to whether we finish with success * Ouputs: Cap entry if found, NULL otherwise. */ static struct clicap * clicap_find(const char *data, int *negate, int *finished) { static char buf[BUFSIZE]; static char *p; struct clicap *cap; char *s; *negate = 0; if(data) { rb_strlcpy(buf, data, sizeof(buf)); p = buf; } if(*finished) return NULL; /* skip any whitespace */ while(*p && IsSpace(*p)) p++; if(EmptyString(p)) { *finished = 1; return NULL; } if(*p == '-') { *negate = 1; p++; /* someone sent a '-' without a parameter.. */ if(*p == '\0') return NULL; } if((s = strchr(p, ' '))) *s++ = '\0'; if((cap = bsearch(p, clicap_list, CLICAP_LIST_LEN, sizeof(struct clicap), (bqcmp) clicap_compare))) { if(s) p = s; else *finished = 1; } return cap; }
char *reconstruct_parv(int parc, const char *parv[]) { static char tmpbuf[BUFSIZE]; int i; rb_strlcpy(tmpbuf, parv[0], BUFSIZE); for (i = 1; i < parc; i++) { rb_strlcat(tmpbuf, " ", BUFSIZE); rb_strlcat(tmpbuf, parv[i], BUFSIZE); } return tmpbuf; }
static void remove_quote_part(hook_data_privmsg_channel *data) { if (data->approved || EmptyString(data->text) || data->msgtype != MESSAGE_TYPE_PART) return; rb_strlcpy(part_buf, "\"", sizeof(part_buf) - 1); rb_strlcat(part_buf, data->text, sizeof(part_buf) - 1); rb_strlcat(part_buf, "\"", sizeof(part_buf)); data->text = part_buf; }
static int me_sasl(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p, *agent_p; /* Let propagate if not addressed to us, or if broadcast. * Only SASL agents can answer global requests. */ if(strncmp(parv[2], me.id, 3)) return 0; if((target_p = find_id(parv[2])) == NULL) return 0; if(target_p->preClient == NULL) return 0; if((agent_p = find_id(parv[1])) == NULL) return 0; if(source_p != agent_p->servptr) /* WTF?! */ return 0; /* We only accept messages from SASL agents; these must have umode +S * (so the server must be listed in a service{} block). */ if(!IsService(agent_p)) return 0; /* Reject if someone has already answered. */ if(*target_p->preClient->sasl_agent && strncmp(parv[1], target_p->preClient->sasl_agent, IDLEN)) return 0; else if(!*target_p->preClient->sasl_agent) rb_strlcpy(target_p->preClient->sasl_agent, parv[1], IDLEN); if(*parv[3] == 'C') sendto_one(target_p, "AUTHENTICATE %s", parv[4]); else if(*parv[3] == 'D') { if(*parv[4] == 'F') sendto_one(target_p, form_str(ERR_SASLFAIL), me.name, EmptyString(target_p->name) ? "*" : target_p->name); else if(*parv[4] == 'S') { sendto_one(target_p, form_str(RPL_SASLSUCCESS), me.name, EmptyString(target_p->name) ? "*" : target_p->name); target_p->preClient->sasl_complete = 1; ServerStats.is_ssuc++; } *target_p->preClient->sasl_agent = '\0'; /* Blank the stored agent so someone else can answer */ } return 0; }
struct Client *make_local_person_full(const char *nick, const char *username, const char *hostname, const char *ip, const char *realname) { struct Client *client; client = make_client(NULL); rb_dlinkMoveNode(&client->localClient->tnode, &unknown_list, &lclient_list); client->servptr = &me; rb_dlinkAdd(client, &client->lnode, &client->servptr->serv->users); make_user(client); SetClient(client); rb_inet_pton_sock(ip, (struct sockaddr *)&client->localClient->ip); rb_strlcpy(client->name, nick, sizeof(client->name)); rb_strlcpy(client->username, username, sizeof(client->username)); rb_strlcpy(client->host, hostname, sizeof(client->host)); rb_inet_ntop_sock((struct sockaddr *)&client->localClient->ip, client->sockhost, sizeof(client->sockhost)); rb_strlcpy(client->info, realname, sizeof(client->info)); add_to_client_hash(client->name, client); return client; }
/* SET ADMINSTRING */ static void quote_adminstring(struct Client *source_p, const char *arg, int newval) { if(EmptyString(arg)) { sendto_one_notice(source_p, ":ADMINSTRING is currently '%s'", GlobalSetOptions.adminstring); } else { rb_strlcpy(GlobalSetOptions.adminstring, arg, sizeof(GlobalSetOptions.adminstring)); sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed ADMINSTRING to '%s'", get_oper_name(source_p), arg); } }
pid_t rb_spawn_process(const char *path, const char **argv) { PROCESS_INFORMATION pi; STARTUPINFO si; char cmd[MAX_PATH]; memset(&pi, 0, sizeof(pi)); memset(&si, 0, sizeof(si)); rb_strlcpy(cmd, path, sizeof(cmd)); if(CreateProcess(cmd, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == FALSE) return -1; return (pi.dwProcessId); }
static void cap_end(struct Client *source_p, const char *arg) { if(IsRegistered(source_p)) return; source_p->flags &= ~FLAGS_CLICAP; if(source_p->name[0] && source_p->flags & FLAGS_SENTUSER) { char buf[USERLEN+1]; rb_strlcpy(buf, source_p->username, sizeof(buf)); register_local_user(source_p, source_p, buf); } }
struct Client *make_remote_server_full(struct Client *uplink, const char *name, const char *id) { struct Client *client; client = make_client(NULL); client->servptr = uplink; attach_server_conf(client, find_server_conf(name)); rb_strlcpy(client->name, name, sizeof(client->name)); rb_strlcpy(client->id, id, sizeof(client->id)); rb_dlinkAdd(client, &client->lnode, &uplink->serv->servers); rb_dlinkMoveNode(&client->localClient->tnode, &unknown_list, &serv_list); rb_dlinkAddTailAlloc(client, &global_serv_list); make_server(client); SetServer(client); add_to_client_hash(client->name, client); return client; }
/* * add_connection - creates a client which has just connected to us on * the given fd. The sockhost field is initialized with the ip# of the host. * The client is sent to the auth module for verification, and not put in * any client list yet. */ static void add_connection(struct Listener *listener, rb_fde_t *F, struct sockaddr *sai, struct sockaddr *lai) { struct Client *new_client; s_assert(NULL != listener); /* * get the client socket name from the socket * the client has already been checked out in accept_connection */ new_client = make_client(NULL); if (listener->ssl) { rb_fde_t *xF[2]; if(rb_socketpair(AF_UNIX, SOCK_STREAM, 0, &xF[0], &xF[1], "Incoming ssld Connection") == -1) { free_client(new_client); return; } new_client->localClient->ssl_ctl = start_ssld_accept(F, xF[1], new_client->localClient->connid); /* this will close F for us */ if(new_client->localClient->ssl_ctl == NULL) { free_client(new_client); return; } F = xF[0]; SetSSL(new_client); } memcpy(&new_client->localClient->ip, sai, sizeof(struct rb_sockaddr_storage)); memcpy(&new_client->preClient->lip, lai, sizeof(struct rb_sockaddr_storage)); /* * copy address to 'sockhost' as a string, copy it to host too * so we have something valid to put into error messages... */ rb_inet_ntop_sock((struct sockaddr *)&new_client->localClient->ip, new_client->sockhost, sizeof(new_client->sockhost)); rb_strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host)); new_client->localClient->F = F; new_client->localClient->listener = listener; ++listener->ref_count; start_auth(new_client); }
struct scache_entry * scache_connect(const char *name, const char *info, int hidden) { struct scache_entry *ptr; ptr = find_or_add(name); rb_strlcpy(ptr->info, info, sizeof(ptr->info)); ptr->flags |= SC_ONLINE; if (hidden) ptr->flags |= SC_HIDDEN; else ptr->flags &= ~SC_HIDDEN; ptr->last_connect = rb_current_time(); return ptr; }
static void chm_nocolour_process(hook_data_privmsg_channel *data) { /* don't waste CPU if message is already blocked */ if (data->approved) return; if (data->chptr->mode.mode & mode_nocolour) { rb_strlcpy(buf, data->text, sizeof buf); strip_colour(buf); data->text = buf; } }
/* * list_one_channel() * * inputs - client pointer, channel pointer, whether normally visible * outputs - none * side effects - a channel is listed */ static void list_one_channel(struct Client *source_p, struct Channel *chptr, int visible) { char topic[TOPICLEN + 1]; if (chptr->topic != NULL) rb_strlcpy(topic, chptr->topic, sizeof topic); else topic[0] = '\0'; strip_colour(topic); sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name, visible ? "" : "!", chptr->chname, rb_dlink_list_length(&chptr->members), topic); }
struct Client *make_remote_person_full(struct Client *server, const char *nick, const char *username, const char *hostname, const char *ip, const char *realname) { struct Client *client; struct sockaddr addr; client = make_client(server); make_user(client); SetRemoteClient(client); client->servptr = server; rb_dlinkAdd(server, &server->lnode, &server->servptr->serv->users); rb_inet_pton_sock(ip, &addr); rb_strlcpy(client->name, nick, sizeof(client->name)); rb_strlcpy(client->username, username, sizeof(client->username)); rb_strlcpy(client->host, hostname, sizeof(client->host)); rb_inet_ntop_sock(&addr, client->sockhost, sizeof(client->sockhost)); rb_strlcpy(client->info, realname, sizeof(client->info)); add_to_client_hash(nick, client); add_to_hostname_hash(client->host, client); return client; }