keep in sync with OGN upstream (SVN-319)
[ircu2.10.12-pk.git] / ircd / m_svsjoin.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_svsjoin.c
3  * Written by David Herrmann.
4  */
5
6 #include "config.h"
7
8 #include "channel.h"
9 #include "client.h"
10 #include "handlers.h"
11 #include "hash.h"
12 #include "ircd.h"
13 #include "ircd_chattr.h"
14 #include "ircd_features.h"
15 #include "ircd_reply.h"
16 #include "ircd_string.h"
17 #include "msg.h"
18 #include "numeric.h"
19 #include "numnicks.h"
20 #include "s_debug.h"
21 #include "s_user.h"
22 #include "send.h"
23
24 #include <string.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27
28 /** SVSJOIN
29  * SVSJOIN is forwarded to the server where the user is connected to.
30  * This allows to send SVSJOINs from all servers in the network but additionally causes
31  * some overhead. Though, SVSJOIN is not often called and this overhead can be ignored.
32  */
33 int m_svsjoin(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
34 {
35     struct Client *acptr;
36     struct Channel *chptr;
37     struct JoinBuf join;
38     struct JoinBuf create;
39     unsigned int flags = 0;
40     char *name;
41
42         if (!IsNetServ(sptr) || !HasFlag(sptr, FLAG_SECURITY_SERV))
43     return send_reply(sptr, ERR_NOPRIVILEGES);
44         
45     if(parc < 3) {
46         return protocol_violation(cptr, "Too few arguments for SVSJOIN");
47     }
48
49     /* Ignore if the user has already quitted. */
50     if(!(acptr = FindUser(parv[1]))) {
51         return 0;
52     }
53
54     /* Check channelname. */
55     if(!IsChannelName(parv[2]) || !strIsIrcCh(parv[2])) {
56         return 0;
57     }
58
59     /* Create channel if necessary and return a pointer. */
60     chptr = get_channel(acptr, parv[2], (!FindChannel(parv[2])) ? CGT_CREATE : CGT_NO_CREATE);
61     if(find_member_link(chptr, acptr)) return 0; /* User is already in the channel. */
62
63     /* Forward the message to the server where the user is connected to. */
64     if(!MyConnect(acptr)) {
65             const struct User* user = cli_user(acptr);
66                 struct Client *server = user->server; 
67         sendcmdto_one(sptr, CMD_SVSJOIN, acptr, "%s%s %s", cli_yxx(server), cli_yxx(acptr), chptr->chname);
68         return 0;
69     }
70
71     name = chptr->chname;
72
73     /* We need to use \joinbuf to let a user join.
74      * We fill only the \joinbuf which is actually used but
75      * create both.
76      */
77
78     joinbuf_init(&join, acptr, acptr, JOINBUF_TYPE_JOIN, 0, 0);
79     joinbuf_init(&create, acptr, acptr, JOINBUF_TYPE_CREATE, 0, TStime());
80
81     flags = (chptr->users == 0) ? CHFL_CHANOP | CHFL_CHANNEL_MANAGER : CHFL_DEOPPED;
82     if(chptr->users) joinbuf_join(&join, chptr, flags);
83     else joinbuf_join(&create, chptr, flags);
84
85     /* Send information to the user. */
86     if(chptr->topic[0]) {
87         send_reply(acptr, RPL_TOPIC, chptr->chname, chptr->topic);
88         send_reply(acptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time);
89     }
90     do_names(acptr, chptr, NAMES_ALL|NAMES_EON|(((chptr->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0));
91
92     joinbuf_flush(&join);
93     joinbuf_flush(&create);
94
95     return 0;
96 }
97
98 /* ms_svsjoin - server message handler
99  *
100  * parv[0] = sender prefix
101  * parv[1] = numeric of client
102  * parv[2] = channel, NO CHANLIST!
103  */
104 signed int ms_svsjoin(struct Client* cptr, struct Client* sptr, signed int parc, char* parv[]) {
105     struct Client *acptr;
106     struct Channel *chptr;
107     struct JoinBuf join;
108     struct JoinBuf create;
109     unsigned int flags = 0;
110     char *name;
111
112     if(parc < 3) {
113         return protocol_violation(cptr, "Too few arguments for SVSJOIN");
114     }
115
116     /* Ignore if the user has already quitted. */
117     if(!(acptr = findNUser(parv[1]))) {
118         return 0;
119     }
120
121     /* Check channelname. */
122     if(!IsChannelName(parv[2]) || !strIsIrcCh(parv[2])) {
123         return 0;
124     }
125
126     /* Create channel if necessary and return a pointer. */
127     chptr = get_channel(acptr, parv[2], (!FindChannel(parv[2])) ? CGT_CREATE : CGT_NO_CREATE);
128     if(find_member_link(chptr, acptr)) return 0; /* User is already in the channel. */
129
130     /* Forward the message to the server where the user is connected to. */
131     if(!MyConnect(acptr)) {
132         sendcmdto_one(sptr, CMD_SVSJOIN, acptr, "%s %s", parv[1], chptr->chname);
133         return 0;
134     }
135     
136     #ifndef UNRESTRICTED_SERV
137     
138     name = chptr->chname;
139
140     /* We need to use \joinbuf to let a user join.
141      * We fill only the \joinbuf which is actually used but
142      * create both.
143      */
144
145     joinbuf_init(&join, acptr, acptr, JOINBUF_TYPE_JOIN, 0, 0);
146     joinbuf_init(&create, acptr, acptr, JOINBUF_TYPE_CREATE, 0, TStime());
147
148     flags = (chptr->users == 0) ? CHFL_CHANOP : CHFL_DEOPPED;
149     if(chptr) joinbuf_join(&join, chptr, flags);
150     else joinbuf_join(&create, chptr, flags);
151
152     /* Send information to the user. */
153     if(chptr->topic[0]) {
154         send_reply(acptr, RPL_TOPIC, chptr->chname, chptr->topic);
155         send_reply(acptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time);
156     }
157     do_names(acptr, chptr, NAMES_ALL|NAMES_EON|(((chptr->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0));
158
159     joinbuf_flush(&join);
160     joinbuf_flush(&create);
161     
162     #endif
163
164     return 0;
165 }
166