00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: users.c,v 1.56 2007-05-10 00:25:07 sven Exp $";
00022 #endif
00023
00024 #include <eggdrop/eggdrop.h>
00025
00026
00027
00028 typedef struct {
00029 user_t *u;
00030 const char *ircmask;
00031 const char **entries;
00032 int nentries, maxentries;
00033 int rand_delete;
00034 } walker_info_t;
00035
00036 typedef struct {
00037 long start;
00038 long limit;
00039 partymember_t *pmember;
00040 const char *data;
00041 const char *channel;
00042 flags_t musthave[2];
00043 flags_t mustnothave[2];
00044 } cmd_match_data_t;
00045
00046 #define BAD_HANDLE_CHARS " *?@:"
00047
00048
00049
00050 static int g_uid = 1, uid_wraparound = 0;
00051
00052
00053 static int nusers = 0;
00054
00055
00056 static hash_table_t *irchost_cache_ht = NULL;
00057
00058
00059 static hash_table_t *handle_ht = NULL;
00060
00061
00062 static hash_table_t *uid_ht = NULL;
00063
00064
00065 static ircmask_list_t ircmask_list = {NULL};
00066
00083 static bind_table_t *BT_uflags = NULL;
00084
00101 static bind_table_t *BT_uset = NULL;
00102
00116 static bind_table_t *BT_udelete = NULL;
00117
00118
00119 static user_t *real_user_new(const char *handle, int uid);
00120 static int user_get_uid();
00121 static int cache_check_add(const void *key, void *dataptr, void *client_data);
00122 static int cache_check_del(const void *key, void *dataptr, void *client_data);
00123 static int cache_rand_cleanup(const char *event);
00124 static int cache_user_del(user_t *u, const char *ircmask);
00125 static void append_setting(user_t *u, const char *chan, const char *flag_str, xml_node_t *extended);
00126 static int userlist_delete_walker(const void *key, void *dataptr, void *client_data);
00127
00128 int user_init(void)
00129 {
00130
00131
00132 handle_ht = hash_table_create(NULL, NULL, USER_HASH_SIZE, HASH_TABLE_STRINGS);
00133 uid_ht = hash_table_create(NULL, NULL, USER_HASH_SIZE, HASH_TABLE_INTS);
00134 irchost_cache_ht = hash_table_create(NULL, NULL, HOST_HASH_SIZE, HASH_TABLE_STRINGS | HASH_TABLE_FREE_KEY);
00135
00136
00137 BT_uflags = bind_table_add(BTN_USER_CHANGE_FLAGS, 4, "ssss", MATCH_MASK, BIND_STACKABLE);
00138 BT_uset = bind_table_add(BTN_USER_CHANGE_SETTINGS, 4, "ssss", MATCH_MASK, BIND_STACKABLE);
00139 BT_udelete = bind_table_add(BTN_USER_DELETE, 1, "U", MATCH_NONE, BIND_STACKABLE);
00140
00141
00142 bind_add_simple("event", NULL, "hourly", cache_rand_cleanup);
00143
00144 return(0);
00145 }
00146
00147 int user_shutdown(void)
00148 {
00149 hash_table_walk(uid_ht, userlist_delete_walker, NULL);
00150
00151
00152 garbage_run();
00153
00154 bind_table_del(BT_udelete);
00155 bind_table_del(BT_uset);
00156 bind_table_del(BT_uflags);
00157
00158 hash_table_delete(irchost_cache_ht);
00159 hash_table_delete(uid_ht);
00160 hash_table_delete(handle_ht);
00161
00162 return (0);
00163 }
00164
00165 void user_walk(hash_table_node_func callback, void *data)
00166 {
00167 hash_table_walk(uid_ht, callback, data);
00168 }
00169
00170 int user_load(const char *fname)
00171 {
00172 int uid;
00173 xml_node_t *root, *user_node, *ircmask_node, *setting_node, *extended_node;
00174 char *handle, *ircmask, *chan, *flag_str;
00175 user_t *u;
00176
00177 if (!(root = xml_parse_file(fname))) {
00178 putlog(LOG_MISC, "*", _("Failed to load userfile '%s': %s"), fname, xml_last_error());
00179 return -1;
00180 }
00181
00182 xml_node_get_vars(root, "ii", "next_uid", &uid, "uid_wraparound", &uid_wraparound);
00183 g_uid = uid;
00184
00185 user_node = xml_node_lookup(root, 0, "user", 0, 0);
00186 for (; user_node; user_node = user_node->next_sibling) {
00187
00188 xml_node_get_vars(user_node, "sinn", "handle", &handle, "uid", &uid, "ircmask", &ircmask_node, "setting", &setting_node);
00189
00190 if (!handle || !uid) continue;
00191 u = real_user_new(handle, uid);
00192
00193
00194 if (!u) continue;
00195
00196
00197 for (; ircmask_node; ircmask_node = ircmask_node->next_sibling) {
00198 ircmask = xml_node_str(ircmask_node, NULL);
00199 if (!ircmask) continue;
00200 u->ircmasks = realloc(u->ircmasks, sizeof(char *) * (u->nircmasks+1));
00201 u->ircmasks[u->nircmasks] = strdup(ircmask);
00202 u->nircmasks++;
00203 ircmask_list_add(&ircmask_list, ircmask, u);
00204 }
00205
00206
00207
00208 if (!setting_node) append_setting(u, NULL, NULL, NULL);
00209 for (; setting_node; setting_node = setting_node->next_sibling) {
00210 xml_node_get_vars(setting_node, "ssn", "chan", &chan, "flags", &flag_str, "extended", &extended_node);
00211 append_setting(u, chan, flag_str, extended_node);
00212 }
00213 }
00214 xml_doc_delete(root);
00215
00216 if (nusers == 1) putlog(LOG_MISC, "*", _("Loaded 1 user"));
00217 else putlog(LOG_MISC, "*", _("Loaded %d users"), nusers);
00218
00219 return(0);
00220 }
00221
00222 static int save_walker(const void *key, void *dataptr, void *param)
00223 {
00224 xml_node_t *root = param;
00225 user_t *u = *(user_t **)dataptr;
00226 user_setting_t *setting;
00227 xml_node_t *user_node, *setting_node;
00228 int i;
00229 char flag_str[128];
00230
00231 user_node = xml_node_new();
00232 user_node->name = strdup("user");
00233 xml_node_set_str(u->handle, user_node, "handle", 0, 0);
00234 xml_node_set_int(u->uid, user_node, "uid", 0, 0);
00235 for (i = 0; i < u->nircmasks; i++) xml_node_set_str(u->ircmasks[i], user_node, "ircmask", i, 0);
00236 for (i = 0; i < u->nsettings; i++) {
00237 setting = u->settings+i;
00238 setting_node = xml_node_new();
00239 setting_node->name = strdup("setting");
00240 if (setting->chan) xml_node_set_str(setting->chan, setting_node, "chan", 0, 0);
00241 flag_to_str(&u->settings[i].flags, flag_str);
00242 xml_node_set_str(flag_str, setting_node, "flags", 0, 0);
00243 xml_node_append(setting_node, u->settings[i].extended);
00244 xml_node_append(user_node, setting_node);
00245 }
00246 xml_node_append(root, user_node);
00247 return(0);
00248 }
00249
00250 static int unlink_walker(const void *key, void *dataptr, void *param)
00251 {
00252 user_t *u = *(user_t **)dataptr;
00253 int i;
00254
00255 for (i = 0; i < u->nsettings; i++) {
00256 xml_node_unlink(u->settings[i].extended);
00257 }
00258 return(0);
00259 }
00260
00261 int user_save(const char *fname)
00262 {
00263 xml_node_t *root;
00264
00265 root = xml_node_new();
00266 root->name = strdup("users");
00267
00268 xml_node_set_int(g_uid, root, "next_uid", 0, 0);
00269 xml_node_set_int(uid_wraparound, root, "uid_wraparound", 0, 0);
00270 hash_table_walk(uid_ht, save_walker, root);
00271
00272 xml_save_file((fname) ? fname : "users.xml", root, XML_INDENT);
00273
00274 hash_table_walk(uid_ht, unlink_walker, NULL);
00275
00276 xml_node_delete(root);
00277 return(0);
00278 }
00279
00280 static int user_get_uid()
00281 {
00282 user_t *u;
00283 int uid;
00284
00285 if (g_uid <= 0) {
00286 g_uid = 1;
00287 uid_wraparound++;
00288 }
00289
00290
00291 if (uid_wraparound) {
00292 while (!hash_table_find(uid_ht, (void *)g_uid, &u)) g_uid++;
00293 }
00294
00295 uid = g_uid;
00296 g_uid++;
00297 return(uid);
00298 }
00299
00300 const char *user_invalid_handle(const char *handle)
00301 {
00302 if (user_lookup_by_handle(handle)) return _("Handle already exists!");
00303 for (; *handle; ++handle) {
00304 if (*handle < 32 || strchr(BAD_HANDLE_CHARS, *handle)) {
00305 return _("Handle contains invalid characters!");
00306 }
00307 }
00308 return NULL;
00309 }
00310
00311 static user_t *real_user_new(const char *handle, int uid)
00312 {
00313 user_t *u;
00314
00315
00316 if (user_invalid_handle(handle)) return(NULL);
00317
00318 u = calloc(1, sizeof(*u));
00319 u->handle = strdup(handle);
00320 if (!uid) uid = user_get_uid();
00321 u->uid = uid;
00322
00323 hash_table_insert(handle_ht, u->handle, u);
00324 hash_table_insert(uid_ht, (void *)u->uid, u);
00325 nusers++;
00326 return(u);
00327 }
00328
00329 user_t *user_new(const char *handle)
00330 {
00331 int uid;
00332 user_t *u;
00333
00334 uid = user_get_uid();
00335 u = real_user_new(handle, uid);
00336 if (!u) return(NULL);
00337
00338
00339 u->settings = calloc(1, sizeof(*u->settings));
00340 u->nsettings = 1;
00341 u->settings[0].extended = xml_node_new();
00342 u->settings[0].extended->name = strdup("extended");
00343
00344 return(u);
00345 }
00346
00347 static int user_really_delete(void *client_data)
00348 {
00349 int i;
00350 user_t *u = client_data;
00351 user_setting_t *setting;
00352
00353
00354 for (i = 0; i < u->nircmasks; i++) free(u->ircmasks[i]);
00355 if (u->ircmasks) free(u->ircmasks);
00356
00357
00358 for (i = 0; i < u->nsettings; i++) {
00359 setting = u->settings+i;
00360 xml_node_delete(setting->extended);
00361 if (setting->chan) free(setting->chan);
00362 }
00363 if (u->settings) free(u->settings);
00364 if (u->handle) free(u->handle);
00365
00366 free(u);
00367 return(0);
00368 }
00369
00370 int user_delete(user_t *u)
00371 {
00372 int i;
00373
00374 if (!u || (u->flags & (USER_DELETED | USER_LINKING_BOT | USER_LINKED_BOT))) return(-1);
00375
00376 nusers--;
00377 hash_table_remove(handle_ht, u->handle, NULL);
00378 hash_table_remove(uid_ht, (void *)u->uid, NULL);
00379 cache_user_del(u, "*");
00380 for (i = 0; i < u->nircmasks; i++) ircmask_list_del(&ircmask_list, u->ircmasks[i], u);
00381 u->flags |= USER_DELETED;
00382 bind_check(BT_udelete, NULL, NULL, u);
00383 garbage_add(user_really_delete, u, 0);
00384 return(0);
00385 }
00386
00387 static int userlist_delete_walker(const void *key, void *dataptr, void *client_data)
00388 {
00389 return user_delete(*(user_t **)dataptr);
00390 }
00391
00392 user_t *user_lookup_by_handle(const char *handle)
00393 {
00394 user_t *u = NULL;
00395 if (handle == NULL) return NULL;
00396 hash_table_find(handle_ht, handle, &u);
00397 return(u);
00398 }
00399
00400 user_t *user_lookup_authed(const char *handle, const char *pass)
00401 {
00402 user_t *u = user_lookup_by_handle(handle);
00403 if (!u) return(NULL);
00404 if (user_check_pass(u, pass)) return(u);
00405 return(NULL);
00406 }
00407
00408 user_t *user_lookup_by_uid(int uid)
00409 {
00410 user_t *u = NULL;
00411
00412 hash_table_find(uid_ht, (void *)uid, &u);
00413 return(u);
00414 }
00415
00416 user_t *user_lookup_by_irchost_nocache(const char *irchost)
00417 {
00418 user_t *u;
00419
00420
00421 if (!hash_table_find(irchost_cache_ht, irchost, &u)) return(u);
00422
00423
00424 ircmask_list_find(&ircmask_list, irchost, &u);
00425 return(u);
00426 }
00427
00428 user_t *user_lookup_by_irchost(const char *irchost)
00429 {
00430 user_t *u;
00431
00432
00433 if (!hash_table_find(irchost_cache_ht, irchost, &u)) return(u);
00434
00435
00436 ircmask_list_find(&ircmask_list, irchost, &u);
00437
00438
00439 hash_table_insert(irchost_cache_ht, strdup(irchost), u);
00440 return(u);
00441 }
00442
00443 static int cache_check_add(const void *key, void *dataptr, void *client_data)
00444 {
00445 const char *irchost = key;
00446 user_t *u = *(user_t **)dataptr;
00447 walker_info_t *info = client_data;
00448 int i, strength, max_strength;
00449
00450
00451 max_strength = 0;
00452 if (u) {
00453 for (i = 0; i < u->nircmasks; i++) {
00454 strength = wild_match(u->ircmasks[i], irchost);
00455 if (strength > max_strength) max_strength = strength;
00456 }
00457 }
00458
00459
00460 strength = wild_match(info->ircmask, irchost);
00461 if (strength > max_strength) {
00462
00463 *(user_t **)dataptr = info->u;
00464 }
00465 return(0);
00466 }
00467
00468 static int cache_check_del(const void *key, void *dataptr, void *client_data)
00469 {
00470 const char *irchost = key;
00471 user_t *u = *(user_t **)dataptr;
00472 walker_info_t *info = client_data;
00473
00474 if ((info->rand_delete && (rand() & 1)) || (!info->rand_delete && u == info->u && wild_match(info->ircmask, irchost))) {
00475 if (info->nentries >= info->maxentries) {
00476 info->maxentries = 2*info->maxentries+1;
00477 info->entries = realloc(info->entries, sizeof(*info->entries) * (info->maxentries+1));
00478 }
00479 info->entries[info->nentries] = irchost;
00480 info->nentries++;
00481 }
00482 return(0);
00483 }
00484
00485 static int cache_user_del(user_t *u, const char *ircmask)
00486 {
00487 walker_info_t info;
00488 int i;
00489
00490
00491 info.u = u;
00492 info.ircmask = ircmask;
00493 info.entries = NULL;
00494 info.nentries = 0;
00495 info.maxentries = 0;
00496 info.rand_delete = 0;
00497 hash_table_walk(irchost_cache_ht, cache_check_del, &info);
00498 for (i = 0; i < info.nentries; i++) {
00499 hash_table_remove(irchost_cache_ht, info.entries[i], NULL);
00500 }
00501 if (info.entries) free(info.entries);
00502
00503
00504 ircmask_list_del(&ircmask_list, ircmask, u);
00505 return(0);
00506 }
00507
00508 static int cache_rand_cleanup(const char *event)
00509 {
00510 walker_info_t info;
00511 int i;
00512
00513
00514 info.u = NULL;
00515 info.ircmask = NULL;
00516 info.entries = NULL;
00517 info.nentries = 0;
00518 info.maxentries = 0;
00519 info.rand_delete = 1;
00520 hash_table_walk(irchost_cache_ht, cache_check_del, &info);
00521 putlog(LOG_MISC, "*", "user_rand_cleanup: deleting %d entries from cache", info.nentries);
00522 for (i = 0; i < info.nentries; i++) {
00523 hash_table_remove(irchost_cache_ht, info.entries[i], NULL);
00524 }
00525 if (info.entries) free(info.entries);
00526 return(0);
00527 }
00528
00529 int user_add_ircmask(user_t *u, const char *ircmask)
00530 {
00531 walker_info_t info;
00532
00533
00534 u->ircmasks = (char **)realloc(u->ircmasks, sizeof(char *) * (u->nircmasks+1));
00535 u->ircmasks[u->nircmasks] = strdup(ircmask);
00536 u->nircmasks++;
00537
00538
00539 ircmask_list_add(&ircmask_list, ircmask, u);
00540
00541
00542 info.u = u;
00543 info.ircmask = ircmask;
00544 hash_table_walk(irchost_cache_ht, cache_check_add, &info);
00545 return(0);
00546 }
00547
00548 int user_del_ircmask(user_t *u, const char *ircmask)
00549 {
00550 int i;
00551
00552
00553 for (i = 0; i < u->nircmasks; i++) {
00554 if (!strcasecmp(u->ircmasks[i], ircmask)) break;
00555 }
00556 if (i == u->nircmasks) return(-1);
00557
00558
00559 memmove(u->ircmasks+i, u->ircmasks+i+1, sizeof(char *) * (u->nircmasks - i - 1));
00560 u->nircmasks--;
00561
00562
00563 cache_user_del(u, ircmask);
00564
00565 return(0);
00566 }
00567
00568 static int get_flags(user_t *u, const char *chan, flags_t **flags)
00569 {
00570 int i;
00571
00572 if (!chan) i = 0;
00573 else {
00574 for (i = 1; i < u->nsettings; i++) {
00575 if (!strcasecmp(chan, u->settings[i].chan)) break;
00576 }
00577 if (i == u->nsettings) return(-1);
00578 }
00579 *flags = &u->settings[i].flags;
00580 return(0);
00581 }
00582
00583 int user_get_flags(user_t *u, const char *chan, flags_t *flags)
00584 {
00585 flags_t *uflags;
00586
00587 if (get_flags(u, chan, &uflags)) return(-1);
00588
00589 flags->builtin = uflags->builtin;
00590 flags->udef = uflags->udef;
00591 return(0);
00592 }
00593
00594 static int check_flag_change(user_t *u, const char *chan, flags_t *oldflags, flags_t *newflags)
00595 {
00596 char oldstr[64], newstr[64], *change;
00597 int r;
00598
00599 if (u->flags & (USER_LINKING_BOT | USER_LINKED_BOT) && !chan && (oldflags->builtin & 2) != (newflags->builtin & 2)) return -1;
00600 flag_to_str(oldflags, oldstr);
00601 flag_to_str(newflags, newstr);
00602 change = egg_msprintf(NULL, 0, NULL, "%s %s %s", chan ? chan : "", oldstr, newstr);
00603 r = bind_check(BT_uflags, NULL, change, u->handle, chan, oldstr, newstr);
00604 free(change);
00605
00606
00607 if (r & BIND_RET_BREAK) return(-1);
00608 if (!chan) {
00609 if (newflags->builtin & 2) u->flags |= USER_BOT;
00610 else u->flags &= ~USER_BOT;
00611 }
00612 return(0);
00613 }
00614
00615 int user_set_flags(user_t *u, const char *chan, flags_t *flags)
00616 {
00617 flags_t *oldflags, newflags;
00618
00619 if (get_flags(u, chan, &oldflags)) {
00620 append_setting(u, chan, NULL, NULL);
00621 if (get_flags(u, chan, &oldflags)) return -1;
00622 }
00623 newflags.builtin = flags->builtin;
00624 newflags.udef = flags->udef;
00625 if (check_flag_change(u, chan, oldflags, &newflags)) return(0);
00626 oldflags->builtin = newflags.builtin;
00627 oldflags->udef = newflags.udef;
00628 if (chan)
00629 channel_sanity_check(oldflags);
00630 else
00631 global_sanity_check(oldflags);
00632 return(0);
00633 }
00634
00635 int user_set_flags_str(user_t *u, const char *chan, const char *flags)
00636 {
00637 flags_t *oldflags, newflags;
00638
00639 if (get_flags(u, chan, &oldflags)) {
00640 append_setting(u, chan, NULL, NULL);
00641 if (get_flags(u, chan, &oldflags)) return(-1);
00642 }
00643 newflags.builtin = oldflags->builtin;
00644 newflags.udef = oldflags->udef;
00645 flag_merge_str(&newflags, flags);
00646 if (check_flag_change(u, chan, oldflags, &newflags)) return(0);
00647 oldflags->builtin = newflags.builtin;
00648 oldflags->udef = newflags.udef;
00649 if (chan)
00650 channel_sanity_check(oldflags);
00651 else
00652 global_sanity_check(oldflags);
00653 return(0);
00654 }
00655
00656 static void append_setting(user_t *u, const char *chan, const char *flag_str, xml_node_t *extended)
00657 {
00658 user_setting_t *setting;
00659 u->settings = realloc(u->settings, sizeof(*u->settings) * (u->nsettings+1));
00660 setting = u->settings + u->nsettings;
00661 u->nsettings++;
00662 memset(setting, 0, sizeof(*setting));
00663 if (chan) setting->chan = strdup(chan);
00664 if (flag_str) flag_from_str(&setting->flags, flag_str);
00665 if (!chan && setting->flags.builtin & 2) u->flags |= USER_BOT;
00666 if (extended) {
00667 xml_node_unlink(extended);
00668 setting->extended = extended;
00669 }
00670 else {
00671 setting->extended = xml_node_new();
00672 setting->extended->name = strdup("extended");
00673 }
00674 }
00675
00676 static xml_node_t *find_setting(user_t *u, const char *chan, const char *name, int create)
00677 {
00678 user_setting_t *setting;
00679 int i = 0;
00680
00681 if (chan) for (i = 1; i < u->nsettings; i++) {
00682 if (!strcasecmp(chan, u->settings[i].chan)) break;
00683 }
00684 if (i >= u->nsettings) {
00685 if (!create) return(NULL);
00686 append_setting(u, chan, NULL, NULL);
00687 }
00688 setting = u->settings+i;
00689 return xml_node_lookup(setting->extended, create, name, 0, NULL);
00690 }
00691
00692 int user_get_setting(user_t *u, const char *chan, const char *setting, char **valueptr)
00693 {
00694 xml_node_t *node = find_setting(u, chan, setting, 0);
00695
00696 return xml_node_get_str(valueptr, node, NULL);
00697 }
00698
00699 int user_set_setting(user_t *u, const char *chan, const char *setting, const char *value)
00700 {
00701 int r;
00702 char *change, buf[64];
00703 xml_node_t *node;
00704
00705 change = egg_msprintf(buf, sizeof(buf), NULL, "%s %s", chan ? chan : "", setting);
00706 r = bind_check(BT_uset, NULL, change, u->handle, chan, setting, value);
00707 if (change != buf) free(change);
00708
00709 if (r & BIND_RET_BREAK) return(0);
00710
00711 node = find_setting(u, chan, setting, 1);
00712 return xml_node_set_str(value, node, NULL);
00713 }
00714
00715 int user_has_pass(user_t *u)
00716 {
00717 char *hash, *salt;
00718
00719 user_get_setting(u, NULL, "pass", &hash);
00720 user_get_setting(u, NULL, "salt", &salt);
00721 if (hash && salt && strcmp(hash, "none")) return(1);
00722 return(0);
00723 }
00724
00725 int user_check_pass(user_t *u, const char *pass)
00726 {
00727 char *hash, *salt, testhex[33];
00728 unsigned char test[16];
00729 MD5_CTX ctx;
00730
00731 user_get_setting(u, NULL, "pass", &hash);
00732 user_get_setting(u, NULL, "salt", &salt);
00733 if (!hash || !salt || !strcmp(hash, "none")) return(0);
00734
00735 MD5_Init(&ctx);
00736 MD5_Update(&ctx, salt, strlen(salt));
00737 MD5_Update(&ctx, pass, strlen(pass));
00738 MD5_Final(test, &ctx);
00739 MD5_Hex(test, testhex);
00740 return !strcasecmp(testhex, hash);
00741 }
00742
00743 int user_set_pass(user_t *u, const char *pass)
00744 {
00745 char hashhex[33], *salt, new_salt[33];
00746 unsigned char hash[16];
00747 MD5_CTX ctx;
00748
00749 user_get_setting(u, NULL, "salt", &salt);
00750 if (!salt) {
00751 salt = new_salt;
00752 user_rand_pass(salt, sizeof(new_salt));
00753 user_set_setting(u, NULL, "salt", salt);
00754 }
00755
00756 if (!pass || !*pass) {
00757 user_set_setting(u, NULL, "pass", "none");
00758 return(1);
00759 }
00760 MD5_Init(&ctx);
00761 MD5_Update(&ctx, salt, strlen(salt));
00762 MD5_Update(&ctx, pass, strlen(pass));
00763 MD5_Final(hash, &ctx);
00764 MD5_Hex(hash, hashhex);
00765 user_set_setting(u, NULL, "pass", hashhex);
00766 return(0);
00767 }
00768
00769 int user_count()
00770 {
00771 return(nusers);
00772 }
00773
00774
00775 int user_rand_pass(char *buf, int bufsize)
00776 {
00777 int i, c;
00778
00779 bufsize--;
00780 if (!buf || bufsize <= 0) return(-1);
00781 for (i = 0; i < bufsize; i++) {
00782 c = (random() + (random() >> 16) + (random() >> 24)) % 62;
00783 if (c < 10) c += 48;
00784 else if (c < 36) c += 55;
00785 else c += 61;
00786 buf[i] = c;
00787 }
00788 buf[i] = 0;
00789 return(0);
00790 }
00791
00792 int user_check_flags(user_t *u, const char *chan, flags_t *flags)
00793 {
00794 flags_t f;
00795
00796 user_get_flags(u, chan, &f);
00797 return flag_match_subset(flags, &f);
00798 }
00799
00800 int user_check_flags_str(user_t *u, const char *chan, const char *flags)
00801 {
00802 flags_t f;
00803
00804 flag_from_str(&f, flags);
00805 return user_check_flags(u, chan, &f);
00806 }
00807
00808 int user_check_partial_flags(user_t *u, const char *chan, flags_t *flags)
00809 {
00810 flags_t f;
00811
00812 user_get_flags(u, chan, &f);
00813 return flag_match_partial(flags, &f);
00814 }
00815
00816 int user_check_partial_flags_str(user_t *u, const char *chan, const char *flags)
00817 {
00818 flags_t f;
00819
00820 flag_from_str(&f, flags);
00821 return user_check_partial_flags(u, chan, &f);
00822 }
00823
00824 int user_change_handle(user_t *u, const char *newhandle)
00825 {
00826 char *old = u->handle;
00827 partymember_t *p = NULL;
00828
00829 if (user_invalid_handle(newhandle)) return 1;
00830 hash_table_remove(handle_ht, u->handle, NULL);
00831 u->handle = strdup(newhandle);
00832 hash_table_insert(handle_ht, u->handle, u);
00833
00834 while ((p = partymember_lookup(old, NULL, -1))) {
00835 partymember_set_nick(p, u->handle);
00836 }
00837
00838 free(u->handle);
00839 return(0);
00840 }
00841
00842 static int ircmask_matches_user(user_t *u, const char *wild)
00843 {
00844 int i;
00845
00846 for (i = 0; i < u->nircmasks; i++)
00847 if (wild_match(wild, u->ircmasks[i]))
00848 return 1;
00849 return 0;
00850 }
00851
00852 static int
00853 attr_matches_user(user_t *u, cmd_match_data_t *mdata)
00854 {
00855 int matched = 0, haschanflags = 0;
00856 flags_t globflags, chanflags;
00857
00858 chanflags.builtin = chanflags.udef = 0;
00859
00860 if (user_get_flags(u, NULL, &globflags))
00861 return 0;
00862
00863 if (mdata->channel) {
00864 haschanflags = !user_get_flags(u, mdata->channel, &chanflags);
00865 if (!haschanflags)
00866 return 0;
00867 }
00868
00869 if ((mdata->musthave[0].builtin | mdata->musthave[0].udef) &&
00870 flag_match_subset(&mdata->musthave[0], &globflags) &&
00871 (!(mdata->mustnothave[0].builtin | mdata->mustnothave[0].udef) ||
00872 !flag_match_partial(&globflags, &mdata->mustnothave[0]))
00873 )
00874 matched = 1;
00875
00876 if (mdata->data) {
00877
00878 int tmpyes = mdata->musthave[1].builtin | mdata->musthave[1].udef;
00879 int tmpnot = mdata->mustnothave[1].builtin | mdata->mustnothave[1].udef;
00880 if (*mdata->data == '|') {
00881
00882 return (matched ||
00883 ((tmpyes && flag_match_subset(&mdata->musthave[1], &chanflags)) &&
00884
00885 (!tmpnot || !flag_match_partial(&chanflags, &mdata->mustnothave[1])))
00886
00887
00888 );
00889 }
00890 else if (*mdata->data == '&')
00891 return (matched &&
00892 ((tmpyes && flag_match_subset(&mdata->musthave[1], &chanflags)) &&
00893 (!tmpnot || !flag_match_partial(&chanflags, &mdata->mustnothave[1])))
00894 );
00895 else
00896 return 0;
00897 }
00898
00899 return matched;
00900 }
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910 static int
00911 callback_match_attr(const char *key, char **data, cmd_match_data_t *mdata)
00912 {
00913 user_t *u = user_lookup_by_handle(key);
00914
00915 if (!u)
00916 return 0;
00917
00918 if (mdata->start && attr_matches_user(u, mdata)) {
00919 mdata->start--;
00920 return 0;
00921 }
00922
00923 if (mdata->limit && attr_matches_user(u, mdata)) {
00924 mdata->limit--;
00925 partymember_printf(mdata->pmember, _(" %s"), key);
00926 }
00927
00928 return 0;
00929 }
00930
00931 static int
00932 callback_match_ircmask(const char *key, char **data, cmd_match_data_t *mdata)
00933 {
00934 user_t *u = user_lookup_by_handle(key);
00935
00936 if (!u)
00937 return 0;
00938
00939 if (mdata->start && (wild_match(mdata->data, key) || ircmask_matches_user(u, mdata->data))) {
00940 mdata->start--;
00941 return 0;
00942 }
00943
00944 if (mdata->limit && (wild_match(mdata->data, key) || ircmask_matches_user(u, mdata->data))) {
00945 mdata->limit--;
00946 partymember_printf(mdata->pmember, _(" %s"), key);
00947 }
00948
00949 return 0;
00950 }
00951
00952 int
00953 partyline_cmd_match_ircmask(void *p, const char *mask, long start, long limit)
00954 {
00955 cmd_match_data_t mdata;
00956
00957 mdata.start = start;
00958 mdata.limit = limit;
00959
00960 mdata.pmember = (partymember_t *)p;
00961 mdata.data = mask;
00962
00963 hash_table_walk(handle_ht, (hash_table_node_func)callback_match_ircmask, &mdata);
00964
00965 return 0;
00966 }
00967
00968 int
00969 partyline_cmd_match_attr(void *p, const char *attr, const char *chan, long start, long limit)
00970 {
00971 cmd_match_data_t mdata;
00972 int plsmns = 1, globchan = 0;
00973 char flagshack[] = "+ ";
00974
00975 mdata.start = start;
00976 mdata.limit = limit;
00977
00978 mdata.pmember = (partymember_t *)p;
00979 mdata.data = NULL;
00980 mdata.channel = chan;
00981 mdata.musthave[0].builtin = mdata.musthave[0].udef = 0;
00982 mdata.mustnothave[0].builtin = mdata.mustnothave[0].udef = 0;
00983 mdata.musthave[1].builtin = mdata.musthave[1].udef = 0;
00984 mdata.mustnothave[1].builtin = mdata.mustnothave[1].udef = 0;
00985
00986 while (*attr) {
00987 switch (*attr) {
00988 case '+':
00989 plsmns = 1;
00990 break;
00991 case '-':
00992 plsmns = 0;
00993 break;
00994 case '&':
00995 case '|':
00996 if (globchan == 0) {
00997 globchan++;
00998 mdata.data = attr;
00999 }
01000 break;
01001 default:
01002 flagshack[1] = *attr;
01003 flag_merge_str(plsmns ? &mdata.musthave[globchan] :
01004 &mdata.mustnothave[globchan], flagshack);
01005 break;
01006 }
01007 attr++;
01008 }
01009
01010 hash_table_walk(handle_ht, (hash_table_node_func)callback_match_attr, &mdata);
01011
01012 return 0;
01013 }