Plug some memory leaks, and eliminate some unnecessary
[working/Evergreen.git] / Open-ILS / src / c-apps / oils_utils.c
1 #include "openils/oils_utils.h"
2 #include "openils/oils_idl.h"
3
4 osrfHash* oilsInitIDL(const char* idl_filename) {
5
6         char* freeable_filename = NULL;
7         const char* filename;
8
9         if(idl_filename)
10                 filename = idl_filename;
11         else {
12                 freeable_filename = osrf_settings_host_value("/IDL");
13                 filename = freeable_filename;
14         }
15
16         if (!filename) {
17                 osrfLogError(OSRF_LOG_MARK, "No settings config for '/IDL'");
18                 return NULL;
19         }
20
21         osrfLogInfo(OSRF_LOG_MARK, "Parsing IDL %s", filename);
22
23         if (!oilsIDLInit( filename )) {
24                 osrfLogError(OSRF_LOG_MARK, "Problem loading IDL file [%s]!", filename);
25                 if(freeable_filename)
26                         free(freeable_filename);
27                 return NULL;
28         }
29
30         if(freeable_filename)
31                 free(freeable_filename);
32         return oilsIDL();
33 }
34
35 /**
36         @brief Return a const string with the value of a specified column in a row object.
37         @param object Pointer to the row object.
38         @param field Name of the column.
39         @return Pointer to a const string representing the value of the specified column,
40                 or NULL in case of error.
41
42         The row object must be a JSON_ARRAY with a classname.  The column value must be a
43         JSON_STRING or a JSON_NUMBER.  Any other object type results in a return of NULL.
44
45         The return value points into the internal contents of the row object, which
46         retains ownership.
47 */
48 const char* oilsFMGetStringConst( const jsonObject* object, const char* field ) {
49         return jsonObjectGetString(oilsFMGetObject( object, field ));
50 }
51
52 /**
53         @brief Return a string with the value of a specified column in a row object.
54         @param object Pointer to the row object.
55         @param field Name of the column.
56         @return Pointer to a newly allocated string representing the value of the specified column,
57                 or NULL in case of error.
58
59         The row object must be a JSON_ARRAY with a classname.  The column value must be a
60         JSON_STRING or a JSON_NUMBER.  Any other object type results in a return of NULL.
61
62         The calling code is responsible for freeing the returned string by calling free().
63  */
64 char* oilsFMGetString( const jsonObject* object, const char* field ) {
65         return jsonObjectToSimpleString(oilsFMGetObject( object, field ));
66 }
67
68 /**
69         @brief Return a pointer to the value of a specified column in a row object.
70         @param object Pointer to the row object.
71         @param field Name of the column.
72         @return Pointer to the jsonObject representing the value of the specified column, or NULL
73                 in case of error.
74
75         The row object must be a JSON_ARRAY with a classname.
76
77         The return value may point to a JSON_NULL, JSON_STRING, JSON_NUMBER, or JSON_ARRAY.  It
78         points into the internal contents of the row object, which retains ownership.
79 */
80 const jsonObject* oilsFMGetObject( const jsonObject* object, const char* field ) {
81         if(!(object && field)) return NULL;
82         if( object->type != JSON_ARRAY || !object->classname ) return NULL;
83         int pos = fm_ntop(object->classname, field);
84         if( pos > -1 )
85                 return jsonObjectGetIndex( object, pos );
86         return NULL;
87 }
88
89
90 int oilsFMSetString( jsonObject* object, const char* field, const char* string ) {
91         if(!(object && field && string)) return -1;
92         osrfLogInternal(OSRF_LOG_MARK, "oilsFMSetString(): Collecing position for field %s", field);
93         int pos = fm_ntop(object->classname, field);
94         if( pos > -1 ) {
95                 osrfLogInternal(OSRF_LOG_MARK, "oilsFMSetString(): Setting string "
96                                 "%s at field %s [position %d]", string, field, pos );
97                 jsonObjectSetIndex( object, pos, jsonNewObject(string) );
98                 return 0;
99         }
100         return -1;
101 }
102
103
104 int oilsUtilsIsDBTrue( const char* val ) {
105         if( val && strcasecmp(val, "f") && strcmp(val, "0") ) return 1;
106         return 0;
107 }
108
109
110 long oilsFMGetObjectId( const jsonObject* obj ) {
111         long id = -1;
112         if(!obj) return id;
113         char* ids = oilsFMGetString( obj, "id" );
114         if(ids) {
115                 id = atol(ids);
116                 free(ids);
117         }
118         return id;
119 }
120
121
122 oilsEvent* oilsUtilsCheckPerms( int userid, int orgid, char* permissions[], int size ) {
123         if (!permissions) return NULL;
124         int i;
125         oilsEvent* evt = NULL;
126
127         // Find the root org unit, i.e. the one with no parent.
128         // Assumption: there is only one org unit with no parent.
129         if (orgid == -1) {
130                 jsonObject* where_clause = jsonParse( "{\"parent_ou\":null}" );
131                 jsonObject* org = oilsUtilsQuickReq(
132                         "open-ils.cstore",
133                         "open-ils.cstore.direct.actor.org_unit.search",
134                         where_clause
135                 );
136                 jsonObjectFree( where_clause );
137
138                 orgid = (int)jsonObjectGetNumber( oilsFMGetObject( org, "id" ) );
139
140                 jsonObjectFree(org);
141         }
142
143         for( i = 0; i < size && permissions[i]; i++ ) {
144
145                 char* perm = permissions[i];
146                 jsonObject* params = jsonParseFmt("[%d, \"%s\", %d]", userid, perm, orgid);
147                 jsonObject* o = oilsUtilsQuickReq( "open-ils.storage",
148                         "open-ils.storage.permission.user_has_perm", params );
149
150                 char* r = jsonObjectToSimpleString(o);
151
152                 if(r && !strcmp(r, "0"))
153                         evt = oilsNewEvent3( OSRF_LOG_MARK, OILS_EVENT_PERM_FAILURE, perm, orgid );
154
155                 jsonObjectFree(params);
156                 jsonObjectFree(o);
157                 free(r);
158
159                 if(evt)
160                         break;
161         }
162
163         return evt;
164 }
165
166 /**
167         @brief Perform a remote procedure call.
168         @param service The name of the service to invoke.
169         @param method The name of the method to call.
170         @param params The parameters to be passed to the method, if any.
171         @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
172         doesn't return anything.
173
174         If the @a params parameter points to a JSON_ARRAY, pass each element of the array
175         as a separate parameter.  If it points to any other kind of jsonObject, pass it as a
176         single parameter.  If it is NULL, pass no parameters.
177
178         The calling code is responsible for freeing the returned object by calling jsonObjectFree().
179 */
180 jsonObject* oilsUtilsQuickReq( const char* service, const char* method,
181                 const jsonObject* params ) {
182         if(!(service && method)) return NULL;
183
184         osrfLogDebug(OSRF_LOG_MARK, "oilsUtilsQuickReq(): %s - %s", service, method );
185
186         // Open an application session with the service, and send the request
187         osrfAppSession* session = osrfAppSessionClientInit( service );
188         int reqid = osrfAppSessionSendRequest( session, params, method, 1 );
189
190         // Get the response
191         osrfMessage* omsg = osrfAppSessionRequestRecv( session, reqid, 60 );
192         jsonObject* result = jsonObjectClone( osrfMessageGetResult(omsg) );
193
194         // Clean up
195         osrfMessageFree(omsg);
196         osrfAppSessionFree(session);
197         return result;
198 }
199
200 /**
201         @brief Call a method of the open-ils.storage service.
202         @param method Name of the method.
203         @param params Parameters to be passed to the method, if any.
204         @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
205         doesn't return anything.
206
207         If the @a params parameter points to a JSON_ARRAY, pass each element of the array
208         as a separate parameter.  If it points to any other kind of jsonObject, pass it as a
209         single parameter.  If it is NULL, pass no parameters.
210
211         The calling code is responsible for freeing the returned object by calling jsonObjectFree().
212 */
213 jsonObject* oilsUtilsStorageReq( const char* method, const jsonObject* params ) {
214         return oilsUtilsQuickReq( "open-ils.storage", method, params );
215 }
216
217 /**
218         @brief Call a method of the open-ils.cstore service.
219         @param method Name of the method.
220         @param params Parameters to be passed to the method, if any.
221         @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
222         doesn't return anything.
223
224         If the @a params parameter points to a JSON_ARRAY, pass each element of the array
225         as a separate parameter.  If it points to any other kind of jsonObject, pass it as a
226         single parameter.  If it is NULL, pass no parameters.
227
228         The calling code is responsible for freeing the returned object by calling jsonObjectFree().
229 */
230 jsonObject* oilsUtilsCStoreReq( const char* method, const jsonObject* params ) {
231         return oilsUtilsQuickReq("open-ils.cstore", method, params);
232 }
233
234
235
236 /**
237         @brief Given a username, fetch the corresponding row from the actor.usr table, if any.
238         @param name The username for which to search.
239         @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
240         or a JSON_NULL if it doesn't.
241
242         The calling code is responsible for freeing the returned object by calling jsonObjectFree().
243 */
244 jsonObject* oilsUtilsFetchUserByUsername( const char* name ) {
245         if(!name) return NULL;
246         jsonObject* params = jsonParseFmt("{\"usrname\":\"%s\"}", name);
247         jsonObject* user = oilsUtilsQuickReq(
248                 "open-ils.cstore", "open-ils.cstore.direct.actor.user.search", params );
249
250         jsonObjectFree(params);
251         long id = oilsFMGetObjectId(user);
252         osrfLogDebug(OSRF_LOG_MARK, "Fetched user %s:%ld", name, id);
253         return user;
254 }
255
256 /**
257         @brief Given a barcode, fetch the corresponding row from the actor.usr table, if any.
258         @param name The barcode for which to search.
259         @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
260         or a JSON_NULL if it doesn't.
261
262         Look up the barcode in actor.card.  Follow a foreign key from there to get a row in
263         actor.usr.
264
265         The calling code is responsible for freeing the returned object by calling jsonObjectFree().
266 */
267 jsonObject* oilsUtilsFetchUserByBarcode(const char* barcode) {
268         if(!barcode) return NULL;
269
270         osrfLogInfo(OSRF_LOG_MARK, "Fetching user by barcode %s", barcode);
271
272         jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", barcode);
273         jsonObject* card = oilsUtilsQuickReq(
274                 "open-ils.cstore", "open-ils.cstore.direct.actor.card.search", params );
275         jsonObjectFree(params);
276
277         if(!card)
278                 return NULL;   // No such card
279
280         // Get the user's id as a double
281         char* usr = oilsFMGetString(card, "usr");
282         jsonObjectFree(card);
283         if(!usr)
284                 return NULL;   // No user id (shouldn't happen)
285         double iusr = strtod(usr, NULL);
286         free(usr);
287
288         // Look up the user in actor.usr
289         params = jsonParseFmt("[%f]", iusr);
290         jsonObject* user = oilsUtilsQuickReq(
291                 "open-ils.cstore", "open-ils.cstore.direct.actor.user.retrieve", params);
292
293         jsonObjectFree(params);
294         return user;
295 }
296
297 char* oilsUtilsFetchOrgSetting( int orgid, const char* setting ) {
298         if(!setting) return NULL;
299
300         jsonObject* params = jsonParseFmt("[%d, \"%s\"]", orgid, setting );
301
302         jsonObject* set = oilsUtilsQuickReq(
303                 "open-ils.actor",
304                 "open-ils.actor.ou_setting.ancestor_default", params);
305
306         char* value = jsonObjectToSimpleString(jsonObjectGetKey(set, "value"));
307         jsonObjectFree(params);
308         jsonObjectFree(set);
309         osrfLogDebug(OSRF_LOG_MARK, "Fetched org [%d] setting: %s => %s", orgid, setting, value);
310         return value;
311 }
312
313
314
315 char* oilsUtilsLogin( const char* uname, const char* passwd, const char* type, int orgId ) {
316         if(!(uname && passwd)) return NULL;
317
318         osrfLogDebug(OSRF_LOG_MARK, "Logging in with username %s", uname );
319         char* token = NULL;
320
321         jsonObject* params = jsonParseFmt("[\"%s\"]", uname);
322
323         jsonObject* o = oilsUtilsQuickReq(
324                 "open-ils.auth", "open-ils.auth.authenticate.init", params );
325
326         const char* seed = jsonObjectGetString(o);
327         char* passhash = md5sum(passwd);
328         char buf[256];
329         snprintf(buf, sizeof(buf), "%s%s", seed, passhash);
330         char* fullhash = md5sum(buf);
331
332         jsonObjectFree(o);
333         jsonObjectFree(params);
334         free(passhash);
335
336         params = jsonParseFmt( "[\"%s\", \"%s\", \"%s\", \"%d\"]", uname, fullhash, type, orgId );
337         o = oilsUtilsQuickReq( "open-ils.auth",
338                 "open-ils.auth.authenticate.complete", params );
339
340         if(o) {
341                 const char* tok = jsonObjectGetString(
342                         jsonObjectGetKey(jsonObjectGetKey(o,"payload"), "authtoken"));
343                 if( tok )
344                         token = strdup( tok );
345         }
346
347         free(fullhash);
348         jsonObjectFree(params);
349         jsonObjectFree(o);
350
351         return token;
352 }
353
354
355 jsonObject* oilsUtilsFetchWorkstation( long id ) {
356         jsonObject* p = jsonParseFmt("[%ld]", id);
357         jsonObject* r = oilsUtilsQuickReq(
358                 "open-ils.storage",
359                 "open-ils.storage.direct.actor.workstation.retrieve", p );
360         jsonObjectFree(p);
361         return r;
362 }
363
364 jsonObject* oilsUtilsFetchWorkstationByName( const char* name ) {
365         jsonObject* p = jsonParseFmt("{\"name\":\"%s\"}", name);
366         jsonObject* r = oilsUtilsCStoreReq(
367                 "open-ils.cstore.direct.actor.workstation.search", p);
368         jsonObjectFree(p);
369         return r;
370 }