1 /*
2 * Copyright (c) 2006 Robin Burchell <surreal.w00t@gmail.com>
3 * Rights to this code are documented in doc/LICENCE.
4 *
5 * This file contains functionality implementing OperServ COMPARE.
6 *
7 */
8
9 #include "atheme.h"
10
11 DECLARE_MODULE_V1
12 (
13 "operserv/compare", false, _modinit, _moddeinit,
14 PACKAGE_STRING,
15 "Robin Burchell <surreal.w00t@gmail.com>"
16 );
17
18 static void os_cmd_compare(sourceinfo_t *si, int parc, char *parv[]);
19
20 command_t os_compare = { "COMPARE", N_("Compares two users or channels."), PRIV_CHAN_AUSPEX, 2, os_cmd_compare, { .path = "oservice/compare" } };
21
_modinit(module_t * m)22 void _modinit(module_t *m)
23 {
24 service_named_bind_command("operserv", &os_compare);
25 }
26
_moddeinit(module_unload_intent_t intent)27 void _moddeinit(module_unload_intent_t intent)
28 {
29 service_named_unbind_command("operserv", &os_compare);
30 }
31
os_cmd_compare(sourceinfo_t * si,int parc,char * parv[])32 static void os_cmd_compare(sourceinfo_t *si, int parc, char *parv[])
33 {
34 char *object1 = parv[0];
35 char *object2 = parv[1];
36 channel_t *c1, *c2;
37 user_t *u1, *u2;
38 mowgli_node_t *n1, *n2;
39 chanuser_t *cu1, *cu2;
40 int matches = 0;
41
42 int temp = 0;
43 char buf[512];
44 char tmpbuf[100];
45
46 memset(buf, '\0', 512);
47 memset(tmpbuf, '\0', 100);
48
49 if (!object1 || !object2)
50 {
51 command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "COMPARE");
52 command_fail(si, fault_needmoreparams, _("Syntax: COMPARE <nick|#channel> <nick|#channel>"));
53 return;
54 }
55
56 if (*object1 == '#')
57 {
58 if (*object2 == '#')
59 {
60 /* compare on two channels */
61 c1 = channel_find(object1);
62 c2 = channel_find(object2);
63
64 if (!c1 || !c2)
65 {
66 command_fail(si, fault_nosuch_target, _("Both channels must exist for @compare"));
67 return;
68 }
69
70 command_success_nodata(si, _("Common users in \2%s\2 and \2%s\2"), object1, object2);
71
72 /* iterate over the users in channel 1 */
73 MOWGLI_ITER_FOREACH(n1, c1->members.head)
74 {
75 cu1 = n1->data;
76
77 /* now iterate over each of channel 2's members, and compare them to the current user from ch1 */
78 MOWGLI_ITER_FOREACH(n2, c2->members.head)
79 {
80 cu2 = n2->data;
81
82 /* match! */
83 if (cu1->user == cu2->user)
84 {
85 /* common user! */
86 snprintf(tmpbuf, 99, "%s, ", cu1->user->nick);
87 strcat((char *)buf, tmpbuf);
88 memset(tmpbuf, '\0', 100);
89
90 /* if too many, output to user */
91 if (temp >= 5 || strlen(buf) > 300)
92 {
93 command_success_nodata(si, "%s", buf);
94 memset(buf, '\0', 512);
95 temp = 0;
96 }
97
98 temp++;
99 matches++;
100 }
101 }
102 }
103 }
104 else
105 {
106 /* bad syntax */
107 command_fail(si, fault_badparams, _("Bad syntax for @compare. Use @compare on two channels, or two users."));
108 return;
109 }
110 }
111 else
112 {
113 if (*object2 == '#')
114 {
115 /* bad syntax */
116 command_fail(si, fault_badparams, _("Bad syntax for @compare. Use @compare on two channels, or two users."));
117 return;
118 }
119 else
120 {
121 /* compare on two users */
122 u1 = user_find_named(object1);
123 u2 = user_find_named(object2);
124
125 if (!u1 || !u2)
126 {
127 command_fail(si, fault_nosuch_target, _("Both users must exist for @compare"));
128 return;
129 }
130
131 command_success_nodata(si, _("Common channels for \2%s\2 and \2%s\2"), object1, object2);
132
133 /* iterate over the channels of user 1 */
134 MOWGLI_ITER_FOREACH(n1, u1->channels.head)
135 {
136 cu1 = n1->data;
137
138 /* now iterate over each of user 2's channels to the current channel from user 1 */
139 MOWGLI_ITER_FOREACH(n2, u2->channels.head)
140 {
141 cu2 = n2->data;
142
143 /* match! */
144 if (cu1->chan == cu2->chan)
145 {
146 /* common channel! */
147 snprintf(tmpbuf, 99, "%s, ", cu1->chan->name);
148 strcat((char *)buf, tmpbuf);
149 memset(tmpbuf, '\0', 100);
150
151 /* if too many, output to user */
152 if (temp >= 5 || strlen(buf) > 300)
153 {
154 command_success_nodata(si, "%s", buf);
155 memset(buf, '\0', 512);
156 temp = 0;
157 }
158
159 temp++;
160 matches++;
161 }
162 }
163 }
164 }
165 }
166
167 if (buf[0] != 0)
168 command_success_nodata(si, "%s", buf);
169
170 command_success_nodata(si, _("\2%d\2 matches comparing %s and %s"), matches, object1, object2);
171 logcommand(si, CMDLOG_ADMIN, "COMPARE: \2%s\2 to \2%s\2 (\2%d\2 matches)", object1, object2, matches);
172 }
173
174 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
175 * vim:ts=8
176 * vim:sw=8
177 * vim:noexpandtab
178 */
179