Bez tytułu

z Round Madrill, 3 miesiące temu, napisane w C, wyświetlone 35 razy. [paste_expire] 7 miesiące.
URL https://pastebin.k4be.pl/view/e9a04c4b Udostępnij
Pobierz wklejkę lub Pokaż surowy tekst
  1.  
  2. #include "unrealircd.h"
  3.  
  4. /* this should go into include/numeric.h (was there at one point of time) */
  5.  
  6. #define RPL_WHOISKEYVALUE    760
  7. #define RPL_KEYVALUE         761
  8. #define RPL_KEYNOTSET    766
  9. #define RPL_METADATASUBOK    770
  10. #define RPL_METADATAUNSUBOK  771
  11. #define RPL_METADATASUBS     772
  12. #define RPL_METADATASYNCLATER 774
  13.  
  14. #define STR_RPL_WHOISKEYVALUE           /* 760 */       "%s %s %s :%s"
  15. #define STR_RPL_KEYVALUE                        /* 761 */       "%s %s %s :%s"
  16. #define STR_RPL_KEYNOTSET                       /* 766 */       "%s %s :key not set" /* FIXME sending FAIL instead */
  17. #define STR_RPL_METADATASUBOK           /* 770 */       ":%s"
  18. #define STR_RPL_METADATAUNSUBOK         /* 771 */       ":%s"
  19. #define STR_RPL_METADATASUBS            /* 772 */       ":%s"
  20. #define STR_RPL_METADATASYNCLATER       /* 774 */       "%s %s"
  21.  
  22. /* sendnumeric() which allows message tags (BATCH in our case) */
  23.  
  24. #define sendnumeric_mtags(to, mtags, numeric, ...) sendnumericfmt_tags(to, mtags, numeric, STR_ ## numeric, ##__VA_ARGS__)
  25.  
  26. void vsendto_one(Client *to, MessageTag *mtags, const char *pattern, va_list vl); /* no prototype from send.c */
  27.  
  28. void sendnumericfmt_tags (Client *to, MessageTag *mtags, int numeric, FORMAT_STRING(const char *pattern), ...) {
  29.         va_list vl;
  30.         char realpattern[512];
  31.  
  32.         snprintf(realpattern, sizeof(realpattern), ":%s %.3d %s %s", me.name, numeric, to->name[0] ? to->name : "*", pattern);
  33.  
  34.         va_start(vl, pattern);
  35.         vsendto_one(to, mtags, realpattern, vl);
  36.         va_end(vl);
  37. }
  38.  
  39. /* actual METADATA code */
  40.  
  41. #define STR_HELPER(x) #x
  42. #define STR(x) STR_HELPER(x)
  43.  
  44. /* get or set for perms */
  45. #define MODE_SET 0
  46. #define MODE_GET 1
  47.  
  48. #define WATCH_EVENT_METADATA    3000 /* core uses 0..8, we hope no other module will try 3000 */
  49.  
  50. #define MYCONF "metadata"
  51.  
  52. #define CHECKPARAMSCNT_OR_DIE(count, return) \
  53. { \
  54.         if (parc < count+1 || BadPtr(parv[count])) \
  55.         { \
  56.                 sendnumeric(client, ERR_NEEDMOREPARAMS, "METADATA"); \
  57.                 return; \
  58.         } \
  59. }
  60.  
  61. /* target "*" is always the user issuing the command */
  62.  
  63. #define PROCESS_TARGET_OR_DIE(target, user, channel, return) \
  64. { \
  65.         char *channame; \
  66.         channame = strchr(target, '#'); \
  67.         if (channame) \
  68.         { \
  69.                 channel = find_channel(channame); \
  70.                 if (!channel) \
  71.                 { \
  72.                         sendnumeric(client, ERR_NOSUCHNICK, channame); \
  73.                         return; \
  74.                 } \
  75.         } else \
  76.         { \
  77.                 if (strcmp(target, "*")) \
  78.                 { \
  79.                         user = hash_find_nickatserver(target, NULL); \
  80.                         if (!user) \
  81.                         { \
  82.                                 sendnumeric(client, ERR_NOSUCHNICK, target); \
  83.                                 return; \
  84.                         } \
  85.                 } else \
  86.                 { \
  87.                         user = client; \
  88.                 } \
  89.         } \
  90. }
  91.  
  92. #define FOR_EACH_KEY(keyindex, parc, parv) while(keyindex++, key = parv[keyindex], (!BadPtr(key) && keyindex < parc))
  93. #define IsSendable(x)           (DBufLength(&x->local->sendQ) < 2048)
  94. #define CHECKREGISTERED_OR_DIE(client, return) \
  95. { \
  96.         if (!IsUser(client)) \
  97.         { \
  98.                 sendnumeric(client, ERR_NOTREGISTERED); \
  99.                 return; \
  100.         } \
  101. }
  102. #define USER_METADATA(client) moddata_client(client, metadataUser).ptr
  103. #define CHANNEL_METADATA(channel) moddata_channel(channel, metadataChannel).ptr
  104.  
  105. #define MAKE_BATCH(client, batch, mtags) do { \
  106.         if (HasCapability(client, "batch")) { \
  107.                 generate_batch_id(batch); \
  108.                 sendto_one(client, NULL, ":%s BATCH +%s metadata", me.name, batch); \
  109.                 mtags = safe_alloc(sizeof(MessageTag)); \
  110.                 mtags->name = strdup("batch"); \
  111.                 mtags->value = strdup(batch); \
  112.         } \
  113. } while(0)
  114.  
  115. #define FINISH_BATCH(client, batch, mtags) do { \
  116.         if (*batch) \
  117.                 sendto_one(client, NULL, ":%s BATCH -%s", me.name, batch); \
  118.         if (mtags) \
  119.                 free_message_tags(mtags); \
  120. } while(0)
  121.  
  122. struct metadata {
  123.         char *name;
  124.         char *value;
  125.         struct metadata *next;
  126. };
  127.  
  128. struct metadata_subscriptions {
  129.         char *name;
  130.         struct metadata_subscriptions *next;
  131. };
  132.  
  133. struct metadata_moddata_user {
  134.         struct metadata *metadata;
  135.         struct metadata_subscriptions *subs;
  136.         struct metadata_unsynced *us;
  137. };
  138.  
  139. struct metadata_unsynced { /* we're listing users (UIDs) or channels that should be synced but were not */
  140.         char *id;
  141.         char *key;
  142.         struct metadata_unsynced *next;
  143. };
  144.  
  145. CMD_FUNC(cmd_metadata);
  146. CMD_FUNC(cmd_metadata_remote);
  147. CMD_FUNC(cmd_metadata_local);
  148. EVENT(metadata_queue_evt);
  149. const char *metadata_cap_param(Client *client);
  150. char *metadata_isupport_param(void);
  151. int metadata_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
  152. int metadata_configposttest(int *errs);
  153. int metadata_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
  154. int metadata_server_sync(Client *client);
  155. int metadata_join(Client *client, Channel *channel, MessageTag *mtags);
  156. int metadata_user_registered(Client *client);
  157. void metadata_user_free(ModData *md);
  158. void metadata_channel_free(ModData *md);
  159. void metadata_free(struct metadata *metadata);
  160. void metadata_free_subs(struct metadata_subscriptions *subs);
  161. int metadata_is_subscribed(Client *user, const char *key);
  162. const char *metadata_get_user_key_value(Client *user, const char *key);
  163. const char *metadata_get_channel_key_value(Channel *channel, const char *key);
  164. void user_metadata_changed(Client *user, const char *key, const char *value, Client *changer);
  165. void channel_metadata_changed(Channel *channel, const char *key, const char *value, Client *changer);
  166. void metadata_free_list(struct metadata *metadata, const char *whose, Client *client);
  167. struct metadata_moddata_user *metadata_prepare_user_moddata(Client *user);
  168. void metadata_set_channel(Channel *channel, const char *key, const char *value, Client *client);
  169. void metadata_set_user(Client *user, const char *key, const char *value, Client *client);
  170. void metadata_send_channel(Channel *channel, const char *key, Client *client, MessageTag *mtags);
  171. void metadata_send_user(Client *user, const char *key, Client *client, MessageTag *mtags);
  172. int metadata_subscribe(const char *key, Client *client, int remove);
  173. void metadata_clear_channel(Channel *channel, Client *client);
  174. void metadata_clear_user(Client *user, Client *client);
  175. void metadata_send_subscribtions(Client *client);
  176. void metadata_send_all_for_channel(Channel *channel, Client *client);
  177. void metadata_send_all_for_user(Client *user, Client *client);
  178. void metadata_send_pending(Client *client);
  179. void metadata_sync_user(Client *client, Client *target, MessageTag *mtags, int create_batch);
  180. void metadata_sync_channel(Client *client, Channel *channel);
  181. int metadata_key_valid(const char *key);
  182. int metadata_check_perms(Client *user, Channel *channel, Client *client, const char *key, int mode);
  183. void metadata_send_change(Client *client, MessageTag *mtags, const char *who, const char *key, const char *value, Client *changer);
  184. int metadata_notify_or_queue(Client *client, MessageTag *mtags, const char *who, const char *key, const char *value, Client *changer);
  185. int metadata_monitor_connect(Client *client);
  186. int metadata_monitor_notification(Client *client, Watch *watch, Link *lp, int event);
  187.  
  188. ModDataInfo *metadataUser;
  189. ModDataInfo *metadataChannel;
  190. long CAP_METADATA = 0L;
  191. long CAP_METADATA_NOTIFY = 0L;
  192.  
  193. struct metadata_settings_s {
  194.         int max_user_metadata;
  195.         int max_channel_metadata;
  196.         int max_subscriptions;
  197.         int max_value_bytes;
  198. } metadata_settings;
  199.  
  200. ModuleHeader MOD_HEADER = {
  201.         "third/metadata-2",
  202.         "6.0",
  203.         "draft/metadata-2 and draft/metadata-notify-2 cap",
  204.         "k4be",
  205.         "unrealircd-6"
  206. };
  207.  
  208. /*
  209. metadata {
  210.         max-user-metadata 10;
  211.         max-channel-metadata 10;
  212.         max-subscriptions 10;
  213.         max-value-bytes 300;
  214. };
  215. */
  216.  
  217. int metadata_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
  218.         ConfigEntry *cep;
  219.         int errors = 0;
  220.         int i;
  221.        
  222.         if (type != CONFIG_MAIN)
  223.                 return 0;
  224.  
  225.         if (!ce || !ce->name)
  226.                 return 0;
  227.  
  228.         if (strcmp(ce->name, MYCONF))
  229.                 return 0;
  230.  
  231.         for (cep = ce->items; cep; cep = cep->next)
  232.         {
  233.                 if (!cep->name)
  234.                 {
  235.                         config_error("%s:%i: blank %s item", cep->file->filename, cep->line_number, MYCONF);
  236.                         errors++;
  237.                         continue;
  238.                 }
  239.  
  240.                 if (!cep->value || !strlen(cep->value))
  241.                 {
  242.                         config_error("%s:%i: %s::%s must be non-empty", cep->file->filename, cep->line_number, MYCONF, cep->name);
  243.                         errors++;
  244.                         continue;
  245.                 }
  246.        
  247.                 if (!strcmp(cep->name, "max-user-metadata"))
  248.                 {
  249.                         for (i = 0; cep->value[i]; i++)
  250.                         {
  251.                                 if (!isdigit(cep->value[i]))
  252.                                 {
  253.                                         config_error("%s:%i: %s::%s must be an integer between 1 and 100", cep->file->filename, cep->line_number, MYCONF, cep->name);
  254.                                         errors++;
  255.                                         break;
  256.                                 }
  257.                         }
  258.                         if (!errors && (atoi(cep->value) < 1 || atoi(cep->value) > 100))
  259.                         {
  260.                                 config_error("%s:%i: %s::%s must be an integer between 1 and 100", cep->file->filename, cep->line_number, MYCONF, cep->name);
  261.                                 errors++;
  262.                         }
  263.                         continue;
  264.                 }
  265.  
  266.                 if (!strcmp(cep->name, "max-channel-metadata"))
  267.                 {
  268.                         for (i = 0; cep->value[i]; i++)
  269.                         {
  270.                                 if (!isdigit(cep->value[i]))
  271.                                 {
  272.                                         config_error("%s:%i: %s::%s must be an integer between 0 and 100", cep->file->filename, cep->line_number, MYCONF, cep->name);
  273.                                         errors++;
  274.                                         break;
  275.                                 }
  276.                         }
  277.                         if (!errors && (atoi(cep->value) < 0 || atoi(cep->value) > 100))
  278.                         {
  279.                                 config_error("%s:%i: %s::%s must be an integer between 0 and 100", cep->file->filename, cep->line_number, MYCONF, cep->name);
  280.                                 errors++;
  281.                         }
  282.                         continue;
  283.                 }
  284.  
  285.                 if (!strcmp(cep->name, "max-subscriptions"))
  286.                 {
  287.                         for (i = 0; cep->value[i]; i++)
  288.                         {
  289.                                 if (!isdigit(cep->value[i]))
  290.                                 {
  291.                                         config_error("%s:%i: %s::%s must be an integer between 1 and 100", cep->file->filename, cep->line_number, MYCONF, cep->name);
  292.                                         errors++;
  293.                                         break;
  294.                                 }
  295.                         }
  296.                         if (!errors && (atoi(cep->value) < 0 || atoi(cep->value) > 100))
  297.                         {
  298.                                 config_error("%s:%i: %s::%s must be an integer between 1 and 100", cep->file->filename, cep->line_number, MYCONF, cep->name);
  299.                                 errors++;
  300.                         }
  301.                         continue;
  302.                 }
  303.  
  304.  
  305.                 if (!strcmp(cep->name, "max-value-bytes"))
  306.                 {
  307.                         for (i = 0; cep->value[i]; i++)
  308.                         {
  309.                                 if (!isdigit(cep->value[i]))
  310.                                 {
  311.                                         config_error("%s:%i: %s::%s must be an integer between 1 and 400", cep->file->filename, cep->line_number, MYCONF, cep->name);
  312.                                         errors++;
  313.                                         break;
  314.                                 }
  315.                         }
  316.                         if (!errors && (atoi(cep->value) < 0 || atoi(cep->value) > 400))
  317.                         {
  318.                                 config_error("%s:%i: %s::%s must be an integer between 1 and 400", cep->file->filename, cep->line_number, MYCONF, cep->name);
  319.                                 errors++;
  320.                         }
  321.                         continue;
  322.                 }
  323.  
  324.                 config_warn("%s:%i: unknown item %s::%s", cep->file->filename, cep->line_number, MYCONF, cep->name);
  325.         }
  326.        
  327.         *errs = errors;
  328.         return errors ? -1 : 1;
  329. }
  330.  
  331. int metadata_configposttest(int *errs) {
  332.         /* null the settings to avoid keeping old value if none is set in config */
  333.         metadata_settings.max_user_metadata = 0;
  334.         metadata_settings.max_channel_metadata = 0;
  335.         metadata_settings.max_subscriptions = 0;
  336.         metadata_settings.max_value_bytes = 0;
  337.         return 1;
  338. }
  339.  
  340. int metadata_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
  341.         ConfigEntry *cep;
  342.  
  343.         if (type != CONFIG_MAIN)
  344.                 return 0;
  345.  
  346.         if (!ce || !ce->name)
  347.                 return 0;
  348.  
  349.         if (strcmp(ce->name, MYCONF))
  350.                 return 0;
  351.  
  352.         for (cep = ce->items; cep; cep = cep->next)
  353.         {
  354.                 if (!cep->name)
  355.                         continue;
  356.  
  357.                 if (!strcmp(cep->name, "max-user-metadata"))
  358.                 {
  359.                         metadata_settings.max_user_metadata = atoi(cep->value);
  360.                         continue;
  361.                 }
  362.  
  363.                 if (!strcmp(cep->name, "max-channel-metadata"))
  364.                 {
  365.                         metadata_settings.max_channel_metadata = atoi(cep->value);
  366.                         continue;
  367.                 }
  368.  
  369.                 if (!strcmp(cep->name, "max-subscriptions"))
  370.                 {
  371.                         metadata_settings.max_subscriptions = atoi(cep->value);
  372.                         continue;
  373.                 }
  374.  
  375.                 if (!strcmp(cep->name, "max-value-bytes"))
  376.                 {
  377.                         metadata_settings.max_value_bytes = atoi(cep->value);
  378.                         continue;
  379.                 }
  380.         }
  381.         return 1;
  382. }
  383.  
  384. MOD_TEST(){
  385.         MARK_AS_OFFICIAL_MODULE(modinfo);
  386.         HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, metadata_configtest);
  387.         HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, metadata_configposttest);
  388.         return MOD_SUCCESS;
  389. }
  390.  
  391. MOD_INIT() {
  392.         ClientCapabilityInfo cap;
  393.         ClientCapability *c;
  394.         ModDataInfo mreq;
  395.        
  396.         MARK_AS_OFFICIAL_MODULE(modinfo);
  397.         MARK_AS_GLOBAL_MODULE(modinfo);
  398.  
  399.         memset(&cap, 0, sizeof(cap));
  400.         cap.name = "draft/metadata-2";
  401.         cap.parameter = metadata_cap_param;
  402.         c = ClientCapabilityAdd(modinfo->handle, &cap, &CAP_METADATA);
  403.        
  404.         memset(&cap, 0, sizeof(cap));
  405.         cap.name = "draft/metadata-notify-2"; /* for old client compatibility */
  406.         c = ClientCapabilityAdd(modinfo->handle, &cap, &CAP_METADATA_NOTIFY);
  407.        
  408.         CommandAdd(modinfo->handle, "METADATA", cmd_metadata, MAXPARA, CMD_USER|CMD_SERVER|CMD_UNREGISTERED);
  409.        
  410.         memset(&mreq, 0 , sizeof(mreq));
  411.         mreq.type = MODDATATYPE_CLIENT;
  412.         mreq.name = "metadata_user",
  413.         mreq.free = metadata_user_free;
  414.         metadataUser = ModDataAdd(modinfo->handle, mreq);
  415.         if (!metadataUser)
  416.         {
  417.                 config_error("[%s] Failed to request metadata_user moddata: %s", MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle));
  418.                 return MOD_FAILED;
  419.         }
  420.        
  421.         memset(&mreq, 0 , sizeof(mreq));
  422.         mreq.type = MODDATATYPE_CHANNEL;
  423.         mreq.name = "metadata_channel",
  424.         mreq.free = metadata_channel_free;
  425.         metadataChannel = ModDataAdd(modinfo->handle, mreq);
  426.         if (!metadataChannel)
  427.         {
  428.                 config_error("[%s] Failed to request metadata_channel moddata: %s", MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle));
  429.                 return MOD_FAILED;
  430.         }
  431.        
  432.         HookAdd(modinfo->handle, HOOKTYPE_SERVER_SYNC, 0, metadata_server_sync);
  433.         HookAdd(modinfo->handle, HOOKTYPE_LOCAL_JOIN, -2, metadata_join);
  434.         HookAdd(modinfo->handle, HOOKTYPE_REMOTE_JOIN, -2, metadata_join);
  435.         HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, metadata_user_registered);
  436.         HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, metadata_monitor_connect);
  437.         HookAdd(modinfo->handle, HOOKTYPE_REMOTE_CONNECT, 0, metadata_monitor_connect);
  438.  
  439.         HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, metadata_configrun);
  440.        
  441.         return MOD_SUCCESS;
  442. }
  443.  
  444. MOD_LOAD() {
  445.         /* setting default values if not configured */
  446.         if (metadata_settings.max_user_metadata == 0)
  447.                 metadata_settings.max_user_metadata = 10;
  448.         if (metadata_settings.max_channel_metadata == 0)
  449.                 metadata_settings.max_channel_metadata = 10;
  450.         if (metadata_settings.max_subscriptions == 0)
  451.                 metadata_settings.max_subscriptions = 10;
  452.         if (metadata_settings.max_value_bytes == 0)
  453.                 metadata_settings.max_value_bytes = 300;
  454.  
  455.         EventAdd(modinfo->handle, "metadata_queue", metadata_queue_evt, NULL, 1500, 0);
  456.         ISupportAdd(modinfo->handle, "METADATA", metadata_isupport_param());
  457.         return MOD_SUCCESS;
  458. }
  459.  
  460. MOD_UNLOAD() {
  461.         return MOD_SUCCESS;
  462. }
  463.  
  464. const char *metadata_cap_param(Client *client)
  465. {
  466.         static char buf[80];
  467.         ircsnprintf(buf, sizeof(buf), "before-connect,max-subs=%d,max-keys=%d,max-value-bytes=%d",
  468.                 metadata_settings.max_subscriptions, metadata_settings.max_user_metadata, metadata_settings.max_value_bytes);
  469.         return buf;
  470. }
  471.  
  472. char *metadata_isupport_param(void)
  473. {
  474.         static char buf[20];
  475.         ircsnprintf(buf, sizeof(buf), "%d", metadata_settings.max_user_metadata);
  476.         return buf;
  477. }
  478.  
  479. void metadata_free(struct metadata *metadata)
  480. {
  481.         safe_free(metadata->name);
  482.         safe_free(metadata->value);
  483.         safe_free(metadata);
  484. }
  485.  
  486. void metadata_free_subs(struct metadata_subscriptions *subs)
  487. {
  488.         safe_free(subs->name);
  489.         safe_free(subs);
  490. }
  491.  
  492. int metadata_is_subscribed(Client *user, const char *key)
  493. {
  494.         struct metadata_moddata_user *moddata = USER_METADATA(user);
  495.         if (!moddata)
  496.                 return 0;
  497.         struct metadata_subscriptions *subs;
  498.         for (subs = moddata->subs; subs; subs = subs->next)
  499.         {
  500.                 if (!strcasecmp(subs->name, key))
  501.                         return 1;
  502.         }
  503.         return 0;
  504. }
  505.  
  506. const char *metadata_get_user_key_value(Client *user, const char *key)
  507. {
  508.         struct metadata_moddata_user *moddata = USER_METADATA(user);
  509.         struct metadata *metadata = NULL;
  510.         if (!moddata)
  511.                 return NULL;
  512.         for (metadata = moddata->metadata; metadata; metadata = metadata->next)
  513.         {
  514.                 if (!strcasecmp(key, metadata->name))
  515.                         return metadata->value;
  516.         }
  517.         return NULL;
  518. }
  519.  
  520. const char *metadata_get_channel_key_value(Channel *channel, const char *key)
  521. {
  522.         struct metadata *metadata;
  523.         for (metadata = CHANNEL_METADATA(channel); metadata; metadata = metadata->next)
  524.         {
  525.                 if (!strcasecmp(key, metadata->name))
  526.                         return metadata->value;
  527.         }
  528.         return NULL;
  529. }
  530.  
  531. /* returns 1 if something remains to sync */
  532. int metadata_notify_or_queue(Client *client, MessageTag *mtags, const char *who, const char *key, const char *value, Client *changer)
  533. {
  534.         int trylater = 0;
  535.         if (!who)
  536.         {
  537.                 unreal_log(ULOG_DEBUG, "metadata", "METADATA_DEBUG", changer, "metadata_notify_or_queue called with null who!");
  538.                 return 0;
  539.         }
  540.         if (!key)
  541.         {
  542.                 unreal_log(ULOG_DEBUG, "metadata", "METADATA_DEBUG", changer, "metadata_notify_or_queue called with null key!");
  543.                 return 0;
  544.         }
  545.         if (!client)
  546.         {
  547.                 unreal_log(ULOG_DEBUG, "metadata", "METADATA_DEBUG", changer, "metadata_notify_or_queue called with null client!");
  548.                 return 0;
  549.         }
  550.  
  551.         struct metadata_moddata_user *moddata = USER_METADATA(client);
  552.         if (!moddata)
  553.                 moddata = metadata_prepare_user_moddata(client);
  554.         struct metadata_unsynced **us = &moddata->us;
  555.  
  556.         if (IsSendable(client))
  557.         {
  558.                 metadata_send_change(client, mtags, who, key, value, changer);
  559.         } else
  560.         { /* store for the SYNC */
  561.                 Client *who_client;
  562.                 const char *uid_or_channel;
  563.                 if (*who == '#') {
  564.                         uid_or_channel = who;
  565.                 } else {
  566.                         who_client = find_client(who, NULL); /* FIXME the caller should already have this figured out */
  567.                         if (!who_client) {
  568.                                 unreal_log(ULOG_DEBUG, "metadata", "METADATA_DEBUG", changer, "metadata_notify_or_queue called with nonexistent client!");
  569.                                 return 0; /* shouldn't happen */
  570.                         }
  571.                         uid_or_channel = who_client->id;
  572.                 }
  573.                        
  574.                 trylater = 1;
  575.                 while (*us)
  576.                         us = &(*us)->next; /* find last list element */
  577.                 *us = safe_alloc(sizeof(struct metadata_unsynced));
  578.                 (*us)->id = strdup(uid_or_channel);
  579.                 (*us)->key = strdup(key);
  580.                 (*us)->next = NULL;
  581.         }
  582.         return trylater;
  583. }
  584.  
  585. void metadata_send_change(Client *client, MessageTag *mtags, const char *who, const char *key, const char *value, Client *changer)
  586. {
  587.         char *sender = NULL;
  588.         if (!key)
  589.         {
  590.                 unreal_log(ULOG_DEBUG, "metadata", "METADATA_DEBUG", changer, "metadata_send_change called with null key!");
  591.                 return;
  592.         }
  593.         if (!who)
  594.         {
  595.                 unreal_log(ULOG_DEBUG, "metadata", "METADATA_DEBUG", changer, "metadata_send_change called with null who!");
  596.                 return;
  597.         }
  598.         if (!client)
  599.         {
  600.                 unreal_log(ULOG_DEBUG, "metadata", "METADATA_DEBUG", changer, "metadata_send_change called with null client!");
  601.                 return;
  602.         }
  603.         if (changer)
  604.         {
  605.                 if (IsServer(client))
  606.                         sender = changer->id;
  607.                 else
  608.                         sender = changer->name;
  609.         }
  610.         if (!sender)
  611.                 sender = me.name;
  612.         if (changer && IsUser(changer) && MyUser(client))
  613.         {
  614.                 if (!value)
  615.                         sendto_one(client, mtags, ":%s!%s@%s METADATA %s %s %s", sender, changer->user->username, GetHost(changer), who, key, "*");
  616.                 else
  617.                         sendto_one(client, mtags, ":%s!%s@%s METADATA %s %s %s :%s", sender, changer->user->username, GetHost(changer), who, key, "*", value);
  618.         } else
  619.         { /* sending S2S (sender is id) or receiving S2S (sender is servername) */
  620.                 if (!value)
  621.                         sendto_one(client, mtags, ":%s METADATA %s %s %s", sender, who, key, "*");
  622.                 else
  623.                         sendto_one(client, mtags, ":%s METADATA %s %s %s :%s", sender, who, key, "*", value);
  624.         }
  625. }
  626.  
  627. /* used for broadcasting changes to subscribed users and linked servers */
  628. void user_metadata_changed(Client *user, const char *key, const char *value, Client *changer){
  629.         Client *acptr;
  630.         if (!user || !key)
  631.                 return; /* sanity check */
  632.         list_for_each_entry(acptr, &lclient_list, lclient_node)
  633.         { /* notifications for local subscribers */
  634.                 if(IsUser(acptr) && IsUser(user) && metadata_is_subscribed(acptr, key) && has_common_channels(user, acptr))
  635.                         metadata_notify_or_queue(acptr, NULL, user->name, key, value, changer);
  636.         }
  637.  
  638.         list_for_each_entry(acptr, &server_list, special_node)
  639.         { /* notifications for linked servers, TODO change to sendto_server */
  640.                 if (acptr == &me)
  641.                         continue;
  642.                 metadata_send_change(acptr, NULL, user->name, key, value, changer);
  643.         }
  644.         /* notifications for MONITOR */
  645.         watch_check(user, WATCH_EVENT_METADATA, metadata_monitor_notification); /* for now sending info for all entries even if only one has changed */
  646. }
  647.  
  648. void channel_metadata_changed(Channel *channel, const char *key, const char *value, Client *changer)
  649. {
  650.         Client *acptr;
  651.         if (!channel || !key)
  652.                 return; /* sanity check */
  653.         list_for_each_entry(acptr, &lclient_list, lclient_node)
  654.         { /* notifications for local subscribers */
  655.                 if (metadata_is_subscribed(acptr, key) && IsMember(acptr, channel))
  656.                         metadata_send_change(acptr, NULL, channel->name, key, value, changer);
  657.         }
  658.        
  659.         list_for_each_entry(acptr, &server_list, special_node)
  660.         { /* notifications for linked servers, TODO change to sendto_server */
  661.                 if(acptr == &me)
  662.                         continue;
  663.                 metadata_send_change(acptr, NULL, channel->name, key, value, changer);
  664.         }
  665. }
  666.  
  667. void metadata_free_list(struct metadata *metadata, const char *whose, Client *client)
  668. {
  669.         struct metadata *prev_metadata = metadata;
  670.         char *name;
  671.         while(metadata)
  672.         {
  673.                 name = metadata->name;
  674.                 safe_free(metadata->value);
  675.                 metadata = metadata->next;
  676.                 safe_free(prev_metadata);
  677.                 prev_metadata = metadata;
  678.                 if(client && whose && *whose)
  679.                 { /* send out the data being removed, unless we're unloading the module */
  680.                         sendnumeric(client, RPL_KEYVALUE, whose, name, "*", "");
  681.                         if(*whose == '#')
  682.                                 channel_metadata_changed(find_channel(whose), name, NULL, client);
  683.                         else
  684.                                 user_metadata_changed(hash_find_nickatserver(whose, NULL), name, NULL, client);
  685.                 }
  686.                 safe_free(name);
  687.         }
  688. }
  689.  
  690. void metadata_channel_free(ModData *md)
  691. {
  692.         if (!md->ptr)
  693.                 return; /* was not set */
  694.         struct metadata *metadata = md->ptr;
  695.         metadata_free_list(metadata, NULL, NULL);
  696. }
  697.  
  698. void metadata_user_free(ModData *md)
  699. {
  700.         struct metadata_moddata_user *moddata = md->ptr;
  701.         if (!moddata)
  702.                 return; /* was not set */
  703.         struct metadata_subscriptions *sub = moddata->subs;
  704.         struct metadata_subscriptions *prev_sub = sub;
  705.         struct metadata_unsynced *us = moddata->us;
  706.         struct metadata_unsynced *prev_us;
  707.         while (sub)
  708.         {
  709.                 safe_free(sub->name);
  710.                 sub = sub->next;
  711.                 safe_free(prev_sub);
  712.                 prev_sub = sub;
  713.         }
  714.         struct metadata *metadata = moddata->metadata;
  715.         metadata_free_list(metadata, NULL, NULL);
  716.         while (us)
  717.         {
  718.                 safe_free(us->id);
  719.                 safe_free(us->key);
  720.                 prev_us = us;
  721.                 us = us->next;
  722.                 safe_free(prev_us);
  723.         }
  724.         safe_free(moddata);
  725. }
  726.  
  727. struct metadata_moddata_user *metadata_prepare_user_moddata(Client *user)
  728. {
  729.         USER_METADATA(user) = safe_alloc(sizeof(struct metadata_moddata_user));
  730.         struct metadata_moddata_user *ptr = USER_METADATA(user);
  731.         ptr->metadata = NULL;
  732.         ptr->subs = NULL;
  733.         return ptr;
  734. }
  735.  
  736. void metadata_set_user(Client *user, const char *key, const char *value, Client *client)
  737. {
  738.         int changed = 0;
  739.         Client *target;
  740.         char *target_name;
  741.         int removed = 0;
  742.         int set = 0;
  743.         int count = 0;
  744.         char *utf8_val = NULL;
  745.  
  746.         if (user)
  747.         {
  748.                 target = user;
  749.                 target_name = user->name;
  750.         } else
  751.         {
  752.                 target = client;
  753.                 target_name = "*";
  754.         }
  755.                
  756.         struct metadata_moddata_user *moddata = USER_METADATA(target);
  757.         if (!moddata) /* first call for this user */
  758.                 moddata = metadata_prepare_user_moddata(target);
  759.         struct metadata **metadata = &moddata->metadata;
  760.         struct metadata *prev;
  761.        
  762.         if (value && strlen(value) > metadata_settings.max_value_bytes)
  763.         {
  764.                 if (client)
  765.                         sendto_one(client, NULL, ":%s FAIL METADATA VALUE_INVALID %s :metadata value too long", me.name, target_name);
  766.                 return;
  767.         }
  768.         if (BadPtr(value) || strlen(value) == 0)
  769.         { /* unset */
  770.                 value = NULL; /* just to make sure */
  771.                 removed = 0;
  772.                 while (*metadata)
  773.                 {
  774.                         if (!strcasecmp(key, (*metadata)->name))
  775.                                 break;
  776.                         metadata = &(*metadata)->next;
  777.                 }
  778.                 if (*metadata)
  779.                 {
  780.                         prev = *metadata;
  781.                         *metadata = prev->next;
  782.                         metadata_free(prev);
  783.                         removed = 1;
  784.                         changed = 1;
  785.                 }
  786.                 if (!removed)
  787.                 {
  788.                         if (client)
  789.                                 sendto_one(client, NULL, ":%s FAIL METADATA KEY_NOT_SET %s %s :key not set", me.name, target_name, key); /* not set so can't remove */
  790.                         return;
  791.                 }
  792.         } else
  793.         { /* set */
  794.                 utf8_val = safe_alloc(metadata_settings.max_value_bytes + 1);
  795.                 unrl_utf8_make_valid(value, utf8_val, metadata_settings.max_value_bytes, 1);
  796.                 while (*metadata)
  797.                 {
  798.                         if (!strcasecmp(key, (*metadata)->name))
  799.                         {
  800.                                 set = 1;
  801.                                 if (strcmp(value, (*metadata)->value))
  802.                                 {
  803.                                         safe_free((*metadata)->value);
  804.                                         (*metadata)->value = utf8_val;
  805.                                         changed = 1;
  806.                                 }
  807.                         }
  808.                         metadata = &(*metadata)->next;
  809.                         count++;
  810.                 }
  811.                 if (!set)
  812.                 {
  813.                         if (!client || count < metadata_settings.max_user_metadata)
  814.                         { /* add new entry for user */
  815.                                 *metadata = safe_alloc(sizeof(struct metadata));
  816.                                 (*metadata)->next = NULL;
  817.                                 (*metadata)->name = strdup(key);
  818.                                 (*metadata)->value = utf8_val;
  819.                                 changed = 1;
  820.                         } else
  821.                         { /* no more allowed */
  822.                                 if (client)
  823.                                         sendto_one(client, NULL, ":%s FAIL METADATA LIMIT_REACHED %s :metadata limit reached", me.name, target_name);
  824.                         }
  825.                 }
  826.                 if (!changed)
  827.                 {
  828.                         safe_free(utf8_val);
  829.                         return;
  830.                 }
  831.         }
  832.  
  833.         if (!IsServer(client) && MyConnect(client))
  834.         {
  835.                 if (BadPtr(value))
  836.                         sendnumeric(client, RPL_KEYNOTSET, (*target_name)?target_name:"*", key); /* ok but empty */
  837.                 else
  838.                         sendnumeric(client, RPL_KEYVALUE, (*target_name)?target_name:"*", key, "*", value?value:""); /* all OK */
  839.         }
  840.         if (changed && (client == &me || IsUser(client) || IsServer(client)))
  841.                 user_metadata_changed(target, key, value, client);
  842. }
  843.  
  844. void metadata_set_channel(Channel *channel, const char *key, const char *value, Client *client)
  845. {
  846.         int changed = 0;
  847.         int set = 0;
  848.         int count = 0;
  849.         char *utf8_val = NULL;
  850.         struct metadata **metadata = (struct metadata **)&CHANNEL_METADATA(channel);
  851.         struct metadata *prev;
  852.  
  853.         if (value && strlen(value) > metadata_settings.max_value_bytes)
  854.         {
  855.                 if (client)
  856.                         sendto_one(client, NULL, ":%s FAIL METADATA VALUE_INVALID %s :metadata value too long", me.name, channel->name);
  857.                 return;
  858.         }
  859.  
  860.         if(BadPtr(value) || strlen(value) == 0)
  861.         { /* unset */
  862.                 value = NULL; /* just to make sure */
  863.                 int removed = 0;
  864.                 while (*metadata)
  865.                 {
  866.                         if (!strcasecmp(key, (*metadata)->name))
  867.                                 break;
  868.                         metadata = &(*metadata)->next;
  869.                 }
  870.                 if (*metadata)
  871.                 {
  872.                         prev = *metadata;
  873.                         *metadata = prev->next;
  874.                         metadata_free(prev);
  875.                         removed = 1;
  876.                         changed = 1;
  877.                 }
  878.                 if (!removed)
  879.                 {
  880.                         if (client)
  881.                                 sendto_one(client, NULL, ":%s FAIL METADATA KEY_NOT_SET %s %s :key not set", me.name, channel->name, key); /* not set so can't remove */
  882.                         return;
  883.                 }
  884.         } else { /* set */
  885.                 utf8_val = safe_alloc(metadata_settings.max_value_bytes + 1);
  886.                 unrl_utf8_make_valid(value, utf8_val, metadata_settings.max_value_bytes, 1);
  887.                 while (*metadata)
  888.                 {
  889.                         if (!strcasecmp(key, (*metadata)->name))
  890.                         {
  891.                                 set = 1;
  892.                                 if (strcmp(value, (*metadata)->value))
  893.                                 {
  894.                                         safe_free((*metadata)->value);
  895.                                         (*metadata)->value = utf8_val;
  896.                                         changed = 1;
  897.                                 }
  898.                         }
  899.                         metadata = &(*metadata)->next;
  900.                         count++;
  901.                 }
  902.                 if (!set)
  903.                 {
  904.                         if (!client || count < metadata_settings.max_channel_metadata)
  905.                         { /* add new entry for user */
  906.                                 *metadata = safe_alloc(sizeof(struct metadata));
  907.                                 (*metadata)->next = NULL;
  908.                                 (*metadata)->name = strdup(key);
  909.                                 (*metadata)->value = utf8_val;
  910.                                 changed = 1;
  911.                         } else
  912.                         { /* no more allowed */
  913.                                 if (client)
  914.                                         sendto_one(client, NULL, ":%s FAIL METADATA LIMIT_REACHED %s :metadata limit reached", me.name, channel->name);
  915.                         }
  916.                 }
  917.                 if (!changed)
  918.                 {
  919.                         safe_free(utf8_val);
  920.                         return;
  921.                 }
  922.         }
  923.         if (IsUser(client) && MyUser(client))
  924.         {
  925.                 if (BadPtr(value))
  926.                         sendnumeric(client, RPL_KEYNOTSET, channel->name, key); /* ok but empty */
  927.                 else
  928.                         sendnumeric(client, RPL_KEYVALUE, channel->name, key, "*", value?value:""); /* all OK */
  929.         }
  930.         if (changed && (IsUser(client) || IsServer(client)))
  931.                 channel_metadata_changed(channel, key, value, client);
  932. }
  933.  
  934. int metadata_subscribe(const char *key, Client *client, int remove)
  935. {
  936.         struct metadata_moddata_user *moddata = USER_METADATA(client);
  937.         struct metadata_subscriptions **subs;
  938.         struct metadata_subscriptions *prev_subs;
  939.         int found = 0;
  940.         int count = 0;
  941.         int trylater = 0;
  942.         const char *value;
  943.         unsigned int hashnum;
  944.         Channel *channel;
  945.         Client *acptr;
  946.         char batch[BATCHLEN+1] = "";
  947.         MessageTag *mtags = NULL;
  948.  
  949.         if (!client)
  950.                 return 0;
  951.        
  952.         if (!moddata) /* first call for this user */
  953.                 moddata = metadata_prepare_user_moddata(client);
  954.         subs = &moddata->subs;
  955.         while (*subs)
  956.         {
  957.                 count++;
  958.                 if (!strcasecmp(key, (*subs)->name))
  959.                 {
  960.                         found = 1;
  961.                         if (remove)
  962.                         {
  963.                                 prev_subs = *subs;
  964.                                 *subs = prev_subs->next;
  965.                                 metadata_free_subs(prev_subs);
  966.                         }
  967.                         break;
  968.                 }
  969.                 subs = &(*subs)->next;
  970.         }
  971.         if (!remove && !found)
  972.         {
  973.                 if (count < metadata_settings.max_subscriptions)
  974.                 {
  975.                         *subs = safe_alloc(sizeof(struct metadata_subscriptions));
  976.                         (*subs)->next = NULL;
  977.                         (*subs)->name = strdup(key);
  978.                 } else
  979.                 { /* no more allowed */
  980.                         sendto_one(client, NULL, ":%s FAIL METADATA TOO_MANY_SUBS %s :too many subscriptions", me.name, key);
  981.                         return 0;
  982.                 }
  983.         }
  984.         if (!remove)
  985.         {
  986.                 MAKE_BATCH(client, batch, mtags);
  987.                 sendnumeric_mtags(client, mtags, RPL_METADATASUBOK, key);
  988.                 if(!IsUser(client))
  989.                         return 0; /* unregistered user is not getting any keys yet */
  990.                 /* we have to send out all subscribed data now */
  991.                 trylater = 0;
  992.                 list_for_each_entry(acptr, &client_list, client_node)
  993.                 {
  994.                         value = NULL;
  995.                         if (IsUser(client) && IsUser(acptr) && has_common_channels(acptr, client))
  996.                                 value = metadata_get_user_key_value(acptr, key);
  997.                         if (value)
  998.                                 trylater |= metadata_notify_or_queue(client, mtags, acptr->name, key, value, NULL);
  999.                 }
  1000.                 for (hashnum = 0; hashnum < CHAN_HASH_TABLE_SIZE; hashnum++)
  1001.                 {
  1002.                         for (channel = hash_get_chan_bucket(hashnum); channel; channel = channel->hnextch)
  1003.                         {
  1004.                                 if (IsMember(client, channel))
  1005.                                 {
  1006.                                         value = metadata_get_channel_key_value(channel, key);
  1007.                                         if (value)
  1008.                                                 trylater |= metadata_notify_or_queue(client, mtags, channel->name, key, value, NULL);
  1009.                                 }
  1010.                         }
  1011.                 }
  1012.                 FINISH_BATCH(client, batch, mtags);
  1013.                 if (trylater)
  1014.                         return 1;
  1015.         } else
  1016.         {
  1017.                 sendnumeric(client, RPL_METADATAUNSUBOK, key); 
  1018.         }
  1019.         return 0;
  1020. }
  1021.  
  1022. void metadata_send_channel(Channel *channel, const char *key, Client *client, MessageTag *mtags)
  1023. {
  1024.         struct metadata *metadata;
  1025.         int found = 0;
  1026.         char batch[BATCHLEN+1] = "";
  1027.         int parent_mtags = !!mtags;
  1028.         if (!parent_mtags)
  1029.                 MAKE_BATCH(client, batch, mtags);
  1030.         for (metadata = CHANNEL_METADATA(channel); metadata; metadata = metadata->next)
  1031.         {
  1032.                 if (!strcasecmp(key, metadata->name))
  1033.                 {
  1034.                         found = 1;
  1035.                         sendnumeric_mtags(client, mtags, RPL_KEYVALUE, channel->name, key, "*", metadata->value);
  1036.                         break;
  1037.                 }
  1038.         }
  1039.         if (!found)
  1040.                 sendnumeric_mtags(client, mtags, RPL_KEYNOTSET, channel->name, key);
  1041.         if (!parent_mtags)
  1042.                 FINISH_BATCH(client, batch, mtags);
  1043. }
  1044.  
  1045. void metadata_send_user(Client *user, const char *key, Client *client, MessageTag *mtags)
  1046. {
  1047.         if (!user)
  1048.                 user = client;
  1049.         struct metadata_moddata_user *moddata = USER_METADATA(user);
  1050.         struct metadata *metadata = NULL;
  1051.         char batch[BATCHLEN+1] = "";
  1052.         int parent_mtags = !!mtags;
  1053.         if (!parent_mtags)
  1054.                 MAKE_BATCH(client, batch, mtags);
  1055.         if (moddata)
  1056.                 metadata = moddata->metadata;
  1057.         int found = 0;
  1058.         for ( ; metadata; metadata = metadata->next)
  1059.         {
  1060.                 if (!strcasecmp(key, metadata->name))
  1061.                 {
  1062.                         found = 1;
  1063.                         sendnumeric_mtags(client, mtags, RPL_KEYVALUE, user->name, key, "*", metadata->value);
  1064.                         break;
  1065.                 }
  1066.         }
  1067.         if (!found)
  1068.                 sendnumeric_mtags(client, mtags, RPL_KEYNOTSET, user->name, key);
  1069.         if (!parent_mtags)
  1070.                 FINISH_BATCH(client, batch, mtags);
  1071. }
  1072.  
  1073. void metadata_clear_channel(Channel *channel, Client *client)
  1074. {
  1075.         struct metadata *metadata = CHANNEL_METADATA(channel);
  1076.         metadata_free_list(metadata, channel->name, client);
  1077.         CHANNEL_METADATA(channel) = NULL;
  1078. }
  1079.  
  1080. void metadata_clear_user(Client *user, Client *client)
  1081. {
  1082.         if (!user)
  1083.                 user = client;
  1084.         struct metadata_moddata_user *moddata = USER_METADATA(user);
  1085.         struct metadata *metadata = NULL;
  1086.         if (!moddata)
  1087.                 return; /* nothing to delete */
  1088.         metadata = moddata->metadata;
  1089.         metadata_free_list(metadata, user->name, client);
  1090.         moddata->metadata = NULL;
  1091. }
  1092.  
  1093. void metadata_send_subscribtions(Client *client)
  1094. {
  1095.         struct metadata_subscriptions *subs;
  1096.         struct metadata_moddata_user *moddata = USER_METADATA(client);
  1097.         char batch[BATCHLEN+1] = "";
  1098.         MessageTag *mtags = NULL;
  1099.        
  1100.         MAKE_BATCH(client, batch, mtags);
  1101.  
  1102.         if (moddata) {
  1103.                 for (subs = moddata->subs; subs; subs = subs->next)
  1104.                         sendnumeric_mtags(client, mtags, RPL_METADATASUBS, subs->name);
  1105.         }
  1106.        
  1107.         FINISH_BATCH(client, batch, mtags);
  1108. }
  1109.  
  1110. void metadata_send_all_for_channel(Channel *channel, Client *client)
  1111. {
  1112.         struct metadata *metadata;
  1113.         char batch[BATCHLEN+1] = "";
  1114.         MessageTag *mtags = NULL;
  1115.         MAKE_BATCH(client, batch, mtags);
  1116.         for (metadata = CHANNEL_METADATA(channel); metadata; metadata = metadata->next)
  1117.                 sendnumeric_mtags(client, mtags, RPL_KEYVALUE, channel->name, metadata->name, "*", metadata->value);
  1118.         FINISH_BATCH(client, batch, mtags);
  1119. }
  1120.  
  1121. void metadata_send_all_for_user(Client *user, Client *client)
  1122. {
  1123.         struct metadata *metadata;
  1124.         char batch[BATCHLEN+1] = "";
  1125.         MessageTag *mtags = NULL;
  1126.         if (!user)
  1127.                 user = client;
  1128.         struct metadata_moddata_user *moddata = USER_METADATA(user);
  1129.         MAKE_BATCH(client, batch, mtags);
  1130.         if (moddata) {
  1131.                 for (metadata = moddata->metadata; metadata; metadata = metadata->next)
  1132.                         sendnumeric_mtags(client, mtags, RPL_KEYVALUE, user->name, metadata->name, "*", metadata->value);
  1133.         }
  1134.         FINISH_BATCH(client, batch, mtags);
  1135. }
  1136.  
  1137. int metadata_key_valid(const char *key)
  1138. {
  1139.         for( ; *key; key++)
  1140.         {
  1141.                 if(*key >= 'a' && *key <= 'z')
  1142.                         continue;
  1143.                 if(*key >= 'A' && *key <= 'Z')
  1144.                         continue;
  1145.                 if(*key >= '0' && *key <= '9')
  1146.                         continue;
  1147.                 if(*key == '_' || *key == '.' || *key == ':' || *key == '-')
  1148.                         continue;
  1149.                 return 0;
  1150.         }
  1151.         return 1;
  1152. }
  1153.  
  1154. int metadata_check_perms(Client *user, Channel *channel, Client *client, const char *key, int mode)
  1155. { /* either user or channel should be NULL */
  1156.         if (!IsUser(client) && channel) /* ignore channel metadata requests for unregistered users */
  1157.                 return 0;
  1158.         if ((user == client) || (!user && !channel)) /* specified target is "*" or own nick */
  1159.                 return 1;
  1160.         if (IsOper(client) && mode == MODE_GET)
  1161.                 return 1; /* allow ircops to view everything */
  1162.         if (channel)
  1163.         {
  1164.                 /* The only requirement for GET is to be in the channel */
  1165.                 if ((mode == MODE_GET) && IsMember(client, channel))
  1166.                         return 1;
  1167.                 /* Otherwise, +hoaq */
  1168.                 if (check_channel_access(client, channel, "hoaq"))
  1169.                         return 1;
  1170.         } else if (user)
  1171.         {
  1172.                 if (mode == MODE_SET)
  1173.                 {
  1174.                         if (user == client)
  1175.                                 return 1;
  1176.                 } else if (mode == MODE_GET)
  1177.                 {
  1178.                         if(has_common_channels(user, client))
  1179.                                 return 1;
  1180.                 }
  1181.                
  1182.         }
  1183.         if (key)
  1184.                 sendto_one(client, NULL, ":%s FAIL METADATA KEY_NO_PERMISSION %s %s :permission denied", me.name, user?user->name:channel->name, key);
  1185.         return 0;
  1186. }
  1187.  
  1188. /* METADATA <Target> <Subcommand> [<Param 1> ... [<Param n>]] */
  1189. CMD_FUNC(cmd_metadata_local)
  1190. {
  1191.         Channel *channel = NULL;
  1192.         Client *user = NULL;
  1193.         const char *target;
  1194.         const char *cmd;
  1195.         const char *key;
  1196.         const char *value = NULL;
  1197.         int keyindex = 3-1;
  1198.         char *channame;
  1199.         MessageTag *batch_mtags = NULL;
  1200.         char batch[BATCHLEN+1] = "";
  1201.        
  1202.         CHECKPARAMSCNT_OR_DIE(2, return);
  1203.  
  1204.         target = parv[1];
  1205.         cmd = parv[2];
  1206.  
  1207.         if (!strcasecmp(cmd, "GET"))
  1208.         {
  1209.                 CHECKREGISTERED_OR_DIE(client, return);
  1210.                 CHECKPARAMSCNT_OR_DIE(3, return);
  1211.                 PROCESS_TARGET_OR_DIE(target, user, channel, return);
  1212.                 MAKE_BATCH(client, batch, batch_mtags);
  1213.                 FOR_EACH_KEY(keyindex, parc, parv)
  1214.                 {
  1215.                         if (metadata_check_perms(user, channel, client, key, MODE_GET))
  1216.                         {
  1217.                                 if (!metadata_key_valid(key))
  1218.                                 {
  1219.                                         sendto_one(client, batch_mtags, ":%s FAIL METADATA KEY_INVALID %s :invalid key", me.name, key);
  1220.                                         continue;
  1221.                                 }
  1222.                                 if (channel)
  1223.                                         metadata_send_channel(channel, key, client, batch_mtags);
  1224.                                 else
  1225.                                         metadata_send_user(user, key, client, batch_mtags);
  1226.                         }
  1227.                 }
  1228.                 FINISH_BATCH(client, batch, batch_mtags);
  1229.         } else if (!strcasecmp(cmd, "LIST"))
  1230.         { /* we're just not sending anything if there are no permissions */
  1231.                 CHECKREGISTERED_OR_DIE(client, return);
  1232.                 PROCESS_TARGET_OR_DIE(target, user, channel, return);
  1233.                 if (metadata_check_perms(user, channel, client, NULL, MODE_GET))
  1234.                 {
  1235.                         if (channel)
  1236.                                 metadata_send_all_for_channel(channel, client);
  1237.                         else
  1238.                                 metadata_send_all_for_user(user, client);
  1239.                 }
  1240.         } else if (!strcasecmp(cmd, "SET"))
  1241.         {
  1242.                 CHECKPARAMSCNT_OR_DIE(3, return);
  1243.                 PROCESS_TARGET_OR_DIE(target, user, channel, return);
  1244.                 key = parv[3];
  1245.                 if (!metadata_check_perms(user, channel, client, key, MODE_SET))
  1246.                         return;
  1247.                 if (parc > 3 && !BadPtr(parv[4]))
  1248.                         value = parv[4];
  1249.  
  1250.                 if (!metadata_key_valid(key))
  1251.                 {
  1252.                         sendto_one(client, NULL, ":%s FAIL METADATA KEY_INVALID %s :invalid key", me.name,  key);
  1253.                         return;
  1254.                 }
  1255.  
  1256.                 if (channel)
  1257.                         metadata_set_channel(channel, key, value, client);
  1258.                 else
  1259.                         metadata_set_user(user, key, value, client);
  1260.         } else if (!strcasecmp(cmd, "CLEAR"))
  1261.         {
  1262.                 CHECKREGISTERED_OR_DIE(client, return);
  1263.                 PROCESS_TARGET_OR_DIE(target, user, channel, return);
  1264.                 if (metadata_check_perms(user, channel, client, "*", MODE_SET))
  1265.                 {
  1266.                         if (channel)
  1267.                                 metadata_clear_channel(channel, client);
  1268.                         else
  1269.                                 metadata_clear_user(user, client);
  1270.                 }
  1271.         } else if (!strcasecmp(cmd, "SUB"))
  1272.         {
  1273.                 PROCESS_TARGET_OR_DIE(target, user, channel, return);
  1274.                 CHECKPARAMSCNT_OR_DIE(3, return);
  1275.                 FOR_EACH_KEY(keyindex, parc, parv)
  1276.                 {
  1277.                         if(metadata_key_valid(key))
  1278.                         {
  1279.                                 metadata_subscribe(key, client, 0);
  1280.                         } else
  1281.                         {
  1282.                                 sendto_one(client, NULL, ":%s FAIL METADATA KEY_INVALID %s :invalid key", me.name,  key);
  1283.                                 continue;
  1284.                         }
  1285.                 }
  1286.         } else if (!strcasecmp(cmd, "UNSUB"))
  1287.         {
  1288.                 CHECKREGISTERED_OR_DIE(client, return);
  1289.                 CHECKPARAMSCNT_OR_DIE(3, return);
  1290.                 int subok = 0;
  1291.                 FOR_EACH_KEY(keyindex, parc, parv)
  1292.                 {
  1293.                         if(metadata_key_valid(key))
  1294.                         {
  1295.                                 metadata_subscribe(key, client, 1);
  1296.                         } else
  1297.                         {
  1298.                                 sendto_one(client, NULL, ":%s FAIL METADATA KEY_INVALID %s :invalid key", me.name,  key);
  1299.                                 continue;
  1300.                         }
  1301.                 }
  1302.         } else if (!strcasecmp(cmd, "SUBS"))
  1303.         {
  1304.                 CHECKREGISTERED_OR_DIE(client, return);
  1305.                 metadata_send_subscribtions(client);
  1306.         } else if (!strcasecmp(cmd, "SYNC"))
  1307.         { /* the client requested re-sending of all subbed metadata */
  1308.                 CHECKREGISTERED_OR_DIE(client, return);
  1309.                 PROCESS_TARGET_OR_DIE(target, user, channel, return);
  1310.                 if (channel)
  1311.                         metadata_sync_channel(client, channel);
  1312.                 else
  1313.                         metadata_sync_user(client, user, NULL, 1);
  1314.         } else
  1315.         {
  1316.                 sendto_one(client, NULL, ":%s FAIL METADATA SUBCOMMAND_INVALID %s :invalid subcommand", me.name,  cmd);
  1317.         }
  1318. }
  1319.  
  1320. /* format of S2S is same as the event: ":origin METADATA <client/channel> <key name> *[ :<key value>]" */
  1321. CMD_FUNC(cmd_metadata_remote)
  1322. { /* handling data from linked server */
  1323.         Channel *channel = NULL;
  1324.         Client *user = NULL;
  1325.         const char *target;
  1326.         const char *key;
  1327.         const char *value;
  1328.         const char *channame;
  1329.  
  1330.         if (parc < 5 || BadPtr(parv[4]))
  1331.         {
  1332.                 if (parc == 4 && !BadPtr(parv[3]))
  1333.                 {
  1334.                         value = NULL;
  1335.                 } else
  1336.                 {
  1337.                         unreal_log(ULOG_DEBUG, "metadata", "METADATA_DEBUG", client, "METADATA S2S: not enough args from $sender",
  1338.                                 log_data_string("sender", client->name));
  1339.                         return;
  1340.                 }
  1341.         } else
  1342.         {
  1343.                 value = parv[4];
  1344.         }
  1345.  
  1346.         target = parv[1];
  1347.         key = parv[2];
  1348.         channame = strchr(target, '#');
  1349.  
  1350.         if (!*target || !strcmp(target, "*") || !metadata_key_valid(key))
  1351.         {
  1352.                 unreal_log(ULOG_DEBUG, "metadata", "METADATA_DEBUG", client, "METADATA S2S: bad metadata target $target or key $key from $sender",
  1353.                         log_data_string("target", target),
  1354.                         log_data_string("key", key),
  1355.                         log_data_string("sender", client->name));
  1356.                 return;
  1357.         }
  1358.         PROCESS_TARGET_OR_DIE(target, user, channel, return);
  1359.  
  1360.         if(channel)
  1361.         {
  1362.                 metadata_set_channel(channel, key, value, client);
  1363.         } else
  1364.         {
  1365.                 metadata_set_user(user, key, value, client);
  1366.         }
  1367. }
  1368.  
  1369. CMD_FUNC(cmd_metadata)
  1370. {
  1371.         if (client != &me && MyConnect(client) && !IsServer(client))
  1372.                 cmd_metadata_local(client, recv_mtags, parc, parv);
  1373.         else
  1374.                 cmd_metadata_remote(client, recv_mtags, parc, parv);
  1375. }
  1376.  
  1377. int metadata_server_sync(Client *client)
  1378. { /* we send all our data to the server that was just linked */
  1379.         Client *acptr;
  1380.         struct metadata_moddata_user *moddata;
  1381.         struct metadata *metadata;
  1382.         unsigned int  hashnum;
  1383.         Channel *channel;
  1384.        
  1385.         list_for_each_entry(acptr, &client_list, client_node)
  1386.         { /* send out users (all on our side of the link) */
  1387.                 moddata = USER_METADATA(acptr);
  1388.                 if(!moddata)
  1389.                         continue;
  1390.                 for (metadata = moddata->metadata; metadata; metadata = metadata->next)
  1391.                         metadata_send_change(client, NULL, acptr->name, metadata->name, metadata->value, &me);
  1392.         }
  1393.  
  1394.         for (hashnum = 0; hashnum < CHAN_HASH_TABLE_SIZE; hashnum++)
  1395.         { /* send out channels */
  1396.                 for(channel = hash_get_chan_bucket(hashnum); channel; channel = channel->hnextch)
  1397.                 {
  1398.                         for(metadata = CHANNEL_METADATA(channel); metadata; metadata = metadata->next)
  1399.                                 metadata_send_change(client, NULL, channel->name, metadata->name, metadata->value, &me);
  1400.                 }
  1401.         }
  1402.         return 0;
  1403. }
  1404.  
  1405. int metadata_join(Client *client, Channel *channel, MessageTag *join_mtags)
  1406. {
  1407.         Client *acptr;
  1408.         Member *cm;
  1409.         const char *value;
  1410.         struct metadata_unsynced *prev_us;
  1411.         struct metadata_unsynced *us;
  1412.         Membership *lp;
  1413.         struct metadata_subscriptions *subs;
  1414.         struct metadata *metadata;
  1415.         char batch[BATCHLEN+1] = "";
  1416.         MessageTag *batch_mtags = NULL;
  1417.  
  1418.         struct metadata_moddata_user *moddata = USER_METADATA(client);
  1419.         if(!moddata)
  1420.                 return 0; /* the user is both not subscribed to anything and has no own data */
  1421.         for (metadata = moddata->metadata; metadata; metadata = metadata->next)
  1422.         { /* if joining user has metadata, let's notify all subscribers */
  1423.                 list_for_each_entry(acptr, &lclient_list, lclient_node)
  1424.                 {
  1425.                         if(IsMember(acptr, channel) && metadata_is_subscribed(acptr, metadata->name))
  1426.                                 metadata_notify_or_queue(acptr, NULL, client->name, metadata->name, metadata->value, NULL);
  1427.                 }
  1428.         }
  1429.         MAKE_BATCH(client, batch, batch_mtags);
  1430.         for (subs = moddata->subs; subs; subs = subs->next)
  1431.         {
  1432.                 value = metadata_get_channel_key_value(channel, subs->name); /* notify joining user about channel metadata */
  1433.                 if(value)
  1434.                         metadata_notify_or_queue(client, batch_mtags, channel->name, subs->name, value, NULL);
  1435.                 for (cm = channel->members; cm; cm = cm->next)
  1436.                 { /* notify joining user about other channel members' metadata */
  1437.                         acptr = cm->client;
  1438.                         if (acptr == client)
  1439.                                 continue; /* ignore own data */
  1440.                         if (has_common_channels(acptr, client))
  1441.                                 continue; /* already seen elsewhere */
  1442.                         value = metadata_get_user_key_value(acptr, subs->name);
  1443.                         if (value)
  1444.                                 metadata_notify_or_queue(client, batch_mtags, acptr->name, subs->name, value, NULL);
  1445.                 }
  1446.         }
  1447.         FINISH_BATCH(client, batch, batch_mtags);
  1448.         return 0;
  1449. }
  1450.  
  1451. void metadata_send_pending(Client *client)
  1452. {
  1453.         Client *acptr = NULL;
  1454.         Channel *channel = NULL;
  1455.         int do_send = 0;
  1456.         char *who;
  1457.         char batch[BATCHLEN+1] = "";
  1458.         MessageTag *mtags = NULL;
  1459.  
  1460.         struct metadata_moddata_user *my_moddata = USER_METADATA(client);
  1461.         if (!my_moddata)
  1462.                 return; /* nothing queued */
  1463.         struct metadata_unsynced *us = my_moddata->us;
  1464.         struct metadata_unsynced *prev_us;
  1465.  
  1466.         if (us)
  1467.                 MAKE_BATCH(client, batch, mtags);
  1468.  
  1469.         while (us)
  1470.         {
  1471.                 if (!IsSendable(client))
  1472.                         break;
  1473.                 if (*us->id == '#') {
  1474.                         channel = find_channel(us->id);
  1475.                         if (channel && IsMember(client, channel)) {
  1476.                                 do_send = 1;
  1477.                                 who = us->id;
  1478.                         }
  1479.                 } else {
  1480.                         acptr = find_client(us->id, NULL);
  1481.                         if (acptr && has_common_channels(acptr, client)) { /* if not, the user has vanished since or one of us parted the channel */
  1482.                                 do_send = 1;
  1483.                                 who = acptr->name;
  1484.                         }
  1485.                 }
  1486.  
  1487.                 if (do_send) {
  1488.                         struct metadata_moddata_user *moddata;
  1489.                         if (acptr)
  1490.                                 moddata = USER_METADATA(acptr);
  1491.                         else
  1492.                                 moddata = CHANNEL_METADATA(channel);
  1493.                         if (moddata)
  1494.                         {
  1495.                                 struct metadata *metadata = moddata->metadata;
  1496.                                 while (metadata)
  1497.                                 {
  1498.                                         if (!strcasecmp(us->key, metadata->name))
  1499.                                         { /* has it */
  1500.                                                 const char *value = metadata_get_user_key_value(acptr, us->key);
  1501.                                                 if(value)
  1502.                                                         metadata_send_change(client, mtags, who, us->key, value, NULL);
  1503.                                         }
  1504.                                         metadata = metadata->next;
  1505.                                 }
  1506.                         }
  1507.                 }
  1508.                 /* now remove the processed entry */
  1509.                 prev_us = us;
  1510.                 us = us->next;
  1511.                 safe_free(prev_us->id);
  1512.                 safe_free(prev_us);
  1513.                 my_moddata->us = us; /* we're always removing the first list item */
  1514.         }
  1515.  
  1516.         FINISH_BATCH(client, batch, mtags);
  1517. }
  1518.  
  1519. int metadata_user_registered(Client *client)
  1520. {       /*      if we have any metadata set at this point, let's broadcast it to other servers and users */
  1521.         struct metadata *metadata;
  1522.         struct metadata_moddata_user *moddata = USER_METADATA(client);
  1523.         if(!moddata)
  1524.                 return HOOK_CONTINUE;
  1525.         for (metadata = moddata->metadata; metadata; metadata = metadata->next)
  1526.                 user_metadata_changed(client, metadata->name, metadata->value, client);
  1527.         return HOOK_CONTINUE;
  1528. }
  1529.  
  1530. void metadata_sync_user(Client *client, Client *target, MessageTag *mtags, int create_batch) {
  1531.         char batch[BATCHLEN+1] = "";
  1532.         struct metadata_subscriptions *subs;
  1533.         struct metadata *metadata;
  1534.         int parent_mtags = 0;
  1535.         Client *acptr;
  1536.        
  1537.         if (mtags)
  1538.                 parent_mtags = 1;
  1539.  
  1540.         struct metadata_moddata_user *moddata = USER_METADATA(target);
  1541.  
  1542.         if (!parent_mtags && create_batch)
  1543.                 MAKE_BATCH(client, batch, mtags);
  1544.  
  1545.         if (moddata) { /* the user is either subscribed to something (this is not interesting to us) or has some own data */
  1546.                 for (metadata = moddata->metadata; metadata; metadata = metadata->next)
  1547.                 {              
  1548.                         if(metadata_is_subscribed(client, metadata->name))
  1549.                                 metadata_notify_or_queue(client, mtags, target->name, metadata->name, metadata->value, NULL);
  1550.                 }
  1551.         }
  1552.  
  1553.         if (!parent_mtags)
  1554.                 FINISH_BATCH(client, batch, mtags);
  1555. }
  1556.  
  1557. void metadata_sync_channel(Client *client, Channel *channel) {
  1558.         MessageTag *mtags = NULL;
  1559.         char batch[BATCHLEN+1] = "";
  1560.         Member *cm;
  1561.         struct metadata_subscriptions *subs;
  1562.         const char *value;
  1563.         struct metadata_moddata_user *moddata = USER_METADATA(client);
  1564.  
  1565.         MAKE_BATCH(client, batch, mtags);
  1566.  
  1567.         if (moddata)
  1568.         {
  1569.                 for (subs = moddata->subs; subs; subs = subs->next)
  1570.                 {
  1571.                         value = metadata_get_channel_key_value(channel, subs->name); /* channel metadata notification */
  1572.                         if(value)
  1573.                                 metadata_notify_or_queue(client, mtags, channel->name, subs->name, value, NULL);
  1574.                 }
  1575.                 for (cm = channel->members; cm; cm = cm->next) /* notify about all channel members' metadata (including the query source) */
  1576.                         metadata_sync_user(client, cm->client, mtags, 0);
  1577.         }
  1578.  
  1579.         FINISH_BATCH(client, batch, mtags);
  1580. }
  1581.  
  1582. EVENT(metadata_queue_evt)
  1583. { /* let's check every 1.5 seconds whether we have something to send */
  1584.         Client *acptr;
  1585.         list_for_each_entry(acptr, &lclient_list, lclient_node)
  1586.         { /* notifications for local subscribers */
  1587.                 if (!IsUser(acptr))
  1588.                         continue;
  1589.                 metadata_send_pending(acptr);
  1590.         }
  1591. }
  1592.  
  1593. int metadata_monitor_connect(Client *client) {
  1594.         watch_check(client, WATCH_EVENT_ONLINE, metadata_monitor_notification);
  1595.         return 0;
  1596. }
  1597.  
  1598. int metadata_monitor_notification(Client *client, Watch *watch, Link *lp, int event)
  1599. {
  1600.         if (!(lp->flags & WATCH_FLAG_TYPE_MONITOR))
  1601.                 return 0;
  1602.         if (!HasCapabilityFast(lp->value.client, CAP_METADATA_NOTIFY))
  1603.                 return 0;
  1604.  
  1605.         switch (event)
  1606.         {
  1607.                 case WATCH_EVENT_ONLINE:
  1608.                 case WATCH_EVENT_METADATA:
  1609.                         metadata_sync_user(lp->value.client, client, NULL, 0);
  1610.                         break;
  1611.                 default:
  1612.                         break; /* may be handled by other modules */
  1613.         }
  1614.        
  1615.         return 0;
  1616. }
  1617.  

odpowiedź "Bez tytułu"

Tutaj możesz odpowiedzieć na wklejkę z góry

captcha