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