]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/srfsh/srfsh.c
added login functionality to the shell
[OpenSRF.git] / src / srfsh / srfsh.c
1 #include "srfsh.h"
2
3 int caught_sigint = 0;
4
5 int main( int argc, char* argv[] ) {
6
7
8
9         /* --------------------------------------------- */
10         if( argc < 2 ) {
11
12                 /* see if they have a .srfsh.xml in their home directory */
13                 char* home = getenv("HOME");
14                 int l = strlen(home) + 36;
15                 char fbuf[l];
16                 memset(fbuf, 0, l);
17                 sprintf(fbuf,"%s/.srfsh.xml",home);
18
19                 if(!access(fbuf, R_OK)) {
20                         if( ! osrf_system_bootstrap_client(fbuf) ) 
21                                 fatal_handler( "Unable to bootstrap client for requests");
22
23                 } else {
24                         fatal_handler( "No Config file found at %s and none specified. "
25                                         "\nusage: %s <config_file>", fbuf, argv[0] );
26                 }
27
28         } else {
29                 if( ! osrf_system_bootstrap_client(argv[1]) ) 
30                         fatal_handler( "Unable to bootstrap client for requests");
31         }
32         /* --------------------------------------------- */
33         load_history();
34
35
36         client = osrf_system_get_transport_client();
37
38
39         /* main process loop */
40         char* request;
41         signal(SIGINT,sig_int_handler);
42         while((request=readline(prompt))) {
43
44                 if( !strcmp(request, "exit") || !strcmp(request,"quit")) 
45                         break; 
46
47                 char* req_copy = strdup(request);
48
49                 parse_request( req_copy ); 
50                 if( request && strlen(request) > 1 ) {
51                         add_history(request);
52                 }
53
54                 free(request);
55                 free(req_copy);
56         }
57
58         if(history_file != NULL )
59                 write_history(history_file);
60         free(request);
61         client_disconnect( client );
62         client_free( client );  
63         config_reader_free();   
64         log_free();
65                 
66         return 0;
67 }
68
69 void sig_child_handler( int s ) {
70         child_dead = 1;
71 }
72
73 void sig_int_handler( int s ) {
74         printf("\n");
75         caught_sigint = 1;
76         signal(SIGINT,sig_int_handler);
77 }
78
79 int load_history() {
80
81         char* home = getenv("HOME");
82         int l = strlen(home) + 24;
83         char fbuf[l];
84
85         memset(fbuf, 0, l);
86         sprintf(fbuf,"%s/.srfsh_history",home);
87         history_file = strdup(fbuf);
88
89         if(!access(history_file, W_OK | R_OK )) {
90                 //set_history_length(999);
91                 history_length = 999;
92                 read_history(history_file);
93         }
94         return 1;
95 }
96
97
98 int parse_error( char* words[] ) {
99
100         if( ! words )
101                 return 0;
102
103         int i = 0;
104         char* current;
105         char buffer[256];
106         memset(buffer, 0, 256);
107         while( (current=words[i++]) ) {
108                 strcat(buffer, current);
109                 strcat(buffer, " ");
110         }
111         if( ! buffer || strlen(buffer) < 1 ) 
112                 printf("\n");
113
114         fprintf( stderr, "???: %s\n", buffer );
115         return 0;
116
117 }
118
119
120 int parse_request( char* request ) {
121
122         if( request == NULL )
123                 return 0;
124
125         int ret_val = 0;
126         int i = 0;
127         char* words[COMMAND_BUFSIZE]; 
128         memset(words,0,COMMAND_BUFSIZE);
129         char* req = request;
130
131         char* cur_tok = strtok( req, " " );
132
133         if( cur_tok == NULL )
134                 return 0;
135
136         while(cur_tok != NULL) {
137                 words[i++] = cur_tok;
138                 cur_tok = strtok( NULL, " " );
139         }
140
141
142         // not sure why (strtok?), but this is necessary
143         memset( words + i, 0, COMMAND_BUFSIZE - i );
144
145         /* pass off to the top level command */
146         if( !strcmp(words[0],"router") ) 
147                 ret_val = handle_router( words );
148
149         else if( !strcmp(words[0],"time") ) 
150                 ret_val = handle_time( words );
151
152         else if (!strcmp(words[0],"request"))
153                 ret_val = handle_request( words, 0 );
154
155         else if (!strcmp(words[0],"relay"))
156                 ret_val = handle_request( words, 1 );
157
158         else if (!strcmp(words[0],"help"))
159                 ret_val = print_help();
160
161         else if (!strcmp(words[0],"set"))
162                 ret_val = handle_set(words);
163
164         else if (!strcmp(words[0],"print"))
165                 ret_val = handle_print(words);
166
167         else if (!strcmp(words[0],"math_bench"))
168                 ret_val = handle_math(words);
169
170         else if (!strcmp(words[0],"introspect"))
171                 ret_val = handle_introspect(words);
172
173         else if (!strcmp(words[0],"login"))
174                 ret_val = handle_login(words);
175
176         else if (words[0][0] == '!')
177                 ret_val = handle_exec( words );
178
179         if(!ret_val)
180                 return parse_error( words );
181
182         return 1;
183
184 }
185
186
187 int handle_introspect(char* words[]) {
188
189         if(words[1]) {
190                 fprintf(stderr, "--> %s\n", words[1]);
191                 char buf[256];
192                 memset(buf,0,256);
193                 sprintf( buf, "request %s opensrf.system.method.all", words[1] );
194                 return parse_request( buf );
195         }
196
197         return 0;
198 }
199
200
201 int handle_login( char* words[]) {
202
203         if( words[1] && words[2]) {
204
205                 char* username = words[1];
206                 char* password = words[2];
207
208                 char buf[256];
209                 memset(buf,0,256);
210
211                 char buf2[256];
212                 memset(buf2,0,256);
213
214                 sprintf( buf, 
215                                 "request open-ils.auth open-ils.auth.authenticate.init \"%s\"", username );
216                 parse_request(buf); 
217
218                 char* hash = json_object_get_string( last_result->result_content );
219
220                 char* pass_buf = md5sum(password);
221
222                 printf("passowrd after %s\n", pass_buf );
223
224                 char both_buf[256];
225                 memset(both_buf,0,256);
226                 sprintf(both_buf,"%s%s",hash, pass_buf);
227
228                 char* mess_buf = md5sum(both_buf);
229
230                 printf("sending %s\n", mess_buf );
231
232                 sprintf( buf2,
233                                 "request open-ils.auth open-ils.auth.authenticate.complete \"%s\", \"%s\"", 
234                                 username, mess_buf );
235
236                 free(pass_buf);
237                 free(mess_buf);
238
239                 parse_request( buf2 );
240
241                 login_session = json_object_get_string( last_result->result_content );
242
243                 printf("Login Session: %s\n", login_session );
244                 
245                 return 1;
246
247         }
248
249         return 0;
250 }
251
252 char* md5sum( char* text ) {
253
254         struct md5_ctx ctx;
255         unsigned char digest[16];
256
257         MD5_start (&ctx);
258
259         int i;
260         for ( i=0 ; i != strlen(text) ; i++ )
261                 MD5_feed (&ctx, text[i]);
262
263         MD5_stop (&ctx, digest);
264
265         char buf[16];
266         memset(buf,0,16);
267
268         char final[256];
269         memset(final,0,256);
270
271         for ( i=0 ; i<16 ; i++ ) {
272                 sprintf(buf, "%02x", digest[i]);
273                 strcat( final, buf );
274         }
275
276         return strdup(final);
277
278 }
279
280
281 int handle_set( char* words[]) {
282
283         char* variable;
284         if( (variable=words[1]) ) {
285
286                 char* val;
287                 if( (val=words[2]) ) {
288
289                         if(!strcmp(variable,"pretty_print")) {
290                                 if(!strcmp(val,"true")) {
291                                         pretty_print = 1;
292                                         printf("pretty_print = true\n");
293                                         return 1;
294                                 } 
295                                 if(!strcmp(val,"false")) {
296                                         pretty_print = 0;
297                                         printf("pretty_print = false\n");
298                                         return 1;
299                                 } 
300                         }
301                 }
302         }
303
304         return 0;
305 }
306
307
308 int handle_print( char* words[]) {
309
310         char* variable;
311         if( (variable=words[1]) ) {
312                 if(!strcmp(variable,"pretty_print")) {
313                         if(pretty_print) {
314                                 printf("pretty_print = true\n");
315                                 return 1;
316                         } else {
317                                 printf("pretty_print = false\n");
318                                 return 1;
319                         }
320                 }
321
322                 if(!strcmp(variable,"login")) {
323                         printf("login session = %s\n", login_session );
324                         return 1;
325                 }
326
327         }
328         return 0;
329 }
330
331 int handle_router( char* words[] ) {
332
333         if(!client)
334                 return 1;
335
336         int i;
337
338         if( words[1] ) { 
339                 if( !strcmp(words[1],"query") ) {
340                         
341                         if( words[2] && !strcmp(words[2],"servers") ) {
342                                 for(i=3; i < COMMAND_BUFSIZE - 3 && words[i]; i++ ) {   
343                                         router_query_servers( words[i] );
344                                 }
345                                 return 1;
346                         }
347                         return 0;
348                 }
349                 return 0;
350         }
351         return 0;
352 }
353
354
355 int handle_exec(char* words[]) {
356
357         int len = strlen(words[0]);
358         char command[len];
359         memset(command,0,len);
360
361         int i; /* chop out the ! */
362         for( i=1; i!= len; i++) {
363                 command[i-1] = words[0][i];
364         }
365
366         free(words[0]);
367         words[0] = strdup(command);
368         signal(SIGCHLD,sig_child_handler);
369         if(fork()) {
370                 while(1) {
371                         sleep(100);
372                         if(child_dead) {
373                                 signal(SIGCHLD,sig_child_handler);
374                                 child_dead = 0;
375                                 break;
376                         }
377                 }
378         } else {
379                 execvp( words[0], words );
380                 exit(0);
381         }
382         return 1;
383 }
384
385
386 int handle_request( char* words[], int relay ) {
387
388         if(!client)
389                 return 1;
390
391         if(words[1]) {
392                 char* server = words[1];
393                 char* method = words[2];
394                 int i;
395                 growing_buffer* buffer = NULL;
396                 if(!relay) {
397                         buffer = buffer_init(128);
398                         buffer_add(buffer, "[");
399                         for(i = 3; words[i] != NULL; i++ ) {
400                                 /* removes trailing semicolon if user accidentally enters it */
401                                 if( words[i][strlen(words[i])-1] == ';' )
402                                         words[i][strlen(words[i])-1] = '\0';
403                                 buffer_add( buffer, words[i] );
404                                 buffer_add(buffer, " ");
405                         }
406                         buffer_add(buffer, "]");
407                 }
408
409                 return send_request( server, method, buffer, relay );
410         } 
411
412         return 0;
413 }
414
415 int send_request( char* server, 
416                 char* method, growing_buffer* buffer, int relay ) {
417         if( server == NULL || method == NULL )
418                 return 0;
419
420         json* params = NULL;
421         if( !relay ) {
422                 if( buffer != NULL && buffer->n_used > 0 ) 
423                         params = json_tokener_parse(buffer->buf);
424         } else {
425                 if(!last_result || ! last_result->result_content) { 
426                         printf("We're not going to call 'relay' with no result params\n");
427                         return 1;
428                 }
429                 else {
430                         json* arr = json_object_new_array();
431                         json_object_array_add( arr, last_result->result_content );
432                         params = arr;
433                 }
434         }
435
436         osrf_app_session* session = osrf_app_client_session_init(server);
437
438         if(!osrf_app_session_connect(session)) {
439                 warning_handler( "Unable to connect to remote service %s\n", server );
440                 return 1;
441         }
442
443         double start = get_timestamp_millis();
444         int req_id = osrf_app_session_make_request( session, params, method, 1 );
445
446         if( caught_sigint ) 
447                 caught_sigint = 0;
448
449         osrf_message* omsg = osrf_app_session_request_recv( session, req_id, 8 );
450
451         if( caught_sigint ) {
452                 caught_sigint = 0;
453                 return 1;
454         }
455
456         if(!omsg) 
457                 printf("\nReceived no data from server\n");
458         
459         
460         signal(SIGPIPE, SIG_IGN);
461
462         FILE* less = popen( "less -EX", "w");
463         if( less == NULL ) { less = stdout; }
464
465         growing_buffer* resp_buffer = buffer_init(4096);
466
467         while(omsg) {
468
469                 if(omsg->result_content) {
470
471                         osrf_message_free(last_result);
472                         last_result = omsg;
473
474                         if( pretty_print ) {
475                                 char* content = json_printer( omsg->result_content );
476                                 buffer_add( resp_buffer, "\nReceived Data: " ); 
477                                 buffer_add( resp_buffer, content );
478                                 buffer_add( resp_buffer, "\n" );
479                                 free(content);
480                         } else {
481                                 char* content = json_object_get_string(omsg->result_content);
482                                         buffer_add( resp_buffer, "\nReceived Data: " ); 
483                                         buffer_add( resp_buffer, content );
484                                         buffer_add( resp_buffer, "\n" );
485                         }
486
487                 } else {
488
489                         buffer_add( resp_buffer, "\nReceived Exception:\nName: " );
490                         buffer_add( resp_buffer, omsg->status_name );
491                         buffer_add( resp_buffer, "\nStatus: " );
492                         buffer_add( resp_buffer, omsg->status_text );
493                         buffer_add( resp_buffer, "\nStatus: " );
494                         char code[16];
495                         memset(code, 0, 16);
496                         sprintf( code, "%d", omsg->status_code );
497                         buffer_add( resp_buffer, code );
498                 }
499
500                 if( caught_sigint ) 
501                         caught_sigint = 0;
502
503                 omsg = osrf_app_session_request_recv( session, req_id, 5 );
504
505                 if( caught_sigint ) {
506                         caught_sigint = 0;
507                         return 1;
508                 }
509         }
510
511
512         double end = get_timestamp_millis();
513
514         fprintf( less, resp_buffer->buf );
515         buffer_free( resp_buffer );
516         fprintf( less, "\n------------------------------------\n");
517         if( osrf_app_session_request_complete( session, req_id ))
518                 fprintf(less, "Request Completed Successfully\n");
519
520
521         fprintf(less, "Request Time in seconds: %.3f\n", end - start );
522         fprintf(less, "------------------------------------\n");
523
524         pclose(less); 
525
526         osrf_app_session_request_finish( session, req_id );
527         osrf_app_session_disconnect( session );
528         osrf_app_session_destroy( session );
529
530
531         return 1;
532
533
534 }
535
536 int handle_time( char* words[] ) {
537
538         if( ! words[1] ) {
539
540                 char buf[36];
541                 memset(buf,0,36);
542                 get_timestamp(buf);
543                 printf( "%s\n", buf );
544                 return 1;
545         }
546
547         if( words[1] ) {
548                 time_t epoch = (time_t)atoi( words[1] );
549                 char* localtime = strdup( ctime( &epoch ) );
550                 printf( "%s => %s", words[1], localtime );
551                 free(localtime);
552                 return 1;
553         }
554
555         return 0;
556
557 }
558
559                 
560
561 int router_query_servers( char* router_server ) {
562
563         if( ! router_server || strlen(router_server) == 0 ) 
564                 return 0;
565
566         char rbuf[256];
567         memset(rbuf,0,256);
568         sprintf(rbuf,"router@%s/router", router_server );
569                 
570         transport_message* send = 
571                 message_init( "servers", NULL, NULL, rbuf, NULL );
572         message_set_router_info( send, NULL, NULL, NULL, "query", 0 );
573
574         client_send_message( client, send );
575         message_free( send );
576
577         transport_message* recv = client_recv( client, -1 );
578         if( recv == NULL ) {
579                 fprintf(stderr, "NULL message received from router\n");
580                 return 1;
581         }
582         
583         printf( 
584                         "---------------------------------------------------------------------------------\n"
585                         "Received from 'server' query on %s\n"
586                         "---------------------------------------------------------------------------------\n"
587                         "original reg time | latest reg time | last used time | class | server\n"
588                         "---------------------------------------------------------------------------------\n"
589                         "%s"
590                         "---------------------------------------------------------------------------------\n"
591                         , router_server, recv->body );
592
593         message_free( recv );
594         
595         return 1;
596 }
597                 
598 int print_help() {
599
600         printf(
601                         "---------------------------------------------------------------------------------\n"
602                         "Commands:\n"
603                         "---------------------------------------------------------------------------------\n"
604                         "help                   - Display this message\n"
605                         "!<command> [args] - Forks and runs the given command in the shell\n"
606                         "time                   - Prints the current time\n"                                    
607                         "time <timestamp>       - Formats seconds since epoch into readable format\n"   
608                         "set <variable> <value> - set a srfsh variable (e.g. set pretty_print true )\n"
609                         "print <variable>               - Displays the value of a srfsh variable\n"
610                         "---------------------------------------------------------------------------------\n"
611
612                         "router query servers <server1 [, server2, ...]>\n"
613                         "       - Returns stats on connected services\n"
614                         "\n"
615                         "\n"
616                         "request <service> <method> [ <json formatted string of params> ]\n"
617                         "       - Anything passed in will be wrapped in a json array,\n"
618                         "               so add commas if there is more than one param\n"
619                         "\n"
620                         "\n"
621                         "relay <service> <method>\n"
622                         "       - Performs the requested query using the last received result as the param\n"
623                         "\n"
624                         "\n"
625                         "math_bench <num_batches> [0|1|2]\n"
626                         "       - 0 means don't reconnect, 1 means reconnect after each batch of 4, and\n"
627                         "                2 means reconnect after every request\n"
628                         "\n"
629                         "introspect <service>\n"
630                         "       - prints the API for the service\n"
631                         "\n"
632                         "\n"
633                         "---------------------------------------------------------------------------------\n"
634                         " Commands for Open-ILS\n"
635                         "---------------------------------------------------------------------------------\n"
636                         "login <username> <password>\n"
637                         "       -       Logs into the 'server' and displays the session id\n"
638                         "       - To view the session id later, enter: print login\n"
639                         "---------------------------------------------------------------------------------\n"
640                         "\n"
641                         "\n"
642                         "Note: long output is piped through 'less'.  To search in 'less', type: /<search>\n"
643                         "---------------------------------------------------------------------------------\n"
644                         "\n"
645                         );
646
647         return 1;
648 }
649
650
651
652 char* tabs(int count) {
653         growing_buffer* buf = buffer_init(24);
654         int i;
655         for(i=0;i!=count;i++)
656                 buffer_add(buf, "   ");
657
658         char* final = buffer_data( buf );
659         buffer_free( buf );
660         return final;
661 }
662
663 char* json_printer( json* object ) {
664
665         if(object == NULL)
666                 return NULL;
667         char* string = json_object_get_string(object);
668
669         growing_buffer* buf = buffer_init(64);
670         int i;
671         int tab_var = 0;
672         for(i=0; i!= strlen(string); i++) {
673
674                 if( string[i] == '{' ) {
675
676                         buffer_add(buf, "\n");
677                         char* tab = tabs(tab_var);
678                         buffer_add(buf, tab);
679                         free(tab);
680                         buffer_add( buf, "{");
681                         tab_var++;
682                         buffer_add( buf, "\n" );        
683                         tab = tabs(tab_var);
684                         buffer_add( buf, tab ); 
685                         free(tab);
686
687                 } else if( string[i] == '[' ) {
688
689                         buffer_add(buf, "\n");
690                         char* tab = tabs(tab_var);
691                         buffer_add(buf, tab);
692                         free(tab);
693                         buffer_add( buf, "[");
694                         tab_var++;
695                         buffer_add( buf, "\n" );        
696                         tab = tabs(tab_var);
697                         buffer_add( buf, tab ); 
698                         free(tab);
699
700                 } else if( string[i] == '}' ) {
701
702                         tab_var--;
703                         buffer_add(buf, "\n");
704                         char* tab = tabs(tab_var);
705                         buffer_add(buf, tab);
706                         free(tab);
707                         buffer_add( buf, "}");
708                         buffer_add( buf, "\n" );        
709                         tab = tabs(tab_var);
710                         buffer_add( buf, tab ); 
711                         free(tab);
712
713                 } else if( string[i] == ']' ) {
714
715                         tab_var--;
716                         buffer_add(buf, "\n");
717                         char* tab = tabs(tab_var);
718                         buffer_add(buf, tab);
719                         free(tab);
720                         buffer_add( buf, "]");
721                         buffer_add( buf, "\n" );        
722                         tab = tabs(tab_var);
723                         buffer_add( buf, tab ); 
724                         free(tab);
725
726                 } else if( string[i] == ',' ) {
727
728                         buffer_add( buf, ",");
729                         buffer_add( buf, "\n" );        
730                         char* tab = tabs(tab_var);
731                         buffer_add(buf, tab);
732                         free(tab);
733
734                 } else {
735
736                         char b[2];
737                         b[0] = string[i];
738                         b[1] = '\0';
739                         buffer_add( buf, b ); 
740                 }
741
742         }
743
744         char* result = buffer_data(buf);
745         buffer_free(buf);
746         return result;
747
748 }
749
750 int handle_math( char* words[] ) {
751         if( words[1] && words[2] ) 
752                 return do_math( atoi(words[1]), atoi(words[2]) );
753         return 0;
754 }
755
756
757 int do_math( int count, int style ) {
758
759         osrf_app_session* session = osrf_app_client_session_init(  "opensrf.math" );
760
761         json* params = json_object_new_array();
762         json_object_array_add(params, json_object_new_string("1"));
763         json_object_array_add(params, json_object_new_string("2"));
764
765         char* methods[] = { "add", "sub", "mult", "div" };
766         char* answers[] = { "3", "-1", "2", "0.500000" };
767
768         float times[ count * 4 ];
769         memset(times,0,count*4);
770
771         int k;
772         for(k=0;k!=100;k++) {
773                 if(!(k%10)) 
774                         fprintf(stderr,"|");
775                 else
776                         fprintf(stderr,".");
777         }
778
779         fprintf(stderr,"\n\n");
780
781         int running = 0;
782         int i;
783         for(i=0; i!= count; i++) {
784
785                 int j;
786                 for(j=0; j != 4; j++) {
787
788                         ++running;
789                         struct timeb t1;
790                         struct timeb t2;
791
792                         ftime(&t1);
793                         int req_id = osrf_app_session_make_request( session, params, methods[j], 1 );
794
795                         if( caught_sigint ) 
796                                 caught_sigint = 0;
797
798                         osrf_message* omsg = osrf_app_session_request_recv( session, req_id, 5 );
799
800                         if( caught_sigint )  {
801                                 caught_sigint = 0;
802                                 return 1;
803                         }
804
805                         ftime(&t2);
806
807                         double start    = ( (int)t1.time        + ( ((float)t1.millitm) / 1000 ) );
808                         double end              = ( (int)t2.time        + ( ((float)t2.millitm) / 1000 ) );
809
810                         times[(4*i) + j] = end - start;
811
812                         if(omsg) {
813         
814                                 if(omsg->result_content) {
815                                         char* jsn = json_object_get_string( omsg->result_content );
816                                         if(!strcmp(jsn, answers[j]))
817                                                 fprintf(stderr, "+");
818                                         else
819                                                 fprintf(stderr, "\n![%s] - should be %s\n", jsn, answers[j] );
820                                 }
821
822                                 osrf_message_free(omsg);
823                 
824                         } else { fprintf( stderr, "\nempty message for tt: %d\n", req_id ); }
825
826                         osrf_app_session_request_finish( session, req_id );
827
828                         if(style == 2)
829                                 osrf_app_session_disconnect( session );
830
831                         if(!(running%100))
832                                 fprintf(stderr,"\n");
833                 }
834
835                 if(style==1)
836                         osrf_app_session_disconnect( session );
837         }
838
839         osrf_app_session_destroy( session );
840         json_object_put( params );
841
842         int c;
843         float total = 0;
844         for(c=0; c!= count*4; c++) 
845                 total += times[c];
846
847         float avg = total / (count*4); 
848         fprintf(stderr, "\n      Average round trip time: %f\n", avg );
849
850         return 1;
851 }