Merge branch 'master' of serenade.mutabah.net:opendispense2
[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         // Check if the dispense is possible
35         if( handler->CanDispense ) {
36                 ret = handler->CanDispense( User, Item->ID );
37                 if(ret) return 1;       // 1: Unable to dispense
38         }
39         
40         // Get username for debugging
41         username = Bank_GetAcctName(User);
42         
43         // Actually do the dispense
44         if( handler->DoDispense ) {
45                 ret = handler->DoDispense( User, Item->ID );
46                 if(ret) {
47                         Log_Error("Dispense failed (%s dispensing '%s' - %ic)",
48                                 username, Item->Name, Item->Price);
49                         free( username );
50                         return -1;      // 1: Unknown Error again
51                 }
52         }
53         
54         // Take away money
55         if( Item->Price )
56         {
57                 char    *reason;
58                 reason = mkstr("Dispense - %s:%i %s", handler->Name, Item->ID, Item->Name);
59                 _Transfer( User, salesAcct, Item->Price, reason );
60                 free(reason);
61         }
62         
63         actualUsername = Bank_GetAcctName(ActualUser);
64         
65         // And log that it happened
66         Log_Info("dispense '%s' (%s:%i) for %s by %s [cost %i, balance %i]",
67                 Item->Name, handler->Name, Item->ID,
68                 username, actualUsername, Item->Price, Bank_GetBalance(User)
69                 );
70         
71         free( username );
72         free( actualUsername );
73         return 0;       // 0: EOK
74 }
75
76 /**
77  * \brief Give money from one user to another
78  */
79 int DispenseGive(int ActualUser, int SrcUser, int DestUser, int Ammount, const char *ReasonGiven)
80 {
81          int    ret;
82         char    *actualUsername;
83         char    *srcName, *dstName;
84         
85         if( Ammount < 0 )       return 1;       // Um... negative give? Not on my watch!
86         
87         ret = _Transfer( SrcUser, DestUser, Ammount, ReasonGiven );
88         if(ret) return 2;       // No Balance
89         
90         
91         actualUsername = Bank_GetAcctName(ActualUser);
92         srcName = Bank_GetAcctName(SrcUser);
93         dstName = Bank_GetAcctName(DestUser);
94         
95         Log_Info("give %i to %s from %s by %s [balances %i, %i] - %s",
96                 Ammount, dstName, srcName, actualUsername,
97                 Bank_GetBalance(SrcUser), Bank_GetBalance(DestUser),
98                 ReasonGiven
99                 );
100         
101         free(srcName);
102         free(dstName);
103         free(actualUsername);
104         
105         return 0;
106 }
107
108 /**
109  * \brief Add money to an account
110  */
111 int DispenseAdd(int ActualUser, int User, int Ammount, const char *ReasonGiven)
112 {
113          int    ret;
114         char    *dstName, *byName;
115         
116         ret = _Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Ammount, ReasonGiven );
117         if(ret) return 2;
118         
119         byName = Bank_GetAcctName(ActualUser);
120         dstName = Bank_GetAcctName(User);
121         
122         Log_Info("add %i to %s by %s [balance %i] - %s",
123                 Ammount, dstName, byName, Bank_GetBalance(User), ReasonGiven
124                 );
125         
126         free(byName);
127         free(dstName);
128         
129         return 0;
130 }
131
132 int DispenseSet(int ActualUser, int User, int Balance, const char *ReasonGiven)
133 {
134          int    curBal = Bank_GetBalance(User);
135         char    *byName, *dstName;
136         
137         _Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Balance-curBal, ReasonGiven );
138         
139         byName = Bank_GetAcctName(ActualUser);
140         dstName = Bank_GetAcctName(User);
141         
142         Log_Info("set balance of %s to %i by %s [balance %i] - %s",
143                 dstName, Balance, byName, Bank_GetBalance(User), ReasonGiven
144                 );
145         
146         free(byName);
147         free(dstName);
148         
149         return 0;
150 }
151
152 /**
153  * \brief Donate money to the club
154  */
155 int DispenseDonate(int ActualUser, int User, int Ammount, const char *ReasonGiven)
156 {
157          int    ret;
158         char    *srcName, *byName;
159         
160         if( Ammount < 0 )       return 2;
161         
162         ret = _Transfer( User, Bank_GetAcctByName(COKEBANK_DEBT_ACCT), Ammount, ReasonGiven );
163         if(ret) return 2;
164         
165         byName = Bank_GetAcctName(ActualUser);
166         srcName = Bank_GetAcctName(User);
167         
168         Log_Info("donate %i from %s by %s [balance %i] - %s",
169                 Ammount, srcName, byName, Bank_GetBalance(User), ReasonGiven
170                 );
171         
172         free(byName);
173         free(srcName);
174         
175         return 0;
176 }
177
178 // --- Internal Functions ---
179 int _GetMinBalance(int Account)
180 {
181          int    flags = Bank_GetFlags(Account);
182         
183         // Evil little piece of HACK:
184         // root's balance cannot be changed by any of the above functions
185         // - Stops dispenses as root by returning insufficent balance.
186         {
187                 char    *username = Bank_GetAcctName(Account);
188                 if( strcmp(username, "root") == 0 )
189                 {
190                         free(username);
191                         return INT_MAX;
192                 }
193                 free(username);
194         }
195         
196         // - Internal accounts have no lower bound
197         if( flags & USER_FLAG_INTERNAL )        return INT_MIN;
198         
199         // Admin to -$10
200         //if( flags & USER_FLAG_ADMIN ) return -1000;
201         
202         // Coke to -$5
203         //if( flags & USER_FLAG_COKE )  return -500;
204         
205         // Anyone else, non-negative
206         return 0;
207 }
208
209 /**
210  * \brief Check if a transfer is possible
211  */
212 int _CanTransfer(int Source, int Destination, int Ammount)
213 {
214         if( Ammount > 0 )
215         {
216                 if( Bank_GetBalance(Source) + Ammount < _GetMinBalance(Source) )
217                         return 0;
218         }
219         else
220         {
221                 if( Bank_GetBalance(Destination) - Ammount < _GetMinBalance(Destination) )
222                         return 0;
223         }
224         return 1;
225 }
226
227 int _Transfer(int Source, int Destination, int Ammount, const char *Reason)
228 {
229         if( !_CanTransfer(Source, Destination, Ammount) )
230                 return 1;
231         return Bank_Transfer(Source, Destination, Ammount, Reason);
232 }

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