#include "afni.h" #include /*********************************************************************** Version notes: 30 Dec 2015 [rickr] NEW: AFNI_15.3.00 - 15.3.00: - 2 digit year - 1 digit quarter (0-based) - 2 digit index (0-based index,incremented by build) - to be applied (by) Jan 1, 2016 - stored in AFNI_version_base.txt - generated/updated by dist_src and checked into github * so this label represents an AFNI build version - it equates to a git commit object (committed to github by build) - people doing local builds will not see this change - local build versions and dates will separate over time OLD: AFNI_2011_12_21_1014 - such labels were done with Ctag in CVS - created Dec, 2004 - Dec, 2011 (though rarely after 2005) - as it labeled _every_ source file, it was dropped - label AFNI_2011_12_21_1014 lasted 4 years (until 30 Dec, 2015) pub/dist/AFNI.version: - file used by most AFNI versions (see AFNI_version_check()) - except for those from June 2014 - Dec 2015 - was generated by afni_vcheck, now by dist_src - first line for version, might have size limit for some sprintf - second line was used by very old AFNI versions - third line used for motd= pub/dist/AFNI.compile_date: - file used by AFNI versions from June 2014 - Dec 2015 - see AFNI_compile_date_check() - updated in distall_MASTER (keep generating 2016 for ~old AFNI) AFNI_version_base.txt : updated by dist_src only AFNI_version.txt : build target, install file for users/progs AFNI_version.h : build target, code file for mrilib.h #include - AFNI_version is actual build target, so always makes new .h There are 3 types of checks going on now: - AFNI_version_check(): MOTD and afni GUI update comments - THD_check_AFNI_version(): command line progs update comments - MCW_popup_message_once(): afni GUI: situational comments - slowly growing? list, all seen on new accounts (or systems) *********************************************************************** */ #ifdef EXPECTED_AFNI_VER_STRLEN #undef EXPECTED_AFNI_VER_STRLEN #endif #define EXPECTED_AFNI_VER_STRLEN 12 #define FAIL_MESSAGE(reason) \ do{ fprintf(stderr,"\n" \ "\n** Version check disabled: %s", \ reason ) ; \ disabled = 1 ; } while(0) static int disabled = 0 ; #define STR_CHILD "tcp:localhost:20279" #define AFNI_HOST "https://afni.nimh.nih.gov/pub/dist/" #define VSIZE 1024 #define COMPILE_URL "https://afni.nimh.nih.gov/pub/dist/AFNI.compile_date" static pid_t vc_child_pid = (pid_t)(-1) ; static IOCHAN *vc_ioc = NULL ; static char *motd_old = NULL ; /* 29 Nov 2005 */ static char *motd_new = NULL ; #undef VERBOSE /* print messages on failure? */ void AFNI_start_fetching_url( char *urlstring ) ; static NI_element * AFNI_read_vctime(void); static int AFNI_version_diff( char * s1, char * s2, int * diff ); static int AFNI_update_vctime( char * new_ver, char * new_motd ); static int vc_check_too_soon( void ); /*------------------------------------------------------------------------*/ /*! This is only called from within the child process. */ static void vexit( int sig ) { #ifdef VERBOSE static volatile int fff=0 ; if( fff ) _exit(1) ; else fff = 1 ; fprintf(stderr,"** Version Check: child fails to complete: %d **\n",sig); #endif _exit(1); } /*------------------------------------------------------------------------*/ /*! This is called at main AFNI process exit, to destroy vc_ioc if it is still open. --------------------------------------------------------------------------*/ static void vc_exit(void){ iochan_close(vc_ioc) ; } /* 12 Dec 2002 */ /*------------------------------------------------------------------------*/ /*! Start the Web fetch to check the AFNI version in a child process. To complete things, call AFNI_version_check() somewhat later. --------------------------------------------------------------------------*/ void AFNI_start_version_check(void) { AFNI_start_fetching_url( AFNI_VERSION_URL ) ; return ; } void AFNI_start_compile_date_check(void) { AFNI_start_fetching_url( COMPILE_URL ) ; return ; } /*------------------------------------------------------------------------*/ void AFNI_start_fetching_url( char *urlstring ) { pid_t child_pid ; #ifdef CYGWIN /* 18 Dec 2002 */ FAIL_MESSAGE("not possible under Cygwin") ; return ; #else /*-- decide if we are to do anything --*/ if( ! AFNI_yesenv("AFNI_VERSION_CHECK") ){ /* never check */ FAIL_MESSAGE("AFNI_VERSION_CHECK forbids") ; return ; } #undef VDELAY #define VDELAY 1234567 /* about 2 weeks */ /* check if we did this in the last VDELAY seconds */ /* also, update global motd_old */ if( vc_check_too_soon() ) { disabled = 1 ; return ; } /*-- OK, start the child process --*/ child_pid = fork() ; if( child_pid == (pid_t)(-1) ){ /* bad */ FAIL_MESSAGE("can't fork") ; return ; } /*---------------------------------------------------------*/ if( child_pid > 0 ){ /* I'm the parent */ /*-- save PID of child for later use --*/ vc_child_pid = child_pid ; /*-- open an IOCHAN to talk to child --*/ vc_ioc = iochan_init( STR_CHILD , "accept" ) ; if( vc_ioc == NULL ){ kill(child_pid,SIGTERM) ; /* cf. Abraham and Isaac */ vc_child_pid = (pid_t)(-1) ; FAIL_MESSAGE("can't open connection to child") ; } else { atexit( vc_exit ) ; /* 12 Dec 2002 */ } return ; /*---------------------------------------------------------*/ } else { /* I'm the child */ /* (never returns) */ int nbuf=0 , jj ; char *vbuf=NULL ; IOCHAN *ioc ; struct utsname ubuf ; char ua[512] ; iochan_enable_perror(0) ; /* don't print TCP/IP error messages */ signal( SIGTERM , vexit ) ; /* if parent kills us, call vexit() */ /*-- get information from the AFNI server --*/ #define USE_HTTP_10 #ifdef USE_HTTP_10 # undef PCLAB # ifdef SHOWOFF # undef SHSH # undef SHSHSH # define SHSH(x) #x # define SHSHSH(x) SHSH(x) # define PCLAB SHSHSH(SHOWOFF) # else # define PCLAB "Unknown" # endif #endif /** 25 Mar 2005: send more info in the request header **/ #ifdef USE_HTTP_10 ubuf.nodename[0] = ubuf.sysname[0] = ubuf.machine[0] = '\0' ; jj = uname( &ubuf ) ; if( jj >= 0 && ubuf.nodename[0] != '\0' ) sprintf( ua , "afni (avers='%s'; prec='%s' node='%s'; sys='%s'; mach='%s')" , AVERZHN, PCLAB, ubuf.nodename, ubuf.sysname, ubuf.machine ) ; else sprintf( ua , "afni (avers='%s'; prec='%s')" , AVERZHN , PCLAB ) ; set_HTTP_10( 1 ) ; set_HTTP_user_agent( ua ) ; #else set_HTTP_10( 0 ) ; #endif /* send the request */ THD_death_setup( 34567 ) ; /* die if 34.567 seconds passes away */ nbuf = read_URL( urlstring , &vbuf ) ; /* may take a while */ set_HTTP_10( 0 ) ; /*-- if this failed, quit --*/ if( nbuf <= 0 || vbuf == NULL || vbuf[0] == '\0' ) { /* block recheck until a new DELAY has passed 22 Mar 2016 [rickr] */ /* - also so server is not flooded when there are issues */ AFNI_update_vctime(NULL, NULL); vexit(1); } /*-- talk to parent process thru IOCHAN --*/ ioc = iochan_init( STR_CHILD , "create" ) ; if( ioc == NULL ) vexit(2); /*-- wait until ioc is ready for writing --*/ jj = iochan_writecheck(ioc,-1) ; if( jj < 0 ) vexit(3); /*-- send the info in vbuf --*/ iochan_sendall( ioc , vbuf , nbuf ) ; while( ! iochan_clearcheck(ioc,10) ) /* loop until cleared */ AFNI_sleep(10) ; /* by parent process */ AFNI_sleep(10); /* a little extra napping, then death */ _exit(0); } #endif /* not CYGWIN */ } /******************************************/ #ifdef VERBOSE # define KAPUT(ss) \ do{ fprintf(stderr,"** Version Check fails: %s **\n",ss); \ return 0; } while(0) #else # define KAPUT(ss) return 0 #endif /*----------------------------------------------------------------------------*/ /*! compute version difference, store in 'diff' return 0 on success expect version strings of the form AFNI_YY.Q.II YY : 2 digit year Q : 0-based quarter II : 0-based build index diff = number of quarters difference (positive means s1 is newer than s2) -----------------------------------------------------------------------------*/ static int AFNI_version_diff(char * s1, char * s2, int * diff) { int major1, minor1, major2, minor2, micro1, micro2; int rv1, rv2; if( !s1 || !s2 || !diff ) { fprintf(stderr,"AVD: bad version strings or diff ptr\n"); return 1; } if( strlen(s1) < EXPECTED_AFNI_VER_STRLEN || strlen(s2) < EXPECTED_AFNI_VER_STRLEN ) { fprintf(stderr,"AVD: short version strings, %.12s, %.12s\n", s1, s2); return 1; } /* assume a format like AFNI_16.1.17 */ rv1 = sscanf(s1, "AFNI_%d.%d.%d", &major1, &minor1, µ1); rv2 = sscanf(s2, "AFNI_%d.%d.%d", &major2, &minor2, µ2); if( rv1 != 3 || rv2 != 3 ) { fprintf(stderr,"AVD: bad version conversion from %s, %s\n", s1, s2); return 1; } *diff = 4*major1 + minor1 - (4*major2 + minor2); return 0; } /*----------------------------------------------------------------------------*/ /*! Complete the version check by seeing if the child process has any data to report from the AFNI web site. - so local .afni.vctime has already been read, and it is time to check for updates (and rewrite local file in any case) - Returns 1 if the version at the AFNI site doesn't match the compiled-in version of this program; - Returns 0 if they match, or it can't tell. - Also prints stuff out. - 29 Nov 2005: also sets GLOBAL_motd string, maybe. ------------------------------------------------------------------------------*/ int AFNI_version_check(void) { int jj , nbuf=0 , vdiff=0 ; char *vbuf=NULL ; char vv[128]="none" ; char *sname , *vvbuf ; #ifdef CYGWIN /* 30 Jun 2005 [rickr] */ return 0; #else /* if something is rotten, then toss it out */ /* (or AFNI_start_fetching_url() sets disabled if it is too soon) */ if( GLOBAL_argopt.allow_rt || disabled ) return 0 ; /* 27 Jan 2003 */ if( vc_ioc == NULL || vc_child_pid == (pid_t)(-1) ) KAPUT("bad child state"); jj = kill(vc_child_pid,0) ; /* is child alive? */ if( jj < 0 ){ IOCHAN_CLOSE(vc_ioc); vc_child_pid=(pid_t)(-1); KAPUT("child not alive"); } jj = iochan_readcheck( vc_ioc , 333 ) ; /* is iochan open yet? */ if( jj <= 0 ){ IOCHAN_CLOSE(vc_ioc); kill(vc_child_pid,SIGTERM); vc_child_pid=(pid_t)(-1); KAPUT("connection to child gone bad"); } /* if here, have data ready to read from child! */ nbuf = 0 ; vbuf = AFMALL(char, VSIZE) ; while(1){ jj = iochan_recv( vc_ioc , vbuf+nbuf , VSIZE-nbuf ) ; if( jj < 1 ) break ; nbuf += jj ; if( nbuf >= VSIZE-1 ) break ; jj = iochan_readcheck( vc_ioc , 5 ) ; if( jj < 1 ) break ; } /* now wait for child to kill itself */ waitpid(vc_child_pid,NULL,WNOHANG); vc_child_pid = (pid_t)(-1); IOCHAN_CLOSE(vc_ioc); /* no data? */ /* require enough (12 bytes) for e.g. AFNI_16.0.00 */ if( nbuf < EXPECTED_AFNI_VER_STRLEN ) { free(vbuf); vbuf = NULL; KAPUT("bad version data"); } /* unlikely */ /* extract version and data/time strings from data */ vvbuf = strstr(vbuf,"AFNI_") ; /* 29 Nov 2005: scan for version string */ if( vvbuf == NULL ) vvbuf = vbuf ; sscanf( vvbuf , "%127s" , vv ); /* get version string out of data */ vvbuf = strstr(vbuf,"motd=") ; /* 29 Nov 2005: motd string */ if( vvbuf != NULL ){ motd_new = (char *)calloc(sizeof(char),VSIZE) ; sscanf( vvbuf+5 , "%988s" , motd_new ) ; if( motd_new[0] == '\0' ){ free(motd_new); motd_new=NULL; } } free(vbuf) ; /* done with the input data from the child */ /* record the current time, so we don't check too often */ /* move to separate function 22 Mar 2016 [rickr] */ AFNI_update_vctime(vv, motd_new) ; /* 29 Nov 2005: compare motd strings (old and new) if different, save new one in GLOBAL_motd for display later */ if( motd_new != NULL ){ if( motd_old == NULL || strcmp(motd_new,motd_old) != 0 ){ GLOBAL_motd = motd_new ; } else { free(motd_new) ; motd_new = NULL ; } } if( motd_old != NULL ){ free(motd_old); motd_old=NULL; } /* compare version strings */ /* set vdiff = quarterly difference between web version and our version */ if( AFNI_version_diff(vv, AVERZHN, &vdiff) ) return 0 ; /* if at least 2 quarters old (truncates to 3+ months), warn user */ if( vdiff >= 2 ) { fprintf(stderr, "\n" "****************************************************\n" " This AFNI version is %d+ months old:\n" " Version ID = %s\n" " Latest version at %s\n" " Version ID = %s\n" "****************************************************\n" " To disable future version checks:\n" " set environment variable AFNI_VERSION_CHECK to NO\n" "****************************************************\n", (vdiff-1)*3, AVERZHN, AFNI_HOST , vv ) ; return 1 ; } return 0 ; #endif /* CYGWIN */ } /* try to update .afni.vctime with new version and motd strings */ /* (broken out from AFNI_version_check) 22 Mar 2016 [rickr] */ static int AFNI_update_vctime(char * new_ver, char * new_motd) { char *home=getenv("HOME") , mname[VSIZE]="file:" , rhs[32]; NI_element *nel ; NI_stream ns ; if( home != NULL ) strcat(mname,home) ; strcat(mname,"/.afni.vctime") ; /* first read the old one or make a new one */ nel = AFNI_read_vctime(); if ( ! nel ) nel = NI_new_data_element("AFNI_vctime",0); ns = NI_stream_open( mname , "w" ) ; if( ns == NULL ) return 1 ; sprintf(rhs,"%d",(int)time(NULL)) ; NI_set_attribute( nel , "version_check_time" , rhs ) ; if( new_ver && (strcmp(new_ver,"none") != 0 ) ) /* 27 Jan 2003 */ NI_set_attribute( nel , "version_string" , AVERZHN ) ; if( new_motd != NULL ) NI_set_attribute( nel , "motd" , new_motd ) ; /* 29 Nov 2005 */ NI_write_element( ns , nel , NI_TEXT_MODE ) ; NI_stream_close(ns) ; return 0 ; } /* read in .afni.vctime into NI_element 22 Mar 2016 [rickr] */ /* (broken out from AFNI_start_fetching_url) */ static NI_element * AFNI_read_vctime(void) { char *home=getenv("HOME") , mname[VSIZE]="file:" ; NI_element *nel=NULL ; NI_stream ns ; if( home != NULL ) strcat(mname,home) ; strcat(mname,"/.afni.vctime") ; ns = NI_stream_open( mname , "r" ) ; if( ns == NULL ) return NULL ; nel = NI_read_element(ns,22) ; NI_stream_close(ns) ; return nel; } /* do we have a valid check_time and is it too soon? */ /* - warn on old check and version change */ /* - possibly update motd_old */ /* (broken out from AFNI_start_fetching_url) 22 Mar 2016 [rickr] */ static int vc_check_too_soon(void) { NI_element *nel=NULL; char *rhs; int last_time, dtime; nel = AFNI_read_vctime() ; if( nel == NULL ) return 0; rhs = NI_get_attribute(nel , "version_check_time"); if( rhs == NULL ) return 0; last_time = strtol(rhs,NULL,10); dtime = ((int)time(NULL)) - last_time; /* too soon to worry */ if( dtime >= 0 && dtime < VDELAY ) { NI_free_element(nel); return 1; } /* warn on version change */ rhs = NI_get_attribute(nel,"version_string") ; /* 27 Jan 2003 */ if( rhs != NULL && strcmp(rhs,AVERZHN) != 0 ){ fprintf(stderr, "\n** Your AFNI version changed from %s to %s since last check\n", rhs , AVERZHN ) ; } /* possibly update global motd_old */ rhs = NI_get_attribute(nel,"motd") ; /* 29 Nov 2005 */ if( rhs != NULL ) { if( motd_old ) free(motd_old); motd_old = strdup(rhs) ; } NI_free_element(nel); return 0; } /*----------------------------------------------------------------------------*/ /*! Complete the compile date check -- return number of days difference. ------------------------------------------------------------------------------*/ static char *monlist[12] = { "JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC" } ; int AFNI_compile_date_check(void) { int jj , nbuf=0 , day_diff=0 ; char *vbuf=NULL , *qbuf ; int new_day =-666 , old_day =-666 ; int new_year =-666 , old_year =-666 ; char new_mon[8] = "Zork" , old_mon[8] = "Zork" ; int new_imm , old_imm ; #ifdef CYGWIN /* 30 Jun 2005 [rickr] */ return 0; #else /* if something is rotten, then toss it out */ if( GLOBAL_argopt.allow_rt || disabled ) return 0 ; /* 27 Jan 2003 */ if( vc_ioc == NULL || vc_child_pid == (pid_t)(-1) ) KAPUT("bad child state"); jj = kill(vc_child_pid,0) ; /* is child alive? */ if( jj < 0 ){ IOCHAN_CLOSE(vc_ioc); vc_child_pid=(pid_t)(-1); KAPUT("child not alive"); } jj = iochan_readcheck( vc_ioc , 333 ) ; /* is iochan open yet? */ if( jj <= 0 ){ IOCHAN_CLOSE(vc_ioc); kill(vc_child_pid,SIGTERM); vc_child_pid=(pid_t)(-1); KAPUT("connection to child gone bad"); } /* if here, have data ready to read from child! */ nbuf = 0 ; vbuf = AFMALL(char, VSIZE) ; while(1){ jj = iochan_recv( vc_ioc , vbuf+nbuf , VSIZE-nbuf ) ; if( jj < 1 ) break ; nbuf += jj ; if( nbuf >= VSIZE-1 ) break ; jj = iochan_readcheck( vc_ioc , 5 ) ; if( jj < 1 ) break ; } /* now wait for child to kill itself */ waitpid(vc_child_pid,NULL,WNOHANG); vc_child_pid = (pid_t)(-1); IOCHAN_CLOSE(vc_ioc); /* no data? */ if( nbuf < 11 ){ free(vbuf); vbuf = NULL; KAPUT("bad compile date data"); } /* unlikely */ /* extract date info from string [e.g., "16 Jun 2014"] */ qbuf = strcasestr(vbuf,"Content-Length:") ; if( qbuf != NULL ){ char *zbuf = strstr(qbuf,"\r\n\r\n") ; if( zbuf != NULL ) qbuf = zbuf + 4 ; } else { qbuf = vbuf ; } sscanf( qbuf , "%d %s %d" , &new_day , new_mon , &new_year ) ; sscanf( __DATE__ , "%s %d %d" , old_mon , &old_day , &old_year ) ; /* day/mon invert */ free(vbuf) ; /* done with the input data from the child */ /* bad results? */ if( new_day < 0 || new_mon[0] == 'Z' || new_year < 0 ) return 0 ; if( old_day < 0 || old_mon[0] == 'Z' || old_year < 0 ) return 0 ; /* compare dates */ for( jj=0 ; jj < 12 ; jj++ ) if( strcasecmp(new_mon,monlist[jj]) == 0 ) break ; if( jj < 12 ) new_imm = jj ; else return 0 ; for( jj=0 ; jj < 12 ; jj++ ) if( strcasecmp(old_mon,monlist[jj]) == 0 ) break ; if( jj < 12 ) old_imm = jj ; else return 0 ; day_diff = (new_year-old_year)*365 + (new_imm-old_imm)*31 + (new_day-old_day) ; /* record the current time, so we don't check too often */ { char *home=getenv("HOME") , mname[VSIZE]="file:" ; NI_stream ns ; if( home != NULL ) strcat(mname,home) ; strcat(mname,"/.afni.vctime") ; ns = NI_stream_open( mname , "w" ) ; if( ns != NULL ){ NI_element *nel=NI_new_data_element("AFNI_vctime",0); char rhs[32]; sprintf(rhs,"%d",(int)time(NULL)) ; NI_set_attribute( nel , "version_check_time" , rhs ) ; NI_write_element( ns , nel , NI_TEXT_MODE ) ; NI_stream_close(ns) ; } } return day_diff ; #endif /* CYGWIN */ } /*----------------------------------------------------------------------*/ /***---------------- 20 Nov 2003: auto-download stuff ----------------***/ #ifdef SHOWOFF # undef SHSH # undef SHSHSH # define SHSH(x) #x # define SHSHSH(x) SHSH(x) # define SNAME "AFNI_UPDATER" /* script file name */ char * AFNI_make_update_script(void) { char *pg_ftp , *pg_afni , *pg_gzip , *pg_tar ; char hbuf[4096], fname[128], adir[4096], *cpt, cwd[4096] ; FILE *fp ; static char sname[4096] ; pg_ftp = THD_find_executable("ftp" ); if( pg_ftp == NULL ) return NULL; pg_afni = THD_find_executable("afni"); if( pg_afni == NULL ) return NULL; pg_gzip = THD_find_executable("gzip"); if( pg_gzip == NULL ) pg_gzip = THD_find_executable("pigz") ; if( pg_gzip == NULL ) return NULL; pg_tar = THD_find_executable("tar" ); if( pg_tar == NULL ) return NULL; strcpy(adir,pg_afni) ; /* extract name of AFNI directory */ cpt = THD_trailname(adir,0) ; *cpt = '\0' ; if( strlen(adir) <= 0 ) return NULL ; /* no AFNI directory? */ strcpy( cwd , adir ) ; /* try to write a test file there */ strcat( cwd , "afni_qadgop" ) ; fp = fopen( cwd , "a" ) ; if( fp == NULL ) return NULL ; /* can't write to AFNI directory? */ fclose(fp) ; remove(cwd) ; getcwd( cwd , 4096 ) ; /* get current directory for later use */ chdir( adir ) ; /* switch to AFNI directory for this work */ /* write a script to get and install the binary archive via FTP */ gethostname( hbuf , 4096 ) ; strcpy( fname , SHSHSH(SHOWOFF) ) ; strcat( fname , ".tgz" ) ; fp = fopen( SNAME , "w" ) ; if( fp == NULL ){ chdir(cwd); return NULL; } fprintf( fp , "#!/bin/sh\n" "echo '++ FTP-ing %s from afni.nimh.nih.gov'\n" "%s -n afni.nimh.nih.gov << EEEEE\n" /* FTP to get file */ "user anonymous AFNI_UPDATER@%s\n" "binary\n" "passive\n" "cd tgz\n" "get %s\n" "bye\n" "EEEEE\n" "echo '++ Unpacking %s'\n" "%s -dc %s | %s xf -\n" /* uncompress and untar .tgz file */ "/bin/rm -f %s\n" /* delete .tgz file */ "echo '++ Moving files'\n" "/bin/mv -f %s/* .\n" /* move untar-ed files up to here */ "/bin/rm -rf %s\n" /* remove any directory leftovers */ "echo '++ Finished'\n" , fname , /* filename to get (for 'FTP-ing' echo) */ pg_ftp , /* FTP program */ hbuf , /* hostname, for FTP password */ fname , /* filename to get (for FTP) */ fname , /* ditto (for 'Unpacking' echo) */ pg_gzip, fname, pg_tar, /* GZIP program, filename, TAR program */ fname , /* filename to delete */ SHSHSH(SHOWOFF) , /* directory to copy up */ SHSHSH(SHOWOFF) /* directory to delete */ ) ; fclose( fp ) ; chmod( SNAME , S_IRUSR | S_IWUSR | S_IXUSR ) ; /* mark as executable */ /* get back to current working directory, then leave */ chdir(cwd) ; sprintf(sname,"%s%s",adir,SNAME) ; return sname ; } #else /* undefined SHOWOFF */ char * AFNI_make_update_script(void){ return NULL; } #endif /* SHOWOFF */ /*----------------------------------------------------------------------*/ #define MOTD_fails ERROR_message("Can't connect to AFNI server!\a\n") /*----------------------------------------------------------------------*/ /*! Display the AFNI message of the day. [29 Nov 2005] ------------------------------------------------------------------------*/ void AFNI_display_motd( Widget w ) { int nbuf ; char *buf=NULL , url[VSIZE] ; ENTRY("AFNI_display_motd") ; set_HTTP_10( 0 ) ; if( GLOBAL_motd == NULL || *GLOBAL_motd == '\0' ){ /* fetch motd name */ char *vbuf=NULL , *vvbuf ; /* from AFNI server */ nbuf = read_URL( AFNI_VERSION_URL , &vbuf ) ; if( nbuf <= 0 || vbuf == NULL ){ MOTD_fails; EXRETURN; } vvbuf = strstr(vbuf,"motd=") ; if( vvbuf == NULL ){ free(vbuf); MOTD_fails; EXRETURN; } GLOBAL_motd = (char *)calloc(sizeof(char),VSIZE) ; sscanf( vvbuf+5 , "%988s" , GLOBAL_motd ) ; free(vbuf) ; if( GLOBAL_motd[0] == '\0' ){ free(GLOBAL_motd); GLOBAL_motd=NULL; MOTD_fails; EXRETURN; } } sprintf(url,"%s%.988s",AFNI_HOST,GLOBAL_motd) ; /** INFO_message("MOTD URL = '%s'",url) ; **/ nbuf = read_URL( url , &buf ) ; if( nbuf > 0 && buf != NULL ){ char *msg = malloc(sizeof(char)*(nbuf+2048)) ; sprintf(msg, "\n" " *********** Current AFNI Message of the Day **********\n\n" " [cf. %s ]\n\n" " [cf. menu item Define Datamode -> Misc -> Message of the Day ]\n\n" " ====================================================================\n\n" "%s\n" , url , buf ); if( w != NULL ){ MCW_textwin_setbig(1) ; /* 29 Apr 2009 */ (void) new_MCW_textwin( w , msg , TEXT_READONLY ); } else { fputs(msg,stderr) ; } free(msg) ; free(buf) ; } else { MOTD_fails ; } EXRETURN ; } /*----------------------------------------------------------------------*/ /*! Display the AFNI historical documents [05 Mar 2008] ------------------------------------------------------------------------*/ void AFNI_display_hist( Widget w ) { #define NBUF 1024 static char *cmd=NULL ; char buf[NBUF+1] , *all=NULL ; int nbuf , nall=0 ; FILE *fp ; /*-- get the path to the command to run --*/ if( cmd == NULL ){ char *pg = THD_find_executable("afni_history") ; if( pg == NULL || *pg == '\0' ){ (void)MCW_popup_message( w , " \n" " Can't find afni_history \n" " program in your PATH!!! \n" , MCW_USER_KILL | MCW_TIMER_KILL ) ; XtSetSensitive(w,False) ; return ; } cmd = (char *)calloc( sizeof(char) , (64+strlen(pg)) ) ; sprintf(cmd,"%s -reverse",pg) ; } /*-- open a pipe to read from the command --*/ fp = popen( cmd , "r" ); if( fp == NULL ){ (void)MCW_popup_message( w , " \n" " Can't run afni_history\n" " program for some reason!\n" , MCW_USER_KILL | MCW_TIMER_KILL ) ; return ; } /*-- read the first bunch of data fromt the pipe --*/ nbuf = fread( buf , 1 , NBUF , fp ) ; if( nbuf < 16 || *buf == '\0' ){ (void)MCW_popup_message( w , " \n" " afni_history program\n" " fails to give output!\n" , MCW_USER_KILL | MCW_TIMER_KILL ) ; return ; } /*-- store this initial string in 'all' --*/ buf[nbuf] = '\0' ; all = strdup(buf) ; nall = strlen(all) ; /*-- loop: read buffer, copy into 'all', until nothing left to read --*/ do{ nbuf = fread( buf , 1 , NBUF , fp ) ; if( nbuf <= 0 ){ pclose(fp); break; } /* read failed ==> done */ buf[nbuf] = '\0' ; all = realloc( all , nall+nbuf+2 ) ; strcat(all,buf) ; nall = strlen(all) ; } while(1) ; /*-- display results in a window, and exeunt omnes --*/ (void)new_MCW_textwin( w , all , 1 ) ; free(all) ; return ; }