2 #include "openils/oils_utils.h"
3 #include "openils/oils_idl.h"
5 osrfHash* oilsInitIDL(const char* idl_filename) {
7 char* freeable_filename = NULL;
11 filename = idl_filename;
13 freeable_filename = osrf_settings_host_value("/IDL");
14 filename = freeable_filename;
18 osrfLogError(OSRF_LOG_MARK, "No settings config for '/IDL'");
22 osrfLogInfo(OSRF_LOG_MARK, "Parsing IDL %s", filename);
24 if (!oilsIDLInit( filename )) {
25 osrfLogError(OSRF_LOG_MARK, "Problem loading IDL file [%s]!", filename);
27 free(freeable_filename);
32 free(freeable_filename);
37 @brief Return a const string with the value of a specified column in a row object.
38 @param object Pointer to the row object.
39 @param field Name of the column.
40 @return Pointer to a const string representing the value of the specified column,
41 or NULL in case of error.
43 The row object must be a JSON_ARRAY with a classname. The column value must be a
44 JSON_STRING or a JSON_NUMBER. Any other object type results in a return of NULL.
46 The return value points into the internal contents of the row object, which
49 const char* oilsFMGetStringConst( const jsonObject* object, const char* field ) {
50 return jsonObjectGetString(oilsFMGetObject( object, field ));
54 @brief Return a string with the value of a specified column in a row object.
55 @param object Pointer to the row object.
56 @param field Name of the column.
57 @return Pointer to a newly allocated string representing the value of the specified column,
58 or NULL in case of error.
60 The row object must be a JSON_ARRAY with a classname. The column value must be a
61 JSON_STRING or a JSON_NUMBER. Any other object type results in a return of NULL.
63 The calling code is responsible for freeing the returned string by calling free().
65 char* oilsFMGetString( const jsonObject* object, const char* field ) {
66 return jsonObjectToSimpleString(oilsFMGetObject( object, field ));
70 @brief Return a pointer to the value of a specified column in a row object.
71 @param object Pointer to the row object.
72 @param field Name of the column.
73 @return Pointer to the jsonObject representing the value of the specified column, or NULL
76 The row object must be a JSON_ARRAY with a classname.
78 The return value may point to a JSON_NULL, JSON_STRING, JSON_NUMBER, or JSON_ARRAY. It
79 points into the internal contents of the row object, which retains ownership.
81 const jsonObject* oilsFMGetObject( const jsonObject* object, const char* field ) {
82 if(!(object && field)) return NULL;
83 if( object->type != JSON_ARRAY || !object->classname ) return NULL;
84 int pos = fm_ntop(object->classname, field);
86 return jsonObjectGetIndex( object, pos );
91 int oilsFMSetString( jsonObject* object, const char* field, const char* string ) {
92 if(!(object && field && string)) return -1;
93 osrfLogInternal(OSRF_LOG_MARK, "oilsFMSetString(): Collecing position for field %s", field);
94 int pos = fm_ntop(object->classname, field);
96 osrfLogInternal(OSRF_LOG_MARK, "oilsFMSetString(): Setting string "
97 "%s at field %s [position %d]", string, field, pos );
98 jsonObjectSetIndex( object, pos, jsonNewObject(string) );
105 int oilsUtilsIsDBTrue( const char* val ) {
106 if( val && strcasecmp(val, "f") && strcmp(val, "0") ) return 1;
111 long oilsFMGetObjectId( const jsonObject* obj ) {
114 char* ids = oilsFMGetString( obj, "id" );
123 oilsEvent* oilsUtilsCheckPerms( int userid, int orgid, char* permissions[], int size ) {
124 if (!permissions) return NULL;
126 oilsEvent* evt = NULL;
128 // Find the root org unit, i.e. the one with no parent.
129 // Assumption: there is only one org unit with no parent.
131 jsonObject* where_clause = jsonParse( "{\"parent_ou\":null}" );
132 jsonObject* org = oilsUtilsQuickReq(
134 "open-ils.cstore.direct.actor.org_unit.search",
137 jsonObjectFree( where_clause );
139 orgid = (int)jsonObjectGetNumber( oilsFMGetObject( org, "id" ) );
144 for( i = 0; i < size && permissions[i]; i++ ) {
146 char* perm = permissions[i];
147 jsonObject* params = jsonParseFmt("[%d, \"%s\", %d]", userid, perm, orgid);
148 jsonObject* o = oilsUtilsQuickReq( "open-ils.storage",
149 "open-ils.storage.permission.user_has_perm", params );
151 char* r = jsonObjectToSimpleString(o);
153 if(r && !strcmp(r, "0"))
154 evt = oilsNewEvent3( OSRF_LOG_MARK, OILS_EVENT_PERM_FAILURE, perm, orgid );
156 jsonObjectFree(params);
168 @brief Perform a remote procedure call.
169 @param service The name of the service to invoke.
170 @param method The name of the method to call.
171 @param params The parameters to be passed to the method, if any.
172 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
173 doesn't return anything.
175 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
176 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
177 single parameter. If it is NULL, pass no parameters.
179 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
181 jsonObject* oilsUtilsQuickReq( const char* service, const char* method,
182 const jsonObject* params ) {
183 if(!(service && method)) return NULL;
185 osrfLogDebug(OSRF_LOG_MARK, "oilsUtilsQuickReq(): %s - %s", service, method );
187 // Open an application session with the service, and send the request
188 osrfAppSession* session = osrfAppSessionClientInit( service );
189 int reqid = osrfAppSessionSendRequest( session, params, method, 1 );
192 osrfMessage* omsg = osrfAppSessionRequestRecv( session, reqid, 60 );
193 jsonObject* result = jsonObjectClone( osrfMessageGetResult(omsg) );
196 osrfMessageFree(omsg);
197 osrfAppSessionFree(session);
202 @brief Call a method of the open-ils.storage service.
203 @param method Name of the method.
204 @param params Parameters to be passed to the method, if any.
205 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
206 doesn't return anything.
208 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
209 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
210 single parameter. If it is NULL, pass no parameters.
212 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
214 jsonObject* oilsUtilsStorageReq( const char* method, const jsonObject* params ) {
215 return oilsUtilsQuickReq( "open-ils.storage", method, params );
219 @brief Call a method of the open-ils.cstore service.
220 @param method Name of the method.
221 @param params Parameters to be passed to the method, if any.
222 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
223 doesn't return anything.
225 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
226 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
227 single parameter. If it is NULL, pass no parameters.
229 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
231 jsonObject* oilsUtilsCStoreReq( const char* method, const jsonObject* params ) {
232 return oilsUtilsQuickReq("open-ils.cstore", method, params);
238 @brief Given a username, fetch the corresponding row from the actor.usr table, if any.
239 @param name The username for which to search.
240 @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
241 or a JSON_NULL if it doesn't.
243 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
245 jsonObject* oilsUtilsFetchUserByUsername( const char* name ) {
246 if(!name) return NULL;
247 jsonObject* params = jsonParseFmt("{\"usrname\":\"%s\"}", name);
248 jsonObject* user = oilsUtilsQuickReq(
249 "open-ils.cstore", "open-ils.cstore.direct.actor.user.search", params );
251 jsonObjectFree(params);
252 long id = oilsFMGetObjectId(user);
253 osrfLogDebug(OSRF_LOG_MARK, "Fetched user %s:%ld", name, id);
258 @brief Given a barcode, fetch the corresponding row from the actor.usr table, if any.
259 @param name The barcode for which to search.
260 @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
261 or a JSON_NULL if it doesn't.
263 Look up the barcode in actor.card. Follow a foreign key from there to get a row in
266 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
268 jsonObject* oilsUtilsFetchUserByBarcode(const char* barcode) {
269 if(!barcode) return NULL;
271 osrfLogInfo(OSRF_LOG_MARK, "Fetching user by barcode %s", barcode);
273 jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", barcode);
274 jsonObject* card = oilsUtilsQuickReq(
275 "open-ils.cstore", "open-ils.cstore.direct.actor.card.search", params );
276 jsonObjectFree(params);
279 return NULL; // No such card
281 // Get the user's id as a double
282 char* usr = oilsFMGetString(card, "usr");
283 jsonObjectFree(card);
285 return NULL; // No user id (shouldn't happen)
286 double iusr = strtod(usr, NULL);
289 // Look up the user in actor.usr
290 params = jsonParseFmt("[%f]", iusr);
291 jsonObject* user = oilsUtilsQuickReq(
292 "open-ils.cstore", "open-ils.cstore.direct.actor.user.retrieve", params);
294 jsonObjectFree(params);
298 char* oilsUtilsFetchOrgSetting( int orgid, const char* setting ) {
299 if(!setting) return NULL;
301 jsonObject* params = jsonParseFmt("[%d, \"%s\"]", orgid, setting );
303 jsonObject* set = oilsUtilsQuickReq(
305 "open-ils.actor.ou_setting.ancestor_default", params);
307 char* value = jsonObjectToSimpleString(jsonObjectGetKey(set, "value"));
308 jsonObjectFree(params);
310 osrfLogDebug(OSRF_LOG_MARK, "Fetched org [%d] setting: %s => %s", orgid, setting, value);
316 char* oilsUtilsLogin( const char* uname, const char* passwd, const char* type, int orgId ) {
317 if(!(uname && passwd)) return NULL;
319 osrfLogDebug(OSRF_LOG_MARK, "Logging in with username %s", uname );
322 jsonObject* params = jsonParseFmt("[\"%s\"]", uname);
324 jsonObject* o = oilsUtilsQuickReq(
325 "open-ils.auth", "open-ils.auth.authenticate.init", params );
327 const char* seed = jsonObjectGetString(o);
328 char* passhash = md5sum(passwd);
330 snprintf(buf, sizeof(buf), "%s%s", seed, passhash);
331 char* fullhash = md5sum(buf);
334 jsonObjectFree(params);
337 params = jsonParseFmt( "[\"%s\", \"%s\", \"%s\", \"%d\"]", uname, fullhash, type, orgId );
338 o = oilsUtilsQuickReq( "open-ils.auth",
339 "open-ils.auth.authenticate.complete", params );
342 const char* tok = jsonObjectGetString(
343 jsonObjectGetKey(jsonObjectGetKey(o,"payload"), "authtoken"));
345 token = strdup( tok );
349 jsonObjectFree(params);
356 jsonObject* oilsUtilsFetchWorkstation( long id ) {
357 jsonObject* p = jsonParseFmt("[%ld]", id);
358 jsonObject* r = oilsUtilsQuickReq(
360 "open-ils.storage.direct.actor.workstation.retrieve", p );
365 jsonObject* oilsUtilsFetchWorkstationByName( const char* name ) {
366 jsonObject* p = jsonParseFmt("{\"name\":\"%s\"}", name);
367 jsonObject* r = oilsUtilsCStoreReq(
368 "open-ils.cstore.direct.actor.workstation.search", p);
374 @brief Convert a string to a number representing a time interval in seconds.
375 @param interval Pointer to string, e.g. "420" or "2 weeks".
376 @return If successful, the number of seconds that the string represents; otherwise -1.
378 If the string is all digits (apart from any leading or trailing white space), convert
379 it directly. Otherwise pass it to PostgreSQL for translation.
381 The result is the same as if we were to pass every string to PostgreSQL, except that,
382 depending on the value of LONG_MAX, we return values for some strings that represent
383 intervals too long for PostgreSQL to represent (i.e. more than 2147483647 seconds).
385 WARNING: a valid interval of -1 second will be indistinguishable from an error. If
386 such an interval is a plausible possibility, don't use this function.
388 long oilsUtilsIntervalToSeconds( const char* s ) {
391 osrfLogWarning( OSRF_LOG_MARK, "String to be converted is NULL" );
395 // Skip leading white space
396 while( isspace( (unsigned char) *s ))
400 osrfLogWarning( OSRF_LOG_MARK, "String to be converted is empty or all white space" );
404 // See if the string is a raw number, i.e. all digits
405 // (apart from any leading or trailing white space)
407 const char* p = s; // For traversing and examining the remaining string
408 if( isdigit( (unsigned char) *p )) {
409 // Looks like a number so far...skip over the digits
412 } while( isdigit( (unsigned char) *p ));
413 // Skip over any following white space
414 while( isspace( (unsigned char) *p ))
417 // This string is a raw number. Convert it directly.
418 long n = strtol( s, NULL, 10 );
419 if( LONG_MAX == n ) {
421 osrfLogWarning( OSRF_LOG_MARK,
422 "String \"%s\"represents a number too big for a long", s );
429 // If we get to this point, the string is not all digits. Pass it to PostgreSQL.
432 jsonObject* query_obj = jsonParseFmt(
433 "{\"from\":[\"config.interval_to_seconds\",\"%s\"]}", s );
436 jsonObject* result = oilsUtilsCStoreReq(
437 "open-ils.cstore.json_query", query_obj );
438 jsonObjectFree( query_obj );
441 jsonObject* seconds_obj = jsonObjectGetKey( result, "config.interval_to_seconds" );
443 if( seconds_obj && JSON_NUMBER == seconds_obj->type )
444 seconds = (long) jsonObjectGetNumber( seconds_obj );
446 osrfLogError( OSRF_LOG_MARK,
447 "Error calling json_query to convert \"%s\" to seconds", s );
449 jsonObjectFree( result );