3 #include "openils/oils_utils.h"
4 #include "openils/oils_idl.h"
6 osrfHash* oilsInitIDL(const char* idl_filename) {
8 char* freeable_filename = NULL;
12 filename = idl_filename;
14 freeable_filename = osrf_settings_host_value("/IDL");
15 filename = freeable_filename;
19 osrfLogError(OSRF_LOG_MARK, "No settings config for '/IDL'");
23 osrfLogInfo(OSRF_LOG_MARK, "Parsing IDL %s", filename);
25 if (!oilsIDLInit( filename )) {
26 osrfLogError(OSRF_LOG_MARK, "Problem loading IDL file [%s]!", filename);
28 free(freeable_filename);
33 free(freeable_filename);
38 @brief Return a const string with the value of a specified column in a row object.
39 @param object Pointer to the row object.
40 @param field Name of the column.
41 @return Pointer to a const string representing the value of the specified column,
42 or NULL in case of error.
44 The row object must be a JSON_ARRAY with a classname. The column value must be a
45 JSON_STRING or a JSON_NUMBER. Any other object type results in a return of NULL.
47 The return value points into the internal contents of the row object, which
50 const char* oilsFMGetStringConst( const jsonObject* object, const char* field ) {
51 return jsonObjectGetString(oilsFMGetObject( object, field ));
55 @brief Return a string with the value of a specified column in a row object.
56 @param object Pointer to the row object.
57 @param field Name of the column.
58 @return Pointer to a newly allocated string representing the value of the specified column,
59 or NULL in case of error.
61 The row object must be a JSON_ARRAY with a classname. The column value must be a
62 JSON_STRING or a JSON_NUMBER. Any other object type results in a return of NULL.
64 The calling code is responsible for freeing the returned string by calling free().
66 char* oilsFMGetString( const jsonObject* object, const char* field ) {
67 return jsonObjectToSimpleString(oilsFMGetObject( object, field ));
71 @brief Return a pointer to the value of a specified column in a row object.
72 @param object Pointer to the row object.
73 @param field Name of the column.
74 @return Pointer to the jsonObject representing the value of the specified column, or NULL
77 The row object must be a JSON_ARRAY with a classname.
79 The return value may point to a JSON_NULL, JSON_STRING, JSON_NUMBER, or JSON_ARRAY. It
80 points into the internal contents of the row object, which retains ownership.
82 const jsonObject* oilsFMGetObject( const jsonObject* object, const char* field ) {
83 if(!(object && field)) return NULL;
84 if( object->type != JSON_ARRAY || !object->classname ) return NULL;
85 int pos = fm_ntop(object->classname, field);
87 return jsonObjectGetIndex( object, pos );
92 int oilsFMSetString( jsonObject* object, const char* field, const char* string ) {
93 if(!(object && field && string)) return -1;
94 osrfLogInternal(OSRF_LOG_MARK, "oilsFMSetString(): Collecing position for field %s", field);
95 int pos = fm_ntop(object->classname, field);
97 osrfLogInternal(OSRF_LOG_MARK, "oilsFMSetString(): Setting string "
98 "%s at field %s [position %d]", string, field, pos );
99 jsonObjectSetIndex( object, pos, jsonNewObject(string) );
106 int oilsUtilsIsDBTrue( const char* val ) {
107 if( val && strcasecmp(val, "f") && strcmp(val, "0") ) return 1;
112 long oilsFMGetObjectId( const jsonObject* obj ) {
115 char* ids = oilsFMGetString( obj, "id" );
123 int oilsUtilsTrackUserActivity(long usr, const char* ewho, const char* ewhat, const char* ehow) {
124 if (!usr && !(ewho || ewhat || ehow)) return 0;
127 jsonObject* params = jsonParseFmt(
128 "{\"from\":[\"actor.insert_usr_activity\", %ld, \"%s\", \"%s\", \"%s\"]}",
130 (NULL == ewho) ? "" : ewho,
131 (NULL == ewhat) ? "" : ewhat,
132 (NULL == ehow) ? "" : ehow
135 osrfAppSession* session = osrfAppSessionClientInit("open-ils.cstore");
136 osrfAppSessionConnect(session);
137 int reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.begin", 1);
138 osrfMessage* omsg = osrfAppSessionRequestRecv(session, reqid, 60);
141 osrfMessageFree(omsg);
142 reqid = osrfAppSessionSendRequest(session, params, "open-ils.cstore.json_query", 1);
143 omsg = osrfAppSessionRequestRecv(session, reqid, 60);
146 const jsonObject* rows = osrfMessageGetResult(omsg);
147 if (rows) rowcount = rows->size;
148 osrfMessageFree(omsg); // frees rows
150 reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.commit", 1);
151 omsg = osrfAppSessionRequestRecv(session, reqid, 60);
152 osrfMessageFree(omsg);
154 reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.rollback", 1);
155 omsg = osrfAppSessionRequestRecv(session, reqid, 60);
156 osrfMessageFree(omsg);
161 osrfAppSessionFree(session); // calls disconnect internally
162 jsonObjectFree(params);
168 oilsEvent* oilsUtilsCheckPerms( int userid, int orgid, char* permissions[], int size ) {
169 if (!permissions) return NULL;
171 oilsEvent* evt = NULL;
173 // Find the root org unit, i.e. the one with no parent.
174 // Assumption: there is only one org unit with no parent.
176 jsonObject* where_clause = jsonParse( "{\"parent_ou\":null}" );
177 jsonObject* org = oilsUtilsQuickReq(
179 "open-ils.cstore.direct.actor.org_unit.search",
182 jsonObjectFree( where_clause );
184 orgid = (int)jsonObjectGetNumber( oilsFMGetObject( org, "id" ) );
189 for( i = 0; i < size && permissions[i]; i++ ) {
191 char* perm = permissions[i];
192 jsonObject* params = jsonParseFmt("[%d, \"%s\", %d]", userid, perm, orgid);
193 jsonObject* o = oilsUtilsQuickReq( "open-ils.storage",
194 "open-ils.storage.permission.user_has_perm", params );
196 char* r = jsonObjectToSimpleString(o);
198 if(r && !strcmp(r, "0"))
199 evt = oilsNewEvent3( OSRF_LOG_MARK, OILS_EVENT_PERM_FAILURE, perm, orgid );
201 jsonObjectFree(params);
213 @brief Perform a remote procedure call.
214 @param service The name of the service to invoke.
215 @param method The name of the method to call.
216 @param params The parameters to be passed to the method, if any.
217 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
218 doesn't return anything.
220 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
221 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
222 single parameter. If it is NULL, pass no parameters.
224 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
226 jsonObject* oilsUtilsQuickReq( const char* service, const char* method,
227 const jsonObject* params ) {
228 if(!(service && method)) return NULL;
230 osrfLogDebug(OSRF_LOG_MARK, "oilsUtilsQuickReq(): %s - %s", service, method );
232 // Open an application session with the service, and send the request
233 osrfAppSession* session = osrfAppSessionClientInit( service );
234 int reqid = osrfAppSessionSendRequest( session, params, method, 1 );
237 osrfMessage* omsg = osrfAppSessionRequestRecv( session, reqid, 60 );
238 jsonObject* result = jsonObjectClone( osrfMessageGetResult(omsg) );
241 osrfMessageFree(omsg);
242 osrfAppSessionFree(session);
247 @brief Call a method of the open-ils.storage service.
248 @param method Name of the method.
249 @param params Parameters to be passed to the method, if any.
250 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
251 doesn't return anything.
253 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
254 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
255 single parameter. If it is NULL, pass no parameters.
257 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
259 jsonObject* oilsUtilsStorageReq( const char* method, const jsonObject* params ) {
260 return oilsUtilsQuickReq( "open-ils.storage", method, params );
264 @brief Call a method of the open-ils.cstore service.
265 @param method Name of the method.
266 @param params Parameters to be passed to the method, if any.
267 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
268 doesn't return anything.
270 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
271 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
272 single parameter. If it is NULL, pass no parameters.
274 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
276 jsonObject* oilsUtilsCStoreReq( const char* method, const jsonObject* params ) {
277 return oilsUtilsQuickReq("open-ils.cstore", method, params);
283 @brief Given a username, fetch the corresponding row from the actor.usr table, if any.
284 @param name The username for which to search.
285 @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
286 or a JSON_NULL if it doesn't.
288 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
290 jsonObject* oilsUtilsFetchUserByUsername( const char* name ) {
291 if(!name) return NULL;
292 jsonObject* params = jsonParseFmt("{\"usrname\":\"%s\"}", name);
293 jsonObject* user = oilsUtilsQuickReq(
294 "open-ils.cstore", "open-ils.cstore.direct.actor.user.search", params );
296 jsonObjectFree(params);
297 long id = oilsFMGetObjectId(user);
298 osrfLogDebug(OSRF_LOG_MARK, "Fetched user %s:%ld", name, id);
303 @brief Given a barcode, fetch the corresponding row from the actor.usr table, if any.
304 @param name The barcode for which to search.
305 @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
306 or a JSON_NULL if it doesn't.
308 Look up the barcode in actor.card. Follow a foreign key from there to get a row in
311 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
313 jsonObject* oilsUtilsFetchUserByBarcode(const char* barcode) {
314 if(!barcode) return NULL;
316 osrfLogInfo(OSRF_LOG_MARK, "Fetching user by barcode %s", barcode);
318 jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", barcode);
319 jsonObject* card = oilsUtilsQuickReq(
320 "open-ils.cstore", "open-ils.cstore.direct.actor.card.search", params );
321 jsonObjectFree(params);
324 return NULL; // No such card
326 // Get the user's id as a double
327 char* usr = oilsFMGetString(card, "usr");
328 jsonObjectFree(card);
330 return NULL; // No user id (shouldn't happen)
331 double iusr = strtod(usr, NULL);
334 // Look up the user in actor.usr
335 params = jsonParseFmt("[%f]", iusr);
336 jsonObject* user = oilsUtilsQuickReq(
337 "open-ils.cstore", "open-ils.cstore.direct.actor.user.retrieve", params);
339 jsonObjectFree(params);
343 char* oilsUtilsFetchOrgSetting( int orgid, const char* setting ) {
344 if(!setting) return NULL;
346 jsonObject* params = jsonParseFmt("[%d, \"%s\"]", orgid, setting );
348 jsonObject* set = oilsUtilsQuickReq(
350 "open-ils.actor.ou_setting.ancestor_default", params);
352 char* value = jsonObjectToSimpleString( jsonObjectGetKeyConst( set, "value" ));
353 jsonObjectFree(params);
355 osrfLogDebug(OSRF_LOG_MARK, "Fetched org [%d] setting: %s => %s", orgid, setting, value);
361 char* oilsUtilsLogin( const char* uname, const char* passwd, const char* type, int orgId ) {
362 if(!(uname && passwd)) return NULL;
364 osrfLogDebug(OSRF_LOG_MARK, "Logging in with username %s", uname );
367 jsonObject* params = jsonParseFmt("[\"%s\"]", uname);
369 jsonObject* o = oilsUtilsQuickReq(
370 "open-ils.auth", "open-ils.auth.authenticate.init", params );
372 const char* seed = jsonObjectGetString(o);
373 char* passhash = md5sum(passwd);
375 snprintf(buf, sizeof(buf), "%s%s", seed, passhash);
376 char* fullhash = md5sum(buf);
379 jsonObjectFree(params);
382 params = jsonParseFmt( "[\"%s\", \"%s\", \"%s\", \"%d\"]", uname, fullhash, type, orgId );
383 o = oilsUtilsQuickReq( "open-ils.auth",
384 "open-ils.auth.authenticate.complete", params );
387 const char* tok = jsonObjectGetString(
388 jsonObjectGetKeyConst( jsonObjectGetKey( o,"payload" ), "authtoken" ));
390 token = strdup( tok );
394 jsonObjectFree(params);
401 jsonObject* oilsUtilsFetchWorkstation( long id ) {
402 jsonObject* p = jsonParseFmt("[%ld]", id);
403 jsonObject* r = oilsUtilsQuickReq(
405 "open-ils.storage.direct.actor.workstation.retrieve", p );
410 jsonObject* oilsUtilsFetchWorkstationByName( const char* name ) {
411 jsonObject* p = jsonParseFmt("{\"name\":\"%s\"}", name);
412 jsonObject* r = oilsUtilsCStoreReq(
413 "open-ils.cstore.direct.actor.workstation.search", p);
419 @brief Convert a string to a number representing a time interval in seconds.
420 @param interval Pointer to string, e.g. "420" or "2 weeks".
421 @return If successful, the number of seconds that the string represents; otherwise -1.
423 If the string is all digits (apart from any leading or trailing white space), convert
424 it directly. Otherwise pass it to PostgreSQL for translation.
426 The result is the same as if we were to pass every string to PostgreSQL, except that,
427 depending on the value of LONG_MAX, we return values for some strings that represent
428 intervals too long for PostgreSQL to represent (i.e. more than 2147483647 seconds).
430 WARNING: a valid interval of -1 second will be indistinguishable from an error. If
431 such an interval is a plausible possibility, don't use this function.
433 long oilsUtilsIntervalToSeconds( const char* s ) {
436 osrfLogWarning( OSRF_LOG_MARK, "String to be converted is NULL" );
440 // Skip leading white space
441 while( isspace( (unsigned char) *s ))
445 osrfLogWarning( OSRF_LOG_MARK, "String to be converted is empty or all white space" );
449 // See if the string is a raw number, i.e. all digits
450 // (apart from any leading or trailing white space)
452 const char* p = s; // For traversing and examining the remaining string
453 if( isdigit( (unsigned char) *p )) {
454 // Looks like a number so far...skip over the digits
457 } while( isdigit( (unsigned char) *p ));
458 // Skip over any following white space
459 while( isspace( (unsigned char) *p ))
462 // This string is a raw number. Convert it directly.
463 long n = strtol( s, NULL, 10 );
464 if( LONG_MAX == n ) {
466 osrfLogWarning( OSRF_LOG_MARK,
467 "String \"%s\"represents a number too big for a long", s );
474 // If we get to this point, the string is not all digits. Pass it to PostgreSQL.
477 jsonObject* query_obj = jsonParseFmt(
478 "{\"from\":[\"config.interval_to_seconds\",\"%s\"]}", s );
481 jsonObject* result = oilsUtilsCStoreReq(
482 "open-ils.cstore.json_query", query_obj );
483 jsonObjectFree( query_obj );
486 const jsonObject* seconds_obj = jsonObjectGetKeyConst( result, "config.interval_to_seconds" );
488 if( seconds_obj && JSON_NUMBER == seconds_obj->type )
489 seconds = (long) jsonObjectGetNumber( seconds_obj );
491 osrfLogError( OSRF_LOG_MARK,
492 "Error calling json_query to convert \"%s\" to seconds", s );
494 jsonObjectFree( result );