Fixing up logging (slot renames and gives)
[tpg/opendispense2.git] / src / server / dispense.c
1 /**
2  */
3 #include "common.h"
4 #include <stdlib.h>
5 #include <limits.h>
6 #include <string.h>
7
8  int    _GetMinBalance(int Account);
9  int    _CanTransfer(int Source, int Destination, int Ammount);
10  int    _Transfer(int Source, int Destination, int Ammount, const char *Reason);
11
12 // === CODE ===
13 /**
14  * \brief Dispense an item for a user
15  * 
16  * The core of the dispense system, I kinda like it :)
17  */
18 int DispenseItem(int ActualUser, int User, tItem *Item)
19 {
20          int    ret, salesAcct;
21         tHandler        *handler;
22         char    *username, *actualUsername;
23         
24         salesAcct = Bank_GetAcctByName(COKEBANK_SALES_ACCT);
25
26         // Check if the user can afford it
27         if( Item->Price && !_CanTransfer(User, salesAcct, Item->Price) )
28         {
29                 return 2;       // 2: No balance
30         }
31         
32         handler = Item->Handler;
33         
34         // KNOWN HACK: Naming a slot "dead" disables it
35         if( strcmp(Item->Name, "dead") == 0 )
36                 return 1;
37         
38         // Check if the dispense is possible
39         if( handler->CanDispense ) {
40                 ret = handler->CanDispense( User, Item->ID );
41                 if(ret) return 1;       // 1: Unable to dispense
42         }
43         
44         // Get username for debugging
45         username = Bank_GetAcctName(User);
46         
47         // Actually do the dispense
48         if( handler->DoDispense ) {
49                 ret = handler->DoDispense( User, Item->ID );
50                 if(ret) {
51                         Log_Error("Dispense failed (%s dispensing %s:%i '%s')",
52                                 username, Item->Name, Item->Handler->Name, Item->ID);
53                         free( username );
54                         return -1;      // 1: Unknown Error again
55                 }
56         }
57         
58         // Take away money
59         if( Item->Price )
60         {
61                 char    *reason;
62                 reason = mkstr("Dispense - %s:%i %s", handler->Name, Item->ID, Item->Name);
63                 _Transfer( User, salesAcct, Item->Price, reason );
64                 free(reason);
65         }
66         
67         actualUsername = Bank_GetAcctName(ActualUser);
68         
69         // And log that it happened
70         Log_Info("dispense '%s' (%s:%i) for %s by %s [cost %i, balance %i]",
71                 Item->Name, handler->Name, Item->ID,
72                 username, actualUsername, Item->Price, Bank_GetBalance(User)
73                 );
74         
75         free( username );
76         free( actualUsername );
77         return 0;       // 0: EOK
78 }
79
80 /**
81  * \brief Refund a dispense
82  */
83 int DispenseRefund(int ActualUser, int DestUser, tItem *Item, int OverridePrice)
84 {
85          int    ret;
86          int    src_acct, price;
87         char    *username, *actualUsername;
88
89         src_acct = Bank_GetAcctByName(COKEBANK_SALES_ACCT);
90
91         if( OverridePrice > 0 )
92                 price = OverridePrice;
93         else
94                 price = Item->Price;
95
96         ret = _Transfer( src_acct, DestUser, price, "Refund");
97         if(ret) return ret;
98
99         username = Bank_GetAcctName(DestUser);
100         actualUsername = Bank_GetAcctName(ActualUser);
101         
102         Log_Info("refund '%s' (%s:%i) to %s by %s [cost %i, balance %i]",
103                 Item->Name, Item->Handler->Name, Item->ID,
104                 username, actualUsername, price, Bank_GetBalance(DestUser)
105                 );
106
107         free(username);
108         free(actualUsername);
109
110         return 0;
111 }
112
113 /**
114  * \brief Give money from one user to another
115  */
116 int DispenseGive(int ActualUser, int SrcUser, int DestUser, int Ammount, const char *ReasonGiven)
117 {
118          int    ret;
119         char    *actualUsername;
120         char    *srcName, *dstName;
121         
122         if( Ammount < 0 )       return 1;       // Um... negative give? Not on my watch!
123         
124         ret = _Transfer( SrcUser, DestUser, Ammount, ReasonGiven );
125         if(ret) return 2;       // No Balance
126         
127         
128         actualUsername = Bank_GetAcctName(ActualUser);
129         srcName = Bank_GetAcctName(SrcUser);
130         dstName = Bank_GetAcctName(DestUser);
131         
132         Log_Info("give %i from %s to %s by %s [balances %i, %i] - %s",
133                 Ammount, srcName, dstName, actualUsername,
134                 Bank_GetBalance(SrcUser), Bank_GetBalance(DestUser),
135                 ReasonGiven
136                 );
137         
138         free(srcName);
139         free(dstName);
140         free(actualUsername);
141         
142         return 0;
143 }
144
145 #if 0 // Dead Code
146 /**
147  * \brief Move money from one user to another (Admin Only)
148  */
149 int DispenseTransfer(int ActualUser, int SrcUser, int DestUser, int Ammount, const char *ReasonGiven)
150 {
151          int    ret;
152         char    *actualUsername;
153         char    *srcName, *dstName;
154
155         // Make sure the user is an admin
156         if( !(Bank_GetFlags(ActualUser) & USER_FLAG_ADMIN) )
157                 return 1;
158         
159         ret = _Transfer( SrcUser, DestUser, Ammount, ReasonGiven );
160         if(ret) return 2;       // No Balance
161         
162         
163         actualUsername = Bank_GetAcctName(ActualUser);
164         srcName = Bank_GetAcctName(SrcUser);
165         dstName = Bank_GetAcctName(DestUser);
166         
167         Log_Info("move %i from %s to %s by %s [balances %i, %i] - %s",
168                 Ammount, srcName, dstName, actualUsername,
169                 Bank_GetBalance(SrcUser), Bank_GetBalance(DestUser),
170                 ReasonGiven
171                 );
172         
173         free(srcName);
174         free(dstName);
175         free(actualUsername);
176         
177         return 0;
178 }
179 #endif
180
181 /**
182  * \brief Add money to an account
183  */
184 int DispenseAdd(int ActualUser, int User, int Ammount, const char *ReasonGiven)
185 {
186          int    ret;
187         char    *dstName, *byName;
188         
189 #if DISPENSE_ADD_BELOW_MIN
190         ret = _Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Ammount, ReasonGiven );
191 #else
192         ret = Bank_Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Ammount, ReasonGiven );
193 #endif
194         if(ret) return 2;
195         
196         byName = Bank_GetAcctName(ActualUser);
197         dstName = Bank_GetAcctName(User);
198         
199         Log_Info("add %i to %s by %s [balance %i] - %s",
200                 Ammount, dstName, byName, Bank_GetBalance(User), ReasonGiven
201                 );
202         
203         free(byName);
204         free(dstName);
205         
206         return 0;
207 }
208
209 int DispenseSet(int ActualUser, int User, int Balance, const char *ReasonGiven)
210 {
211          int    curBal = Bank_GetBalance(User);
212         char    *byName, *dstName;
213         
214         _Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Balance-curBal, ReasonGiven );
215         
216         byName = Bank_GetAcctName(ActualUser);
217         dstName = Bank_GetAcctName(User);
218         
219         Log_Info("set balance of %s to %i by %s [balance %i] - %s",
220                 dstName, Balance, byName, Bank_GetBalance(User), ReasonGiven
221                 );
222         
223         free(byName);
224         free(dstName);
225         
226         return 0;
227 }
228
229 /**
230  * \brief Donate money to the club
231  */
232 int DispenseDonate(int ActualUser, int User, int Ammount, const char *ReasonGiven)
233 {
234          int    ret;
235         char    *srcName, *byName;
236         
237         if( Ammount < 0 )       return 2;
238         
239         ret = _Transfer( User, Bank_GetAcctByName(COKEBANK_DEBT_ACCT), Ammount, ReasonGiven );
240         if(ret) return 2;
241         
242         byName = Bank_GetAcctName(ActualUser);
243         srcName = Bank_GetAcctName(User);
244         
245         Log_Info("donate %i from %s by %s [balance %i] - %s",
246                 Ammount, srcName, byName, Bank_GetBalance(User), ReasonGiven
247                 );
248         
249         free(byName);
250         free(srcName);
251         
252         return 0;
253 }
254
255 int DispenseUpdateItem(int User, tItem *Item, const char *NewName, int NewPrice)
256 {
257         char    *username;
258         
259         // Sanity checks
260         if( NewPrice < 0 )      return 2;
261         if( !Item )     return 2;
262         if( strlen(NewName) < 1 )       return 2;
263         
264         // Update the item
265         free(Item->Name);
266         Item->Name = strdup(NewName);
267         Item->Price = NewPrice;
268         
269         username = Bank_GetAcctName(User);
270         
271         Log_Info("item %s:%i updated to '%s' %i by %s",
272                 Item->Handler->Name, Item->ID,
273                 NewName, NewPrice, username
274                 );
275         
276         free(username);
277         
278         // Update item file
279         Items_UpdateFile();
280         
281         return 0;
282 }
283
284 // --- Internal Functions ---
285 int _GetMinBalance(int Account)
286 {
287          int    flags = Bank_GetFlags(Account);
288         
289         // Evil little piece of HACK:
290         // root's balance cannot be changed by any of the above functions
291         // - Stops dispenses as root by returning insufficent balance.
292         {
293                 char    *username = Bank_GetAcctName(Account);
294                 if( strcmp(username, "root") == 0 )
295                 {
296                         free(username);
297                         return INT_MAX;
298                 }
299                 free(username);
300         }
301         
302         // - Internal accounts have no lower bound
303         if( flags & USER_FLAG_INTERNAL )        return INT_MIN;
304         
305         // Admin to -$50
306 //      if( flags & USER_FLAG_ADMIN )   return -5000;
307         
308         // Coke to -$20
309 //      if( flags & USER_FLAG_COKE )    return -2000;
310         
311         // Anyone else, non-negative
312         return 0;
313 }
314
315 /**
316  * \brief Check if a transfer is possible
317  */
318 int _CanTransfer(int Source, int Destination, int Ammount)
319 {
320         if( Ammount > 0 )
321         {
322                 if( Bank_GetBalance(Source) - Ammount < _GetMinBalance(Source) )
323                         return 0;
324         }
325         else
326         {
327                 if( Bank_GetBalance(Destination) + Ammount < _GetMinBalance(Destination) )
328                         return 0;
329         }
330         return 1;
331 }
332
333 int _Transfer(int Source, int Destination, int Ammount, const char *Reason)
334 {
335         if( !_CanTransfer(Source, Destination, Ammount) )
336                 return 1;
337         return Bank_Transfer(Source, Destination, Ammount, Reason);
338 }

UCC git Repository :: git.ucc.asn.au