}
}
-static int\r
-add_target(struct Client *source_p, struct Client *target_p)\r
-{\r
- unsigned int i, j;\r
- /* messaging themselves, doesnt incur any penalties */\r
- if(source_p == target_p)\r
- return 1;\r
-\r
- if(USED_TARGETS(source_p))\r
- {\r
- /* hunt for an existing target */\r
- for(i = PREV_FREE_TARGET(source_p), j = USED_TARGETS(source_p);\r
- j;\r
- --j, PREV_TARGET(i))\r
- {\r
- if(source_p->localClient->targets[i] == target_p)\r
- return 1;\r
- }\r
-\r
- /* first message after connect, we may only start clearing\r
- * slots after this message --anfl\r
- */\r
- if(!IsTGChange(source_p))\r
- {\r
- SetTGChange(source_p);\r
- source_p->localClient->target_last = rb_current_time();\r
- }\r
- /* clear as many targets as we can */\r
- else if((i = (rb_current_time() - source_p->localClient->target_last) / 60))\r
- {\r
- if(i > USED_TARGETS(source_p))\r
- USED_TARGETS(source_p) = 0;\r
- else\r
- USED_TARGETS(source_p) -= i;\r
-\r
- source_p->localClient->target_last = rb_current_time();\r
- }\r
- /* cant clear any, full target list */\r
- else if(USED_TARGETS(source_p) == 10)\r
- {\r
- add_tgchange(source_p->sockhost);\r
- return 0;\r
- }\r
- }\r
- /* no targets in use, reset their target_last so that they cant\r
- * abuse a long idle to get targets back more quickly\r
- */\r
- else\r
- {\r
- source_p->localClient->target_last = rb_current_time();\r
- SetTGChange(source_p);\r
- }\r
-\r
- source_p->localClient->targets[FREE_TARGET(source_p)] = target_p;\r
- NEXT_TARGET(FREE_TARGET(source_p));\r
- ++USED_TARGETS(source_p);\r
- return 1;\r
+static int
+add_target(struct Client *source_p, struct Client *target_p)
+{
+ int i, j;
+ uint32_t hashv;
+
+ /* can msg themselves or services without using any target slots */
+ if(source_p == target_p || IsService(target_p))
+ return 1;
+
+ /* special condition for those who have had PRIVMSG crippled to allow them
+ * to talk to IRCops still.
+ *
+ * XXX: is this controversial?
+ */
+ if(source_p->localClient->target_last > rb_current_time() && IsOper(target_p))
+ return 1;
+
+ hashv = fnv_hash_upper((const unsigned char *)use_id(target_p), 32);
+
+ if(USED_TARGETS(source_p))
+ {
+ /* hunt for an existing target */
+ for(i = PREV_FREE_TARGET(source_p), j = USED_TARGETS(source_p);
+ j; --j, PREV_TARGET(i))
+ {
+ if(source_p->localClient->targets[i] == hashv)
+ return 1;
+ }
+
+ /* first message after connect, we may only start clearing
+ * slots after this message --anfl
+ */
+ if(!IsTGChange(source_p))
+ {
+ SetTGChange(source_p);
+ source_p->localClient->target_last = rb_current_time();
+ }
+ /* clear as many targets as we can */
+ else if((i = (rb_current_time() - source_p->localClient->target_last) / 60))
+ {
+ if(i > USED_TARGETS(source_p))
+ USED_TARGETS(source_p) = 0;
+ else
+ USED_TARGETS(source_p) -= i;
+
+ source_p->localClient->target_last = rb_current_time();
+ }
+ /* cant clear any, full target list */
+ else if(USED_TARGETS(source_p) == 10)
+ {
+ ServerStats.is_tgch++;
+ add_tgchange(source_p->sockhost);
+ return 0;
+ }
+ }
+ /* no targets in use, reset their target_last so that they cant
+ * abuse a long idle to get targets back more quickly
+ */
+ else
+ {
+ source_p->localClient->target_last = rb_current_time();
+ SetTGChange(source_p);
+ }
+
+ source_p->localClient->targets[FREE_TARGET(source_p)] = hashv;
+ NEXT_TARGET(FREE_TARGET(source_p));
+ ++USED_TARGETS(source_p);
+ return 1;
}
/*