]>
jfr.im git - irc/quakenet/newserv.git/blob - localuser/localuserchannel.c
1 /* Functions for manipulating local users on channels */
4 #include "localuserchannel.h"
5 #include "../nick/nick.h"
6 #include "../channel/channel.h"
7 #include "../irc/irc.h"
8 #include "../lib/version.h"
15 MODULE_VERSION("$Id: localuserchannel.c 663 2006-05-16 17:27:36Z newserv $")
17 int handlechannelmsgcmd(void *source
, int cargc
, char **cargv
);
18 int handlechannelnoticecmd(void *source
, int cargc
, char **cargv
);
19 int handleinvitecmd(void *source
, int cargc
, char **cargv
);
20 void luc_handlekick(int hooknum
, void *arg
);
23 registerserverhandler("P",&handlechannelmsgcmd
,2);
24 registerserverhandler("O",&handlechannelnoticecmd
,2);
25 registerserverhandler("I",&handleinvitecmd
,2);
26 registerhook(HOOK_CHANNEL_KICK
, luc_handlekick
);
30 deregisterserverhandler("P",&handlechannelmsgcmd
);
31 deregisterserverhandler("O",&handlechannelnoticecmd
);
32 deregisterserverhandler("I",&handleinvitecmd
);
33 deregisterhook(HOOK_CHANNEL_KICK
, luc_handlekick
);
36 void luc_handlekick(int hooknum
, void *arg
) {
41 if (homeserver(target
->numeric
)!=mylongnum
)
44 if (umhandlers
[target
->numeric
& MAXLOCALUSER
]) {
49 (umhandlers
[target
->numeric
& MAXLOCALUSER
])(target
, LU_KICKED
, myargs
);
53 /* invites look something like:
54 * XXyyy I TargetNick :#channel
57 int handleinvitecmd(void *source
, int cargc
, char **cargv
) {
67 if (!(sender
=getnickbynumericstr(source
))) {
68 Error("localuserchannel",ERR_WARNING
,"Got invite from unknown numeric %s.",source
);
72 if (!(target
=getnickbynick(cargv
[0]))) {
73 Error("localuserchannel",ERR_WARNING
,"Got invite for unknown local user %s.",cargv
[0]);
77 if (!(cp
=findchannel(cargv
[1]))) {
78 Error("localuserchannel",ERR_WARNING
,"Got invite for non-existent channel %s.",cargv
[1]);
82 if (homeserver(target
->numeric
) != mylongnum
) {
83 Error("localuserchannel",ERR_WARNING
,"Got invite for non-local user %s.",target
->nick
);
87 /* This is a valid race condition.. */
88 if (getnumerichandlefromchanhash(cp
->users
, target
->numeric
)) {
89 Error("localuserchannel",ERR_DEBUG
,"Got invite for user %s already on %s.",target
->nick
, cp
->index
->name
->content
);
93 nargs
[0]=(void *)sender
;
96 if (umhandlers
[target
->numeric
&MAXLOCALUSER
]) {
97 (umhandlers
[target
->numeric
&MAXLOCALUSER
])(target
, LU_INVITE
, nargs
);
103 int handlechannelmsgcmd(void *source
, int cargc
, char **cargv
) {
108 unsigned long numeric
;
116 if (cargv
[0][0]!='#' && cargv
[0][0]!='+') {
117 /* Not a channel message */
121 if ((sender
=getnickbynumericstr((char *)source
))==NULL
) {
122 Error("localuserchannel",ERR_DEBUG
,"PRIVMSG from non existant user %s",(char *)source
);
126 if ((target
=findchannel(cargv
[0]))==NULL
) {
127 Error("localuserchannel",ERR_DEBUG
,"PRIVMSG to non existant channel %s",cargv
[0]);
131 /* OK, we have a valid channel the message was sent to. Let's look to see
132 * if we have any local users on there. Set up the arguments first as they are
133 * always going to be the same. */
135 nargs
[0]=(void *)sender
;
136 nargs
[1]=(void *)target
;
137 nargs
[2]=(void *)cargv
[1];
139 for (found
=0,i
=0;i
<target
->users
->hashsize
;i
++) {
140 numeric
=target
->users
->content
[i
];
141 if (numeric
!=nouser
&& homeserver(numeric
&CU_NUMERICMASK
)==mylongnum
) {
142 /* OK, it's one of our users.. we need to deal with it */
144 if (umhandlers
[numeric
&MAXLOCALUSER
]) {
145 if ((np
=getnickbynumeric(numeric
))==NULL
) {
146 Error("localuserchannel",ERR_ERROR
,"PRIVMSG to channel user who doesn't exist (?) on %s",cargv
[0]);
150 (umhandlers
[numeric
&MAXLOCALUSER
])(np
,LU_CHANMSG
,nargs
);
159 Error("localuserchannel",ERR_DEBUG
,"Couldn't find any local targets for PRIVMSG to %s",cargv
[0]);
166 * Added by Cruicky so S2 can receive channel notices
167 * Shameless rip of the above with s/privmsg/notice
169 int handlechannelnoticecmd(void *source
, int cargc
, char **cargv
) {
174 unsigned long numeric
;
182 if (cargv
[0][0]!='#' && cargv
[0][0]!='+') {
183 /* Not a channel notice */
187 if ((sender
=getnickbynumericstr((char *)source
))==NULL
) {
188 Error("localuserchannel",ERR_DEBUG
,"NOTICE from non existant user %s",(char *)source
);
192 if ((target
=findchannel(cargv
[0]))==NULL
) {
193 Error("localuserchannel",ERR_DEBUG
,"NOTICE to non existant channel %s",cargv
[0]);
197 /* OK, we have a valid channel the notice was sent to. Let's look to see
198 * if we have any local users on there. Set up the arguments first as they are
199 * always going to be the same. */
201 nargs
[0]=(void *)sender
;
202 nargs
[1]=(void *)target
;
203 nargs
[2]=(void *)cargv
[1];
205 for (found
=0,i
=0;i
<target
->users
->hashsize
;i
++) {
206 numeric
=target
->users
->content
[i
];
207 if (numeric
!=nouser
&& homeserver(numeric
&CU_NUMERICMASK
)==mylongnum
) {
208 /* OK, it's one of our users.. we need to deal with it */
210 if (umhandlers
[numeric
&MAXLOCALUSER
]) {
211 if ((np
=getnickbynumeric(numeric
))==NULL
) {
212 Error("localuserchannel",ERR_ERROR
,"NOTICE to channel user who doesn't exist (?) on %s",cargv
[0]);
216 (umhandlers
[numeric
&MAXLOCALUSER
])(np
,LU_CHANNOTICE
,nargs
);
225 Error("localuserchannel",ERR_DEBUG
,"Couldn't find any local targets for NOTICE to %s",cargv
[0]);
231 int localjoinchannel(nick
*np
, channel
*cp
) {
234 if (cp
==NULL
|| np
==NULL
) {
238 /* Check that the user _is_ a local one.. */
239 if (homeserver(np
->numeric
)!=mylongnum
) {
243 /* Check that the user isn't on the channel already */
244 if ((getnumerichandlefromchanhash(cp
->users
,np
->numeric
))!=NULL
) {
248 /* OK, join the channel.. */
249 addnicktochannel(cp
,np
->numeric
);
251 /* Trigger the event */
255 triggerhook(HOOK_CHANNEL_JOIN
, harg
);
258 irc_send("%s J %s %lu",longtonumeric(np
->numeric
,5),cp
->index
->name
->content
,cp
->timestamp
);
263 int localpartchannel(nick
*np
, channel
*cp
) {
266 /* Check pointers are valid.. */
267 if (cp
==NULL
|| np
==NULL
) {
268 Error("localuserchannel",ERR_WARNING
,"Trying to part NULL channel or NULL nick (cp=%x,np=%x)",cp
,np
);
272 /* And that user is local.. */
273 if (homeserver(np
->numeric
)!=mylongnum
) {
274 Error("localuserchannel",ERR_WARNING
,"Trying to part remote user %s",np
->nick
);
278 /* Check that user is on channel */
279 if (getnumerichandlefromchanhash(cp
->users
,np
->numeric
)==NULL
) {
280 Error("localuserchannel",ERR_WARNING
,"Trying to part user %s from channel %s it is not on",np
->nick
,cp
->index
->name
->content
);
285 irc_send("%s L %s",longtonumeric(np
->numeric
,5),cp
->index
->name
->content
);
291 triggerhook(HOOK_CHANNEL_PART
,harg
);
293 /* Now leave the channel */
294 delnickfromchannel(cp
,np
->numeric
,1);
299 int localcreatechannel(nick
*np
, char *channame
) {
302 /* Check that the user _is_ a local one.. */
303 if (homeserver(np
->numeric
)!=mylongnum
) {
307 if ((cp
=findchannel(channame
))!=NULL
) {
312 cp
=createchannel(channame
);
313 cp
->timestamp
=getnettime();
315 /* Add the local user to the channel, preopped */
316 addnicktochannel(cp
,(np
->numeric
)|CUMODE_OP
);
319 irc_send("%s C %s %ld",longtonumeric(np
->numeric
,5),cp
->index
->name
->content
,cp
->timestamp
);
322 triggerhook(HOOK_CHANNEL_NEWCHANNEL
,(void *)cp
);
326 int localgetops(nick
*np
, channel
*cp
) {
329 /* Check that the user _is_ a local one.. */
330 if (homeserver(np
->numeric
)!=mylongnum
) {
334 if ((lp
=getnumerichandlefromchanhash(cp
->users
,np
->numeric
))==NULL
) {
338 if (*lp
& CUMODE_OP
) {
347 irc_send("%s M %s +o %s",mynumeric
->content
,cp
->index
->name
->content
,longtonumeric(np
->numeric
,5));
353 int localgetvoice(nick
*np
, channel
*cp
) {
356 /* Check that the user _is_ a local one.. */
357 if (homeserver(np
->numeric
)!=mylongnum
) {
361 if ((lp
=getnumerichandlefromchanhash(cp
->users
,np
->numeric
))==NULL
) {
365 if (*lp
& CUMODE_VOICE
) {
374 irc_send("%s M %s +v %s",mynumeric
->content
,cp
->index
->name
->content
,longtonumeric(np
->numeric
,5));
382 * Initialises the modechanges structure.
385 void localsetmodeinit (modechanges
*changes
, channel
*cp
, nick
*np
) {
388 changes
->changecount
=0;
394 * localdosetmode_ban:
395 * Set or clear a ban on the channel
398 void localdosetmode_ban (modechanges
*changes
, const char *ban
, short dir
) {
399 sstring
*bansstr
=getsstring(ban
,HOSTLEN
+NICKLEN
+USERLEN
+5);
401 /* If we're told to clear a ban that isn't here, do nothing. */
402 if (dir
==MCB_DEL
&& !clearban(changes
->cp
, bansstr
->content
, 1))
405 if (changes
->changecount
>= MAXMODEARGS
)
406 localsetmodeflush(changes
, 0);
408 changes
->changes
[changes
->changecount
].str
=bansstr
;
409 changes
->changes
[changes
->changecount
].flag
='b';
410 changes
->changes
[changes
->changecount
++].dir
=dir
;
413 setban(changes
->cp
, bansstr
->content
);
418 * localdosetmode_key:
419 * Set or clear a key on the channel
422 void localdosetmode_key (modechanges
*changes
, const char *key
, short dir
) {
426 /* Check we have space in the buffer */
427 if (changes
->changecount
>= MAXMODEARGS
)
428 localsetmodeflush(changes
,0);
431 /* Get a copy of the key for use later */
432 keysstr
=getsstring(key
, KEYLEN
);
434 /* Check there isn't a key set/clear in the pipeline already.. */
435 for (i
=0;i
<changes
->changecount
;i
++) {
436 if (changes
->changes
[i
].flag
=='k') {
437 /* There's a change already.. */
438 if (changes
->changes
[i
].dir
==MCB_ADD
) {
439 /* Already an add key change. Here, we just replace the key
440 * we were going to add with this one. Note that we need to
441 * free the current cp->key, and the changes.str */
442 freesstring(changes
->changes
[i
].str
);
443 changes
->changes
[i
].str
=keysstr
;
444 freesstring(changes
->cp
->key
);
445 changes
->cp
->key
=getsstring(key
, KEYLEN
);
446 /* That's it, we're done */
449 /* There was a command to delete key.. we need to flush
450 * this out then add the new key (-k+k isn't valid).
451 * Make sure this gets flushed, then drop through to common code */
452 localsetmodeflush(changes
, 1);
457 /* We got here, so there's no change pending already .. check for key on chan */
458 if (IsKey(changes
->cp
)) {
459 if (sstringcompare(changes
->cp
->key
, keysstr
)) {
460 /* Key is set and different. Need to put -k in and flush changes now */
461 changes
->changes
[changes
->changecount
].str
=changes
->cp
->key
; /* implicit free */
462 changes
->changes
[changes
->changecount
].dir
=MCB_DEL
;
463 changes
->changes
[changes
->changecount
++].flag
='k';
464 localsetmodeflush(changes
, 1); /* Note that this will free the sstring on the channel */
466 /* Key is set and the same: do nothing. */
467 freesstring(keysstr
); /* Don't need this after all */
472 /* If we get here, there's no key on the channel right now and nothing in the buffer to
473 * add or remove one */
475 changes
->cp
->key
=getsstring(key
, KEYLEN
);
477 changes
->changes
[changes
->changecount
].str
=keysstr
;
478 changes
->changes
[changes
->changecount
].dir
=MCB_ADD
;
479 changes
->changes
[changes
->changecount
++].flag
='k';
481 /* We're removing a key.. */
482 /* Only bother if key is set atm */
483 if (IsKey(changes
->cp
)) {
484 ClearKey(changes
->cp
);
485 for(i
=0;i
<changes
->changecount
;i
++) {
486 if (changes
->changes
[i
].flag
=='k') {
487 /* We were already doing something with a key..
488 * it MUST be adding one */
489 assert(changes
->changes
[i
].dir
==MCB_ADD
);
490 /* Just forget the earlier change */
491 freesstring(changes
->changes
[i
].str
);
492 changes
->changecount
--;
493 for (j
=i
;j
<changes
->changecount
;j
++) {
494 changes
->changes
[j
]=changes
->changes
[j
+1];
496 /* Explicitly free key on chan */
497 freesstring(changes
->cp
->key
);
498 changes
->cp
->key
=NULL
;
503 /* We didn't hit a key change, so put a remove command in */
504 changes
->changes
[changes
->changecount
].str
=changes
->cp
->key
; /* implicit free */
505 changes
->cp
->key
=NULL
;
506 changes
->changes
[changes
->changecount
].dir
=MCB_DEL
;
507 changes
->changes
[changes
->changecount
++].flag
='k';
512 void localdosetmode_limit (modechanges
*changes
, unsigned int limit
, short dir
) {
517 localdosetmode_simple(changes
, 0, CHANMODE_LIMIT
);
521 /* Kill redundant changes */
522 if ((IsLimit(changes
->cp
) && changes
->cp
->limit
==limit
) || !limit
)
525 SetLimit(changes
->cp
);
526 changes
->cp
->limit
=limit
;
527 changes
->delflags
&= ~CHANMODE_LIMIT
;
529 /* Check for existing limit add */
530 for (i
=0;i
<changes
->changecount
;i
++) {
531 if (changes
->changes
[i
].flag
=='l') {
533 freesstring(changes
->changes
[i
].str
);
534 sprintf(buf
,"%u",limit
);
535 changes
->changes
[i
].str
=getsstring(buf
,20);
540 /* None, add new one. Note that we can do +l even if a limit is already set */
541 if (changes
->changecount
>= MAXMODEARGS
)
542 localsetmodeflush(changes
,0);
544 changes
->changes
[changes
->changecount
].flag
='l';
545 sprintf(buf
,"%u",limit
);
546 changes
->changes
[changes
->changecount
].str
=getsstring(buf
,20);
547 changes
->changes
[changes
->changecount
++].dir
=MCB_ADD
;
550 void localdosetmode_simple (modechanges
*changes
, flag_t addmodes
, flag_t delmodes
) {
553 /* We can't add a mode we're deleting, a key, limit, or mode that's already set */
554 addmodes
&= ~(delmodes
| CHANMODE_KEY
| CHANMODE_LIMIT
| changes
->cp
->flags
);
556 /* We can't delete a key or a mode that's not set */
557 delmodes
&= (~(CHANMODE_KEY
) & changes
->cp
->flags
);
559 /* If we're doing +p, do -s as well, and vice versa */
560 /* Also disallow +ps */
561 if (addmodes
& CHANMODE_SECRET
) {
562 addmodes
&= ~(CHANMODE_PRIVATE
);
563 delmodes
|= (CHANMODE_PRIVATE
& changes
->cp
->flags
);
566 if (addmodes
& CHANMODE_PRIVATE
) {
567 delmodes
|= (CHANMODE_SECRET
& changes
->cp
->flags
);
570 /* Fold changes into channel */
571 changes
->cp
->flags
|= addmodes
;
572 changes
->cp
->flags
&= ~delmodes
;
574 if (delmodes
& CHANMODE_LIMIT
) {
575 /* Check for +l in the parametered changes */
576 for (i
=0;i
<changes
->changecount
;i
++) {
577 if (changes
->changes
[i
].flag
=='l') {
578 freesstring(changes
->changes
[i
].str
);
579 changes
->changecount
--;
580 for (j
=0;j
<changes
->changecount
;j
++) {
581 changes
->changes
[j
]=changes
->changes
[j
+1];
586 changes
->cp
->limit
=0;
589 /* And into the changes buffer */
590 changes
->addflags
&= ~delmodes
;
591 changes
->addflags
|= addmodes
;
593 changes
->delflags
&= ~addmodes
;
594 changes
->delflags
|= delmodes
;
599 * Applies a mode change.
602 void localdosetmode_nick (modechanges
*changes
, nick
*target
, short modes
) {
605 if ((lp
=getnumerichandlefromchanhash(changes
->cp
->users
,target
->numeric
))==NULL
) {
606 /* Target isn't on channel, abort */
610 if ((modes
& MC_DEOP
) && (*lp
& CUMODE_OP
)) {
612 if (changes
->changecount
>= MAXMODEARGS
)
613 localsetmodeflush(changes
, 0);
614 changes
->changes
[changes
->changecount
].str
=getsstring(longtonumeric(target
->numeric
,5),5);
615 changes
->changes
[changes
->changecount
].dir
=MCB_DEL
;
616 changes
->changes
[changes
->changecount
++].flag
='o';
619 if ((modes
& MC_DEVOICE
) && (*lp
& CUMODE_VOICE
)) {
620 (*lp
) &= ~CUMODE_VOICE
;
621 if (changes
->changecount
>= MAXMODEARGS
)
622 localsetmodeflush(changes
, 0);
623 changes
->changes
[changes
->changecount
].str
=getsstring(longtonumeric(target
->numeric
,5),5);
624 changes
->changes
[changes
->changecount
].dir
=MCB_DEL
;
625 changes
->changes
[changes
->changecount
++].flag
='v';
628 if ((modes
& MC_OP
) && !(modes
& MC_DEOP
) && !(*lp
& CUMODE_OP
)) {
630 if (changes
->changecount
>= MAXMODEARGS
)
631 localsetmodeflush(changes
, 0);
632 changes
->changes
[changes
->changecount
].str
=getsstring(longtonumeric(target
->numeric
,5),5);
633 changes
->changes
[changes
->changecount
].dir
=MCB_ADD
;
634 changes
->changes
[changes
->changecount
++].flag
='o';
637 if ((modes
& MC_VOICE
) && !(modes
& MC_DEVOICE
) && !(*lp
& CUMODE_VOICE
)) {
638 (*lp
) |= CUMODE_VOICE
;
639 if (changes
->changecount
>= MAXMODEARGS
)
640 localsetmodeflush(changes
, 0);
641 changes
->changes
[changes
->changecount
].str
=getsstring(longtonumeric(target
->numeric
,5),5);
642 changes
->changes
[changes
->changecount
].dir
=MCB_ADD
;
643 changes
->changes
[changes
->changecount
++].flag
='v';
650 * Sends out mode changes to the network.
653 void localsetmodeflush (modechanges
*changes
, int flushall
) {
668 strcpy(addmodes
, printflags_noprefix(changes
->addflags
, cmodeflags
));
669 ampos
=strlen(addmodes
);
671 strcpy(remmodes
, printflags_noprefix(changes
->delflags
, cmodeflags
));
672 rmpos
=strlen(remmodes
);
674 changes
->addflags
=changes
->delflags
=0;
676 for (i
=0;i
<changes
->changecount
;i
++) {
677 /* Don't overflow the string, kinda nasty to work out.. format is: */
678 /* AAAA M #chan +add-rem (addstr) (remstr) */
679 if ((changes
->cp
->index
->name
->length
+ aapos
+ rapos
+
680 ampos
+ rmpos
+ changes
->changes
[i
].str
->length
+ 20) > BUFSIZE
)
683 switch (changes
->changes
[i
].dir
) {
685 addmodes
[ampos
++]=changes
->changes
[i
].flag
;
686 aapos
+=sprintf(addargs
+aapos
, "%s ", changes
->changes
[i
].str
->content
);
690 remmodes
[rmpos
++]=changes
->changes
[i
].flag
;
691 rapos
+=sprintf(remargs
+rapos
, "%s ", changes
->changes
[i
].str
->content
);
694 freesstring(changes
->changes
[i
].str
);
697 if (i
<changes
->changecount
) {
698 for (j
=i
;j
<changes
->changecount
;j
++)
699 changes
->changes
[j
-i
]=changes
->changes
[j
];
702 changes
->changecount
-= i
;
704 if ((ampos
+rmpos
)==0) {
709 addmodes
[ampos
]='\0';
710 remmodes
[rmpos
]='\0';
714 if (changes
->source
==NULL
||
715 (lp
=getnumerichandlefromchanhash(changes
->cp
->users
,changes
->source
->numeric
))==NULL
) {
716 /* User isn't on channel, hack mode */
717 strcpy(source
,mynumeric
->content
);
719 /* Check the user is local */
720 if (homeserver(changes
->source
->numeric
)!=mylongnum
) {
723 if ((*lp
&CUMODE_OP
)==0) {
724 localgetops(changes
->source
,changes
->cp
);
726 strcpy(source
,longtonumeric(changes
->source
->numeric
,5));
730 irc_send("%s M %s %s%s%s%s %s%s",source
,changes
->cp
->index
->name
->content
,
731 rmpos
? "-" : "", remmodes
,
732 ampos
? "+" : "", addmodes
, remargs
, addargs
);
735 /* If we have to flush everything out but didn't finish, go round again */
736 if (changes
->changecount
&& flushall
)
737 localsetmodeflush(changes
, 1);
742 * Sets modes for the user on the channel. This is now a stub routine that
743 * uses the new functions.
746 int localsetmodes(nick
*np
, channel
*cp
, nick
*target
, short modes
) {
749 localsetmodeinit (&changes
, cp
, np
);
750 localdosetmode_nick (&changes
, target
, modes
);
751 localsetmodeflush (&changes
, 1);
756 /* This function just sends the actual mode change,
757 * it assumes that the actual channel modes have been changed appropriately.
758 * This is unfortunately inconsistent with the rest of the localuser API..
761 void localusermodechange(nick
*np
, channel
*cp
, char *modes
) {
765 if (np
==NULL
|| (lp
=getnumerichandlefromchanhash(cp
->users
,np
->numeric
))==NULL
) {
766 /* User isn't on channel, hack mode */
767 strcpy(source
,mynumeric
->content
);
769 /* Check the user is local */
770 if (homeserver(np
->numeric
)!=mylongnum
) {
773 if ((*lp
&CUMODE_OP
)==0) {
776 strcpy(source
,longtonumeric(np
->numeric
,5));
780 irc_send("%s M %s %s",source
,cp
->index
->name
->content
,modes
);
784 /* This function actually sets the topic itself though.. a bit inconsistent :/ */
786 void localsettopic(nick
*np
, channel
*cp
, char *topic
) {
790 if (np
==NULL
|| (lp
=getnumerichandlefromchanhash(cp
->users
,np
->numeric
))==NULL
) {
791 /* User isn't on channel, hack mode */
792 strcpy(source
,mynumeric
->content
);
794 /* Check the user is local */
795 if (homeserver(np
->numeric
)!=mylongnum
) {
798 if ((*lp
&CUMODE_OP
)==0 && IsTopicLimit(cp
)) {
801 strcpy(source
,longtonumeric(np
->numeric
,5));
805 freesstring(cp
->topic
);
808 cp
->topic
=getsstring(topic
,TOPICLEN
);
809 cp
->topictime
=getnettime();
812 irc_send("%s T %s %u %u :%s",source
,cp
->index
->name
->content
,cp
->timestamp
,cp
->topictime
,(cp
->topic
)?cp
->topic
->content
:"");
816 void localkickuser(nick
*np
, channel
*cp
, nick
*target
, const char *message
) {
820 if (np
==NULL
|| (lp
=getnumerichandlefromchanhash(cp
->users
,np
->numeric
))==NULL
) {
821 /* User isn't on channel, hack mode */
822 strcpy(source
,mynumeric
->content
);
824 /* Check the user is local */
825 if (homeserver(np
->numeric
)!=mylongnum
) {
828 if ((*lp
&CUMODE_OP
)==0 && IsTopicLimit(cp
)) {
831 strcpy(source
,longtonumeric(np
->numeric
,5));
834 if ((lp
=getnumerichandlefromchanhash(cp
->users
,target
->numeric
))==NULL
)
837 /* Send the message to the network first in case delnickfromchannel()
838 * destroys the channel.. */
840 irc_send("%s K %s %s :%s",source
,cp
->index
->name
->content
,
841 longtonumeric(target
->numeric
,5), message
);
844 delnickfromchannel(cp
, target
->numeric
, 1);
847 void sendmessagetochannel(nick
*source
, channel
*cp
, char *format
, ... ) {
855 longtonumeric2(source
->numeric
,5,senderstr
);
858 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
859 /* So max sendable message is 495 bytes. Of course, a client won't be able
860 * to receive this.. */
862 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
866 irc_send("%s P %s :%s",senderstr
,cp
->index
->name
->content
,buf
);
870 void localinvite(nick
*source
, channel
*cp
, nick
*target
) {
872 /* Servers can't send invites */
876 /* CHECK: Does the sender have to be on the relevant channel? */
878 /* For some reason invites are sent with the target nick as
881 irc_send("%s I %s :%s",longtonumeric(source
->numeric
,5),
882 target
->nick
, cp
->index
->name
->content
);