Bez tytułu

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

odpowiedź "Bez tytułu"

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

captcha