1 /*
2  * Copyright (c) 2005-2007 Atheme Development Group
3  * Rights to this code are as documented in doc/LICENSE.
4  *
5  * This file contains code for the Memoserv READ function
6  *
7  */
8 
9 #include "atheme.h"
10 
11 DECLARE_MODULE_V1
12 (
13 	"memoserv/read", false, _modinit, _moddeinit,
14 	PACKAGE_STRING,
15 	VENDOR_STRING
16 );
17 
18 #define MAX_READ_AT_ONCE 5
19 
20 static void ms_cmd_read(sourceinfo_t *si, int parc, char *parv[]);
21 
22 command_t ms_read = { "READ", N_("Reads a memo."),
23                         AC_AUTHENTICATED, 2, ms_cmd_read, { .path = "memoserv/read" } };
24 
_modinit(module_t * m)25 void _modinit(module_t *m)
26 {
27         service_named_bind_command("memoserv", &ms_read);
28 }
29 
_moddeinit(module_unload_intent_t intent)30 void _moddeinit(module_unload_intent_t intent)
31 {
32 	service_named_unbind_command("memoserv", &ms_read);
33 }
34 
ms_cmd_read(sourceinfo_t * si,int parc,char * parv[])35 static void ms_cmd_read(sourceinfo_t *si, int parc, char *parv[])
36 {
37 	/* Misc structs etc */
38 	myuser_t *tmu;
39 	mymemo_t *memo, *receipt;
40 	mowgli_node_t *n;
41 	unsigned int i = 1, memonum = 0, numread = 0;
42 	char strfbuf[BUFSIZE];
43 	struct tm tm;
44 	bool readnew;
45 
46 	/* Grab arg */
47 	char *arg1 = parv[0];
48 
49 	if (!arg1)
50 	{
51 		command_fail(si, fault_needmoreparams,
52 			STR_INSUFFICIENT_PARAMS, "READ");
53 
54 		command_fail(si, fault_needmoreparams, _("Syntax: READ <memo number>"));
55 		return;
56 	}
57 
58 	/* Check to see if any memos */
59 	if (!si->smu->memos.count)
60 	{
61 		command_fail(si, fault_nosuch_key, _("You have no memos."));
62 		return;
63 	}
64 
65 	memonum = atoi(arg1);
66 	readnew = !strcasecmp(arg1, "NEW");
67 	if (!readnew && !memonum)
68 	{
69 		command_fail(si, fault_badparams, _("Invalid message index."));
70 		return;
71 	}
72 
73 	/* Check to see if memonum is greater than memocount */
74 	if (memonum > si->smu->memos.count)
75 	{
76 		command_fail(si, fault_nosuch_key, _("Invalid message index."));
77 		return;
78 	}
79 
80 	/* Go to reading memos */
81 	MOWGLI_ITER_FOREACH(n, si->smu->memos.head)
82 	{
83 		memo = (mymemo_t *)n->data;
84 		if (i == memonum || (readnew && !(memo->status & MEMO_READ)))
85 		{
86 			tm = *localtime(&memo->sent);
87 			strftime(strfbuf, sizeof strfbuf,
88 				TIME_FORMAT, &tm);
89 
90 			if (!(memo->status & MEMO_READ))
91 			{
92 				memo->status |= MEMO_READ;
93 				si->smu->memoct_new--;
94 				tmu = myuser_find(memo->sender);
95 
96 				/* If the sender is logged in, tell them the memo's been read */
97 				/* but not for channel memos */
98 				if (memo->status & MEMO_CHANNEL)
99 					;
100 				else if (strcasecmp(si->service->nick, memo->sender) && (tmu != NULL) && (tmu->logins.count > 0))
101 					myuser_notice(si->service->me->nick, tmu, "%s has read your memo, which was sent at %s", entity(si->smu)->name, strfbuf);
102 				else
103 				{
104 					/* If they have an account, their inbox is not full and they aren't memoserv */
105 					if ( (tmu != NULL) && (tmu->memos.count < me.mdlimit) && strcasecmp(si->service->nick, memo->sender))
106 					{
107 						/* Malloc and populate memo struct */
108 						receipt = smalloc(sizeof(mymemo_t));
109 						receipt->sent = CURRTIME;
110 						receipt->status = 0;
111 						mowgli_strlcpy(receipt->sender, si->service->nick, NICKLEN);
112 						snprintf(receipt->text, MEMOLEN, "%s has read a memo from you sent at %s", entity(si->smu)->name, strfbuf);
113 
114 						/* Attach to their linked list */
115 						n = mowgli_node_create();
116 						mowgli_node_add(receipt, n, &tmu->memos);
117 						tmu->memoct_new++;
118 					}
119 				}
120 			}
121 
122 			command_success_nodata(si,
123 				"\2Memo %d - Sent by %s, %s\2",i,memo->sender, strfbuf);
124 
125 			command_success_nodata(si,
126 				"------------------------------------------");
127 
128 			command_success_nodata(si, "%s", memo->text);
129 
130 			if (!readnew)
131 				return;
132 			if (++numread >= MAX_READ_AT_ONCE && si->smu->memoct_new > 0)
133 			{
134 				command_success_nodata(si, _("Stopping command after %d memos."), numread);
135 				return;
136 			}
137 		}
138 		i++;
139 	}
140 
141 	if (readnew && numread == 0)
142 		command_fail(si, fault_nosuch_key, _("You have no new memos."));
143 	else if (readnew)
144 		command_success_nodata(si, _("Read %d memos."), numread);
145 }
146 
147 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
148  * vim:ts=8
149  * vim:sw=8
150  * vim:noexpandtab
151  */
152