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" );
124 oilsEvent* oilsUtilsCheckPerms( int userid, int orgid, char* permissions[], int size ) {
125 if (!permissions) return NULL;
127 oilsEvent* evt = NULL;
129 // Find the root org unit, i.e. the one with no parent.
130 // Assumption: there is only one org unit with no parent.
132 jsonObject* where_clause = jsonParse( "{\"parent_ou\":null}" );
133 jsonObject* org = oilsUtilsQuickReq(
135 "open-ils.cstore.direct.actor.org_unit.search",
138 jsonObjectFree( where_clause );
140 orgid = (int)jsonObjectGetNumber( oilsFMGetObject( org, "id" ) );
145 for( i = 0; i < size && permissions[i]; i++ ) {
147 char* perm = permissions[i];
148 jsonObject* params = jsonParseFmt("[%d, \"%s\", %d]", userid, perm, orgid);
149 jsonObject* o = oilsUtilsQuickReq( "open-ils.storage",
150 "open-ils.storage.permission.user_has_perm", params );
152 char* r = jsonObjectToSimpleString(o);
154 if(r && !strcmp(r, "0"))
155 evt = oilsNewEvent3( OSRF_LOG_MARK, OILS_EVENT_PERM_FAILURE, perm, orgid );
157 jsonObjectFree(params);
169 @brief Perform a remote procedure call.
170 @param service The name of the service to invoke.
171 @param method The name of the method to call.
172 @param params The parameters to be passed to the method, if any.
173 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
174 doesn't return anything.
176 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
177 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
178 single parameter. If it is NULL, pass no parameters.
180 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
182 jsonObject* oilsUtilsQuickReq( const char* service, const char* method,
183 const jsonObject* params ) {
184 if(!(service && method)) return NULL;
186 osrfLogDebug(OSRF_LOG_MARK, "oilsUtilsQuickReq(): %s - %s", service, method );
188 // Open an application session with the service, and send the request
189 osrfAppSession* session = osrfAppSessionClientInit( service );
190 int reqid = osrfAppSessionSendRequest( session, params, method, 1 );
193 osrfMessage* omsg = osrfAppSessionRequestRecv( session, reqid, 60 );
194 jsonObject* result = jsonObjectClone( osrfMessageGetResult(omsg) );
197 osrfMessageFree(omsg);
198 osrfAppSessionFree(session);
203 @brief Call a method of the open-ils.storage service.
204 @param method Name of the method.
205 @param params Parameters to be passed to the method, if any.
206 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
207 doesn't return anything.
209 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
210 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
211 single parameter. If it is NULL, pass no parameters.
213 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
215 jsonObject* oilsUtilsStorageReq( const char* method, const jsonObject* params ) {
216 return oilsUtilsQuickReq( "open-ils.storage", method, params );
220 @brief Call a method of the open-ils.cstore service.
221 @param method Name of the method.
222 @param params Parameters to be passed to the method, if any.
223 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
224 doesn't return anything.
226 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
227 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
228 single parameter. If it is NULL, pass no parameters.
230 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
232 jsonObject* oilsUtilsCStoreReq( const char* method, const jsonObject* params ) {
233 return oilsUtilsQuickReq("open-ils.cstore", method, params);
239 @brief Given a username, fetch the corresponding row from the actor.usr table, if any.
240 @param name The username for which to search.
241 @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
242 or a JSON_NULL if it doesn't.
244 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
246 jsonObject* oilsUtilsFetchUserByUsername( const char* name ) {
247 if(!name) return NULL;
248 jsonObject* params = jsonParseFmt("{\"usrname\":\"%s\"}", name);
249 jsonObject* user = oilsUtilsQuickReq(
250 "open-ils.cstore", "open-ils.cstore.direct.actor.user.search", params );
252 jsonObjectFree(params);
253 long id = oilsFMGetObjectId(user);
254 osrfLogDebug(OSRF_LOG_MARK, "Fetched user %s:%ld", name, id);
259 @brief Given a barcode, fetch the corresponding row from the actor.usr table, if any.
260 @param name The barcode for which to search.
261 @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
262 or a JSON_NULL if it doesn't.
264 Look up the barcode in actor.card. Follow a foreign key from there to get a row in
267 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
269 jsonObject* oilsUtilsFetchUserByBarcode(const char* barcode) {
270 if(!barcode) return NULL;
272 osrfLogInfo(OSRF_LOG_MARK, "Fetching user by barcode %s", barcode);
274 jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", barcode);
275 jsonObject* card = oilsUtilsQuickReq(
276 "open-ils.cstore", "open-ils.cstore.direct.actor.card.search", params );
277 jsonObjectFree(params);
280 return NULL; // No such card
282 // Get the user's id as a double
283 char* usr = oilsFMGetString(card, "usr");
284 jsonObjectFree(card);
286 return NULL; // No user id (shouldn't happen)
287 double iusr = strtod(usr, NULL);
290 // Look up the user in actor.usr
291 params = jsonParseFmt("[%f]", iusr);
292 jsonObject* user = oilsUtilsQuickReq(
293 "open-ils.cstore", "open-ils.cstore.direct.actor.user.retrieve", params);
295 jsonObjectFree(params);
299 char* oilsUtilsFetchOrgSetting( int orgid, const char* setting ) {
300 if(!setting) return NULL;
302 jsonObject* params = jsonParseFmt("[%d, \"%s\"]", orgid, setting );
304 jsonObject* set = oilsUtilsQuickReq(
306 "open-ils.actor.ou_setting.ancestor_default", params);
308 char* value = jsonObjectToSimpleString(jsonObjectGetKey(set, "value"));
309 jsonObjectFree(params);
311 osrfLogDebug(OSRF_LOG_MARK, "Fetched org [%d] setting: %s => %s", orgid, setting, value);
317 char* oilsUtilsLogin( const char* uname, const char* passwd, const char* type, int orgId ) {
318 if(!(uname && passwd)) return NULL;
320 osrfLogDebug(OSRF_LOG_MARK, "Logging in with username %s", uname );
323 jsonObject* params = jsonParseFmt("[\"%s\"]", uname);
325 jsonObject* o = oilsUtilsQuickReq(
326 "open-ils.auth", "open-ils.auth.authenticate.init", params );
328 const char* seed = jsonObjectGetString(o);
329 char* passhash = md5sum(passwd);
331 snprintf(buf, sizeof(buf), "%s%s", seed, passhash);
332 char* fullhash = md5sum(buf);
335 jsonObjectFree(params);
338 params = jsonParseFmt( "[\"%s\", \"%s\", \"%s\", \"%d\"]", uname, fullhash, type, orgId );
339 o = oilsUtilsQuickReq( "open-ils.auth",
340 "open-ils.auth.authenticate.complete", params );
343 const char* tok = jsonObjectGetString(
344 jsonObjectGetKey(jsonObjectGetKey(o,"payload"), "authtoken"));
346 token = strdup( tok );
350 jsonObjectFree(params);
357 jsonObject* oilsUtilsFetchWorkstation( long id ) {
358 jsonObject* p = jsonParseFmt("[%ld]", id);
359 jsonObject* r = oilsUtilsQuickReq(
361 "open-ils.storage.direct.actor.workstation.retrieve", p );
366 jsonObject* oilsUtilsFetchWorkstationByName( const char* name ) {
367 jsonObject* p = jsonParseFmt("{\"name\":\"%s\"}", name);
368 jsonObject* r = oilsUtilsCStoreReq(
369 "open-ils.cstore.direct.actor.workstation.search", p);
375 @brief Convert a string to a number representing a time interval in seconds.
376 @param interval Pointer to string, e.g. "420" or "2 weeks".
377 @return If successful, the number of seconds that the string represents; otherwise -1.
379 If the string is all digits (apart from any leading or trailing white space), convert
380 it directly. Otherwise pass it to PostgreSQL for translation.
382 The result is the same as if we were to pass every string to PostgreSQL, except that,
383 depending on the value of LONG_MAX, we return values for some strings that represent
384 intervals too long for PostgreSQL to represent (i.e. more than 2147483647 seconds).
386 WARNING: a valid interval of -1 second will be indistinguishable from an error. If
387 such an interval is a plausible possibility, don't use this function.
389 long oilsUtilsIntervalToSeconds( const char* s ) {
392 osrfLogWarning( OSRF_LOG_MARK, "String to be converted is NULL" );
396 // Skip leading white space
397 while( isspace( (unsigned char) *s ))
401 osrfLogWarning( OSRF_LOG_MARK, "String to be converted is empty or all white space" );
405 // See if the string is a raw number, i.e. all digits
406 // (apart from any leading or trailing white space)
408 const char* p = s; // For traversing and examining the remaining string
409 if( isdigit( (unsigned char) *p )) {
410 // Looks like a number so far...skip over the digits
413 } while( isdigit( (unsigned char) *p ));
414 // Skip over any following white space
415 while( isspace( (unsigned char) *p ))
418 // This string is a raw number. Convert it directly.
419 long n = strtol( s, NULL, 10 );
420 if( LONG_MAX == n ) {
422 osrfLogWarning( OSRF_LOG_MARK,
423 "String \"%s\"represents a number too big for a long", s );
430 // If we get to this point, the string is not all digits. Pass it to PostgreSQL.
433 jsonObject* query_obj = jsonParseFmt(
434 "{\"from\":[\"config.interval_to_seconds\",\"%s\"]}", s );
437 jsonObject* result = oilsUtilsCStoreReq(
438 "open-ils.cstore.json_query", query_obj );
439 jsonObjectFree( query_obj );
442 jsonObject* seconds_obj = jsonObjectGetKey( result, "config.interval_to_seconds" );
444 if( seconds_obj && JSON_NUMBER == seconds_obj->type )
445 seconds = (long) jsonObjectGetNumber( seconds_obj );
447 osrfLogError( OSRF_LOG_MARK,
448 "Error calling json_query to convert \"%s\" to seconds", s );
450 jsonObjectFree( result );