• Main Page
  • Data Structures
  • Files

omni.c

Go to the documentation of this file.
00001 /*
00002  * This file is part of Titan2Reader
00003  *
00004  * Copyright (C) 2006, Sebastien Judenherc <sebastien.judenherc@agecodagis.com>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
00019  * USA
00020  *
00021  */
00022 
00023 #ifdef OMNI
00024 
00025 #define OMNI_RELEASE_STR "OMNI 2.1 - "__DATE__" - "
00026 
00027 #include <sys/time.h>
00028 #include <math.h>
00029 struct timeval tvStart, tvStop;
00030 
00031 char *errorColor, *normalColor;
00032 
00033 struct OmniStationType
00034 {
00035         char name[16];
00036         char group[32];
00037         int running;
00038         int error;
00039         struct ShortInfos shi;
00040         struct OsirisInformationField oif[OIF_FIELDS_NUMBER];
00041         char alertHtml[30*128];
00042         char alertTip[30*128];
00043         char osirisErrorMessage[OSIRIS_ERROR_MESSAGES][OSIRIS_ERROR_MESSAGE_LENGTH+1];
00044         struct OmniStationType *next;
00045 };
00046 
00047 struct OmniStationType *omniStation=NULL;
00048 
00049 #define OMNI_SUPERVISOR         (1<<0)
00050 #define OMNI_CONFIGURATOR       (1<<1)
00051 #define OMNI_SINGLESTATION      (1<<2)
00052 #define OMNI_TAILER             (1<<3)
00053 #define OMNI_HEADER             (1<<4)
00054 #define OMNI_DATASELECT         (1<<5)
00055 #define OMNI_DISPATCH           (1<<6)
00056 #define OMNI_DATACENTER         (1<<7)
00057 #define OMNI_SHOWEVENT          (1<<8)
00058 #define OMNI_BUILDMAP           (1<<9)
00059 #define OMNI_BUILDTOPO          (1<<10)
00060 #define OMNI_MAIN               (1<<11)
00061 #define OMNI_MATRIX             (1<<12)
00062 
00063 // ordered according to the strength of the link
00064 #define CONTACT         (1<<0)
00065 #define PPP             (1<<1)
00066 #define VPN             (1<<2)
00067 #define WIRELESS        (1<<3)
00068 #define ETHERNET        (1<<4)
00069 #define USB             (1<<5)
00070 
00071 #define AVAILABLE_COLOR "green"
00072 #define RUNNING_COLOR "blue"
00073 #define WAITING_COLOR "grey"
00074 #define MISSED_COLOR "red"
00075 
00076 #define MAPX 800
00077 #define MAPY 600
00078 
00079 #define _BUF_SIZE 65535
00080 #define __min(a,b) (a<b?(a):(b))
00081 
00082 char *omniDir=NULL;
00083 
00084 #define MAX_STATION 1000
00085 char currentNetwork[MAX_STATION][10];
00086 int networkDefined=0;
00087 
00088 void FilterPostInput(void)
00089 {
00090         char line[_BUF_SIZE+1];
00091         char *g;
00092         int len=0;
00093         g=MyGetenv("CONTENT_LENGTH");
00094         if (g)
00095         {
00096                 sscanf(g,"%d",&len);
00097                 len++;
00098         }
00099         PrintError("len=%d\n",len);
00100         fgets(line,__min(_BUF_SIZE,len),stdin);
00101         printf("%s",line);
00102         PrintError("len=%d '%s'\n",len,line);
00103         printf("\n");
00104 }
00105 
00109 void CleanDir(char *dir, int timeout)
00110 {
00111         int n;
00112         struct dirent **direntry;
00113 
00114         int CleanDirSelect(const struct dirent* t)
00115         {
00116                 char s[128];
00117                 struct stat sb;
00118                 sprintf(s,"%s/%s",dir,t->d_name);
00119                 if (stat(s,&sb)==0)
00120                 {
00121                         if (abs(time(NULL)-sb.st_mtime)>timeout)
00122                         {
00123                                 return(1);
00124                         }
00125                 }
00126                 return(0);
00127         }
00128 
00129         n=__scandir(dir,&direntry,CleanDirSelect,__alphasort);
00130         // free the dir buffers
00131         if (n>0)
00132         {
00133                 int i;
00134                 char s[128];
00135                 for (i=0; i<n; i++)
00136                 {
00137                         sprintf(s,"%s/%s",dir,direntry[i]->d_name);
00138                         unlink(s);
00139                         free(direntry[i]);
00140                 }
00141                 free(direntry);
00142         }
00143 }
00144 
00145 
00148 void CheckAlertFiles(void)
00149 {
00150         char *oldOaf=NULL;
00151         char *tok;
00152         char *newOaf=NULL;
00153         char *MailFrom,*MailTo,*SmtpServer,*OIF;
00154         FILE *fo,*fn;
00155         char oldLine[255];
00156         char newLine[255];
00157         char MailToTok[255];
00158         int mail=0;
00159         char a[64];
00160         int t;
00161         oldOaf=MyGetenv("OLDOAF");
00162         newOaf=MyGetenv("NEWOAF");
00163         MailFrom=MyGetenv("MailFrom");
00164         MailTo=MyGetenv("MailTo");
00165         OIF=MyGetenv("OIF");
00166         SmtpServer=MyGetenv("SmtpServer");
00167         // check for the files
00168         if ((oldOaf==NULL)||(newOaf==NULL)||(OIF==NULL)||
00169                         (MailFrom==NULL)||(MailTo==NULL)||
00170                         (SmtpServer==NULL))
00171         {
00172                 PrintError("missing definition\n");
00173                 exit(0);
00174         }
00175         // open the files
00176         fo=fopen(oldOaf,"rt");
00177         fn=fopen(newOaf,"rt");
00178         // exit on error
00179         if ((fo==NULL)||(fn==NULL))
00180         {
00181                 exit(0);
00182         }
00183         mail=0;
00184         // read the new and the old until the end of the new file
00185         while (!feof(fn))
00186         {
00187                 // compare the head of the lines
00188                 oldLine[0]=newLine[0]=0;
00189                 fgets(oldLine,254,fo);
00190                 fgets(newLine,254,fn);
00191                 if ((oldLine[0]==0)&&(newLine[0]==0))
00192                 {
00193                         break;
00194                 }
00195                 // if they differ
00196                 if (memcmp(newLine,oldLine,14))
00197                 {
00198                         // detect the difference, stop
00199                         mail=1;
00200                         break;
00201                 }
00202         }
00203         // finish the old file, do the same
00204         while (!feof(fo))
00205         {
00206                 oldLine[0]=newLine[0]=0;
00207                 fgets(oldLine,254,fo);
00208                 fgets(newLine,254,fn);
00209                 if ((oldLine[0]==0)&&(newLine[0]==0))
00210                 {
00211                         break;
00212                 }
00213                 if (memcmp(newLine,oldLine,14))
00214                 {
00215                         mail=1;
00216                         break;
00217                 }
00218         }
00219         // if the files contain the same alerts, exit now
00220         if (mail==0)
00221         {
00222                 exit(0);
00223         }
00224         puts("helo localhost.localdomain");
00225         printf("mail from: <%s>\n",MailFrom);
00226         strcpy(MailToTok,MailTo);
00227         tok=strtok(MailToTok,",");
00228         while (tok)
00229         {
00230                 printf("rcpt to: <%s>\n",tok);
00231                 tok=strtok(NULL,",");
00232         }
00233         puts("data");
00234         printf("To: %s\n",MailTo);
00235         printf("Subject: [OMNI] %s: alert state has changed\n",MyGetenv("STATION"));
00236         t=time(NULL);
00237         printf("\nDate: %.16s\n",time2str((double)t));
00238         rewind(fo);
00239         rewind(fn);
00240         printf("\n\nNew alert state:\n");
00241         while (!feof(fn))
00242         {
00243                 oldLine[0]=newLine[0]=0;
00244                 if (NULL==fgets(newLine,254,fn))
00245                 {
00246                         break;
00247                 }
00248                 sscanf(newLine,"%s %d",a,&t);
00249                 //printf("%-16s %.16s ",a,time2str((double)t));
00250                 printf("%-16s %s",a,newLine+32);
00251         }
00252         printf("\n\nOld alert state:\n");
00253         while (!feof(fo))
00254         {
00255                 oldLine[0]=newLine[0]=0;
00256                 if (NULL==fgets(oldLine,254,fo))
00257                 {
00258                         break;
00259                 }
00260                 sscanf(oldLine,"%s %d",a,&t);
00261                 //printf("%-16s %.16s ",a,time2str((double)t));
00262                 printf("%-16s %s",a,oldLine+32);
00263         }
00264         printf("\n\nOIF follows:\n");
00265         fclose(fn);
00266         fclose(fo);
00267         fn=fopen(OIF,"rt");
00268         while (fgets(oldLine,254,fn)!=NULL)
00269         {
00270                 printf("%s",oldLine);
00271         }
00272         fclose(fn);
00273         puts("\n.");
00274         puts("quit");
00275         exit(0);
00276 }
00277 
00279 void CheckLoadAvg(void)
00280 {
00281         float load;
00282         float maxLoad;
00283         FILE *f;
00284         char *s;
00285         int cont=12;
00286         // read the maximum load
00287         s=MyGetenv("MAXLOAD");
00288         if (!s)
00289         {
00290                 exit(0);
00291         }
00292         sscanf(s,"%f",&maxLoad);
00293         // while file "pid" exists
00294         while (access("pid",R_OK)==0)
00295         {
00296                 int st;
00297                 // read the current load
00298                 f=fopen("/proc/loadavg","rt");
00299                 if (f)
00300                 {
00301                         fscanf(f,"%f",&load);
00302                         fclose(f);
00303                 }
00304                 // if the current load is below the max, exit
00305                 if (load<maxLoad)
00306                 {
00307                         exit(0);
00308                 }
00309                 // else sleep 10 seconds
00310                 st=5+rand() % 20;
00311                 printf("sleeping %d (%f>%f)\n",st,load,maxLoad);
00312                 sleep(st);
00313                 cont--;
00314                 if (cont==0)
00315                 {
00316                         exit(0);
00317                 }
00318         }
00319         // endwhile
00320         // if we are here, the file "pid" does not exist
00321         // kill the father and exit
00322         kill(getppid(),SIGTERM);
00323         exit(0);
00324 }
00325 
00328 int IncreaseEvtId(void)
00329 {
00330         char file[128];
00331         char renamed[128];
00332         int id=0,cnt;
00333         FILE *f;
00334         sprintf(file,"%s/evtid",omniDir);
00335         sprintf(renamed,"%s/evtid.renamed",omniDir);
00336         // while ((the file does not exist)||(the renamed file exists))
00337         cnt=10;
00338         while ( (access(file,R_OK)!=0) || (access(renamed,R_OK)==0) )
00339         {
00340                 // wait 1 second
00341                 sleep(1);
00342                 // if we are waiting for more than 10 seconds, stop
00343                 cnt--;
00344                 if (cnt<0)
00345                 {
00346                         break;
00347                 }
00348         // end while
00349         }
00350         // rename the file
00351         unlink(renamed);
00352         rename(file,renamed);
00353         // open the renamed file
00354         f=fopen(renamed,"rt");
00355         // read the id
00356         fscanf(f,"%d",&id);
00357         // close the file
00358         fclose(f);
00359         // increase the id
00360         id++;
00361         // open the renamed file
00362         f=fopen(renamed,"wt");
00363         // write id
00364         fprintf(f,"%d",id);
00365         // close the file
00366         fclose(f);
00367         // rename back the file
00368         unlink(file);
00369         rename(renamed,file);
00370         return(id);
00371 }
00372 
00373 
00375 void DispatchDataRequest(void)
00376 {
00377         struct tm tm;
00378         char sta[128],event[256],line[128];
00379         int length;
00380         int sl;
00381         time_t T;
00382         struct OmniStationType *cur;
00383         int id;
00384         FILE *f;
00385         char iline[_BUF_SIZE+1];
00386         char *g;
00387         int ilen=0;
00388         g=MyGetenv("CONTENT_LENGTH");
00389         if (g)
00390         {
00391                 sscanf(g,"%d",&ilen);
00392                 ilen++;
00393         }
00394         PrintError("ilen=%d\n",ilen);
00395         fgets(iline,__min(_BUF_SIZE,ilen),stdin);
00396 
00397         id=IncreaseEvtId();
00398         memset(&tm,0,sizeof(struct tm));
00399         // read the date and window length
00400         sscanf(iline,"%*5c%d%*7c%d%*5c%d%*6c%d%*8c%d%*8c%d%n",
00401                         &(tm.tm_year),&(tm.tm_mon),&(tm.tm_mday),
00402                         &(tm.tm_hour),&(tm.tm_min),&length,&sl);
00403         tm.tm_year-=1900;
00404         tm.tm_mon--;
00405         T=mktime(&tm);
00406         sprintf(event,"EVT%04d|%ld|%ld|lat|lon|dep|T0|%s",
00407                         id,T,T+length,asctime(&tm));
00408         // create the request directory in $OMNIDIR/Data
00409         sprintf(line,"%s/Data/EVT%04d",omniDir,id);
00410         mkdir(line,0777);
00411         // create the request file in $OMNIDIR/Data
00412         sprintf(line,"%s/Data/EVT%04d/EVT%04d",
00413                         omniDir,id,id);
00414         if (NULL!=(f=fopen(line,"wt")))
00415         {
00416                 fprintf(f,"%s",event);
00417                 fclose(f);
00418         }
00419         PrintError("iline='%s', sl=%d\n",iline,sl);
00420         // read the stations
00421         while (sl<strlen(iline))
00422         {
00423                 char c;
00424                 int len=0;
00425                 memset(sta,0,128);
00426                 // find '='
00427                 while (sl<strlen(iline))
00428                 {
00429                         c=iline[sl++];
00430                         if (c=='=')
00431                         {
00432                                 break;
00433                         }
00434                 }
00435                 // copy chars untill '&'
00436                 while (sl<strlen(iline))
00437                 {
00438                         c=iline[sl++];
00439                         if (c=='&')
00440                         {
00441                                 break;
00442                         }
00443                         if (!isalnum(c))
00444                         {
00445                                 break;
00446                         }
00447                         sta[len++]=c;
00448                         if (len>32)
00449                         {
00450                                 break;
00451                         }
00452                 }
00453                 // skip if the end is reached (empty string or string=submit)
00454                 if (len>0)
00455                 {
00456                         if (strcmp("submit",sta)==0)
00457                         {
00458                                 break;
00459                         }
00460                 }
00461                 if (len==0)
00462                 {
00463                         continue;
00464                 }
00465                 // now process the station
00466                 PrintError("processing '%s'\n",sta);
00467                 // if the stations is "ALLSTATIONS" then select all the stations...
00468                 if (0==strcmp(sta,"ALLSTATIONS"))
00469                 {
00470                         for (cur=omniStation; cur; cur=cur->next)
00471                         {
00472                                 // skip if the station is not running
00473                                 if (cur->running==0)
00474                                 {
00475                                         continue;
00476                                 }
00477                                 // skip if the station is not a data logger
00478                                 if ((cur->oif[ndx_sysd_OsirisPhysicalChannels].valid==0)||
00479                                                 (cur->oif[ndx_sysd_OsirisPhysicalChannels].value.d==0))
00480                                 {
00481                                         continue;
00482                                 }
00483                                 PrintError("    ok for '%s'\n",cur->name);
00484                                 // make sure the requests dir exists
00485                                 sprintf(line,"%s/%s/requests",omniDir,cur->name);
00486                                 mkdir(line,0777);
00487                                 // create the request file
00488                                 sprintf(line,"%s/%s/requests/EVT%04d",
00489                                                 omniDir,cur->name,id);
00490                                 if (NULL!=(f=fopen(line,"wt")))
00491                                 {
00492                                         fprintf(f,"%s",event);
00493                                         fclose(f);
00494                                 }
00495                         }
00496                         break;
00497                 }
00498                 // find the station in the list
00499                 for (cur=omniStation; cur; cur=cur->next)
00500                 {
00501                         PrintLog("%s/%s\n",sta,cur->name);
00502                         if (0==strcmp(sta,cur->name))
00503                         {
00504                                 break;
00505                         }
00506                 }
00507                 // skip if the station was not foud
00508                 if (cur==NULL)
00509                 {
00510                         PrintError("station '%s' not found\n",sta);
00511                         continue;
00512                 }
00513                 // skip if the station is not running
00514                 if (cur->running==0)
00515                 {
00516                         PrintError("station '%s' is not running\n",sta);
00517                         continue;
00518                 }
00519                 // skip if the station is not a data logger
00520                 if ((cur->oif[ndx_sysd_OsirisPhysicalChannels].valid==0)||
00521                         (cur->oif[ndx_sysd_OsirisPhysicalChannels].value.d==0))
00522                 {
00523                         continue;
00524                 }
00525                 PrintError("    ok for '%s'\n",sta);
00526                 sprintf(line,"%s/%s/requests",omniDir,sta);
00527                 mkdir(line,0777);
00528                 sprintf(line,"%s/%s/requests/EVT%04d",
00529                                 omniDir,sta,id);
00530                 if (NULL!=(f=fopen(line,"wt")))
00531                 {
00532                         fprintf(f,"%s",event);
00533                         fclose(f);
00534                 }
00535         }
00536 }
00537 
00540 struct OmniStationType * AddOmniStation(void)
00541 {
00542         struct OmniStationType *o,*cur;
00543         o=malloc(sizeof(struct OmniStationType));
00544         memset(o,0,sizeof(struct OmniStationType));
00545         if (omniStation==NULL)
00546         {
00547                 omniStation=o;
00548         }
00549         else
00550         {
00551                 for (cur=omniStation; cur->next; cur=cur->next) ;
00552                 cur->next=o;
00553         }
00554         return(o);
00555 }
00556 
00558 void TroubleShooting(void)
00559 {
00560         void PushHeader(void);
00561         void PushTailer(void);
00562         PushHeader();
00563         puts("<br><br><br>");
00564         puts("To contact Agecodagis SARL: mail to agecodagis@agecodagis.com or call +33 (0)5 61 97 84 46<br>");
00565         puts("<br><br><br>");
00566         puts("<ul>");
00567         puts("<li><b>with Mozilla or Firefox: the tooltip texts do not display errors but only the first line (station name)</b></li><br>");
00568         puts("download and install <a href=https://addons.mozilla.org/en-US/firefox/addon/1715>");
00569         puts("this addon: https://addons.mozilla.org/en-US/firefox/addon/1715</a>\n");
00570         puts("</ul>");
00571         PushTailer();
00572 }
00573 
00577 int ParseOmniOptions(char *cmd)
00578 {
00579         char *s=cmd;
00580         int next,error;
00581         if (*s==0)
00582         {
00583                 return(0);
00584         }
00585         if (*s!=',')
00586         {
00587                 return(-1);
00588         }
00589         while (*s)
00590         {
00591                 s++;
00592                 PrintDebug("%s\n",s);
00593                 next=0;
00594                 error=__LINE__;
00595                 if (strncmp(s,"verbose",7)==0)
00596                 {
00597                         verboseMode=1;
00598                         error=0;
00599                         next=7;
00600                 }
00601                 if (strncmp(s,"troubleshooting",15)==0)
00602                 {
00603                         TroubleShooting();
00604                         exit(0);
00605                 }
00606                 if (strncmp(s,"filterpostinput",15)==0)
00607                 {
00608                         FilterPostInput();
00609                         exit(0);
00610                 }
00611                 if (strncmp(s,"singlestation",13)==0)
00612                 {
00613                         omniMode=OMNI_SINGLESTATION;
00614                         error=0;
00615                         next=13;
00616                 }
00617                 if (strncmp(s,"configurator",12)==0)
00618                 {
00619                         omniMode=OMNI_CONFIGURATOR;
00620                         error=0;
00621                         next=12;
00622                 }
00623                 if (strncmp(s,"supervisor",10)==0)
00624                 {
00625                         omniMode=OMNI_SUPERVISOR;
00626                         error=0;
00627                         next=10;
00628                 }
00629                 if (strncmp(s,"matrix",6)==0)
00630                 {
00631                         omniMode=OMNI_MATRIX;
00632                         error=0;
00633                         next=6;
00634                 }
00635                 if (strncmp(s,"dataselect",10)==0)
00636                 {
00637                         omniMode=OMNI_DATASELECT;
00638                         error=0;
00639                         next=10;
00640                 }
00641                 if (strncmp(s,"map",3)==0)
00642                 {
00643                         omniMode=OMNI_BUILDMAP;
00644                         error=0;
00645                         next=3;
00646                 }
00647                 if (strncmp(s,"main",4)==0)
00648                 {
00649                         omniMode=OMNI_MAIN;
00650                         error=0;
00651                         next=4;
00652                 }
00653                 if (strncmp(s,"topo",4)==0)
00654                 {
00655                         omniMode=OMNI_BUILDTOPO;
00656                         error=0;
00657                         next=4;
00658                 }
00659                 if (strncmp(s,"showevent",9)==0)
00660                 {
00661                         omniMode=OMNI_SHOWEVENT;
00662                         error=0;
00663                         next=9;
00664                 }
00665                 if (strncmp(s,"datacenter",10)==0)
00666                 {
00667                         omniMode=OMNI_DATACENTER;
00668                         error=0;
00669                         next=10;
00670                 }
00671                 if (strncmp(s,"dispatchrequest",15)==0)
00672                 {
00673                         omniMode=OMNI_DISPATCH;
00674                         error=0;
00675                         next=15;
00676                 }
00677                 if (strncmp(s,"header",6)==0)
00678                 {
00679                         omniMode=OMNI_HEADER;
00680                         error=0;
00681                         next=6;
00682                 }
00683                 if (strncmp(s,"tailer",6)==0)
00684                 {
00685                         omniMode=OMNI_TAILER;
00686                         error=0;
00687                         next=6;
00688                 }
00689                 if (strncmp(s,"checkloadavg",12)==0)
00690                 {
00691                         CheckLoadAvg();
00692                         exit(0);
00693                 }
00694                 if (strncmp(s,"checkalert",12)==0)
00695                 {
00696                         CheckAlertFiles();
00697                         exit(0);
00698                 }
00699                 if (error)
00700                 {
00701                         PrintError("could not parse oif option string (error %d)\n",error);
00702                         return(-1);
00703                 }
00704                 s+=next;
00705         }
00706         return(0);
00707 }
00708 
00709 char * StationName(struct OmniStationType *cur)
00710 {
00711         static char r[32];
00712         if ((cur->oif[ndx_comd_Hostid].valid)&&(cur->oif[ndx_comd_StationName].valid))
00713         {
00714                 if (
00715                                 (strcmp(cur->oif[ndx_comd_StationName].value.s,cur->name))&&
00716                                 (strcmp(cur->oif[ndx_comd_Hostid].value.s,cur->name))&&
00717                                 (strcmp(cur->oif[ndx_comd_StationName].value.s,
00718                                         cur->oif[ndx_comd_Hostid].value.s))
00719                    )
00720                 {
00721                         sprintf(r,"%s[%s,%s]",cur->name,
00722                                         cur->oif[ndx_comd_StationName].value.s,
00723                                         cur->oif[ndx_comd_Hostid].value.s);
00724                         return(r);
00725                 }
00726         }
00727         if (cur->oif[ndx_comd_StationName].valid)
00728         {
00729                 if (strcmp(cur->oif[ndx_comd_StationName].value.s,cur->name))
00730                 {
00731                         sprintf(r,"%s[%s]",cur->name,cur->oif[ndx_comd_StationName].value.s);
00732                         return(r);
00733                 }
00734         }
00735         if (cur->oif[ndx_comd_Hostid].valid)
00736         {
00737                 if (strcmp(cur->oif[ndx_comd_Hostid].value.s,cur->name))
00738                 {
00739                         sprintf(r,"%s[%s]",cur->name,cur->oif[ndx_comd_Hostid].value.s);
00740                         return(r);
00741                 }
00742         }
00743         strcpy(r,cur->name);
00744         return(r);
00745 }
00746 
00748 void PushTailer(void)
00749 {
00750         double delta;
00751         puts("<div align=right>");
00752         puts("<a href=http://www.agecodagis.com>");
00753         puts("<img border=0 src=/www/agecodagis.gif><br>");
00754         puts("http://www.agecodagis.com");
00755         puts("</a> </div>");
00756         puts("<center> <font size=-1>");
00757         puts("Osiris Multiscale Network Infrastructure - Agecodagis");
00758         gettimeofday(&tvStop,NULL);
00759         delta=(double)(tvStop.tv_sec-tvStart.tv_sec)+1.e-6*(double)(tvStop.tv_usec-tvStart.tv_usec);
00760         printf("<br>t=%.1f\n",delta);
00761         puts("</font> </body> </html>");
00762 }
00763 
00765 void PushHeader(void)
00766 {
00767         char line[256];
00768         char *tmp;
00769         time_t T;
00770         struct tm tm;
00771         FILE *f;
00772         puts("Content-type: text/html\n");
00773         puts("<html>\n");
00774         puts("<head>\n");
00775         puts("        <meta http-equiv=\"Pragma\" content=\"no-cache\">\n");
00776         puts("        <META Http-Equiv=\"Cache-Control\" Content=\"no-cache\">\n");
00777         puts("        <meta http-equiv=\"Expires\" content=\"0\">\n");
00778         puts("        <meta name=\"Author\" content=\"Agecodagis OMNI\">\n");
00779         tmp=MyGetenv("TITLE");
00780         if (tmp)
00781         {
00782                 puts("        <title>OMNI - ");
00783                 puts(tmp); puts("         </title>\n");
00784         }
00785         puts("        <style type=\"text/css\">\n");
00786         puts("                A:visited {color: blue; text-decoration: none}\n");
00787         puts("                A:active {color: blue; text-decoration: none}\n");
00788         puts("                A:link {color: blue; text-decoration: none}\n");
00789         puts("        </style>\n");
00790         tmp=MyGetenv("REFRESH");
00791         if (tmp)
00792         {
00793                 puts("        <meta http-equiv='REFRESH' content='");
00794                 puts(tmp); puts("'>\n");
00795         }
00796         puts("</head>\n");
00797         puts("<body>\n");
00798         time(&T);
00799         memcpy(&tm,gmtime(&T),sizeof(struct tm));
00800         puts(OMNI_RELEASE_STR);
00801         strftime(line,127,"current time: %Y.%m.%d-%H:%M:%S",&tm);
00802         tmp=MyGetenv("REMOTE_ADDR");
00803         if (tmp)
00804         {
00805                 strcat(line,", client=");
00806                 strcat(line,tmp);
00807         }
00808         tmp=MyGetenv("REMOTE_USER");
00809         if (tmp)
00810         {
00811                 strcat(line,", user=");
00812                 strcat(line,tmp);
00813                 strcat(line," <a href=/www/cgi-bin/SwitchUser>switch user </a>\n");
00814         }
00815         puts(line);
00816         f=fopen("/proc/loadavg","rt");
00817         if (f)
00818         {
00819                 fgets(line,64,f);
00820                 fclose(f);
00821                 printf(" load: %s",line);
00822         }
00823         printf(" <a href=TroubleShooting target=TroubleShooting><b>TroubleShooting</b></a>");
00824         puts("<br>\n");
00825 }
00826 
00830 int StationDirSelect(const struct dirent* t)
00831 {
00832         char s[128];
00833         sprintf(s,"%s/config",t->d_name);
00834         if (access(s,R_OK)==0)
00835         {
00836                 return(1);
00837         }
00838         return(0);
00839 }
00840 
00844 time_t TimeOfFile(char *f)
00845 {
00846         struct stat sb;
00847         if (stat(f,&sb)!=0)
00848         {
00849                 fprintf(stderr,"%s %m",f);
00850                 return(-1);
00851         }
00852         return(sb.st_mtime);
00853 }
00854 
00856 time_t TimeOfInfo(struct OmniStationType *o)
00857 {
00858         if (o->oif[ndx_gpsd_SystemTime].valid)
00859         {
00860                 return(o->oif[ndx_gpsd_SystemTime].value.d);
00861         }
00862         if (o->oif[ndx_diskmgr_LastAcquisitCorrectedTime].valid)
00863         {
00864                 return(o->oif[ndx_diskmgr_LastAcquisitCorrectedTime].value.d);
00865         }
00866         if (o->oif[ndx_acquisit_CorrectedTime].valid)
00867         {
00868                 return(o->oif[ndx_acquisit_CorrectedTime].value.d);
00869         }
00870         return(time(NULL)-o->shi.age);
00871 }
00872 
00873 void ResetInformation()
00874 {
00875         int i;
00876         for (i=0; i<OIF_FIELDS_NUMBER-1; i++)
00877         {
00878                 memset(OIFList[i]->value.s,0,sizeof(OIFList[i]->value.s));
00879                 OIFList[i]->valid=0;
00880         }
00881         alertFlag=0;
00882         memset(&(myShi),0,sizeof(struct ShortInfos));
00883         memset(osirisErrorMessage,0,sizeof(osirisErrorMessage));
00884 }
00885 
00886 void UpdateMap(gdImagePtr im, double scale, double shape, int mapX, int mapY,
00887                 double minLat, double maxLat,
00888                 double minLon, double maxLon)
00889 {
00890         
00891         int bcolor[2],b,black;
00892         char boundary[2][20] = { "political","marine" };
00893         char tmp[128];
00894         char *ptmp;
00895         FILE *f;
00896         int first=0;
00897         gdPoint points[2];
00898         void ProcessOneMapFile(char *fn,int color)
00899         {
00900                 f=fopen(fn,"rb");
00901                 first=1;
00902                 if (f)
00903                 {
00904                         double lat,lon;
00905                         while (!feof(f))
00906                         {
00907                                 fread(&lon,sizeof(double),1,f);
00908                                 if (lon>180.) lon-=360.;
00909                                 if (lon<-180.) lon+=360.;
00910                                 fread(&lat,sizeof(double),1,f);
00911                                 if (
00912                                                 (isnan(lat))||(isnan(lon))
00913                                                 ||
00914                                                 (lon<minLon)||(lon>maxLon)
00915                                                 ||
00916                                                 (lat<minLat)||(lat>maxLat)
00917                                                 )
00918                                 {
00919                                         first=1;
00920                                         continue;
00921                                 }
00922                                 points[1].x=     (int)(scale*(lon-minLon));
00923                                 points[1].y=mapY-(int)(shape*scale*(lat-minLat));
00924                                 if (first==0)
00925                                 {
00926                                         gdImageOpenPolygon(im,points,2,color);
00927                                 }
00928                                 points[0].x=points[1].x;
00929                                 points[0].y=points[1].y;
00930                                 first=0;
00931                         }
00932                         fclose(f);
00933                 }
00934         }
00935 
00936         black=gdImageColorAllocate(im, 0, 0, 0);
00937         bcolor[0]=gdImageColorAllocate(im, 0, 0, 0);
00938         bcolor[1]=gdImageColorAllocate(im, 0, 0, 255);
00939         // plot the boundaries
00940         for (b=0; b<2; b++)
00941         {
00942                 // if the map is large, use the large wide set
00943                 if ((maxLon-minLon>40.)||(maxLat-minLat>40.))
00944                 {
00945                         sprintf(tmp,"%s/www/mapdata/%s-large.dat",omniDir,boundary[b]);
00946                         ProcessOneMapFile(tmp,bcolor[b]);
00947                 }
00948                 // else use the fine data sets
00949                 else
00950                 {
00951                         double bMinLat, bMaxLat, bMinLon, bMaxLon;
00952                         int xBlock,yBlock;
00953                         // test each block
00954                         for (xBlock=0; xBlock<36; xBlock++)
00955                         {
00956                                 bMinLon=-180.+(double)xBlock*10.0;
00957                                 bMaxLon=bMinLon+10.;
00958                                 if ((maxLon<bMinLon)||(minLon>bMaxLon))
00959                                 {
00960                                         continue;
00961                                 }
00962                                 for (yBlock=0; yBlock<18; yBlock++)
00963                                 {
00964                                         bMinLat=80.-(double)yBlock*10.0;
00965                                         bMaxLat=bMinLat+10.;
00966                                         if ((maxLat<bMinLat)||(minLat>bMaxLat))
00967                                         {
00968                                                 continue;
00969                                         }
00970                                         sprintf(tmp,"%s/www/mapdata/%s-%02d_%02d.dat",
00971                                                         omniDir,boundary[b],
00972                                                         xBlock,yBlock);
00973                                         ProcessOneMapFile(tmp,bcolor[b]);
00974                                 }
00975                         }
00976                 }
00977         }
00978         ptmp=MyGetenv("REMOTE_HOST");
00979         if (ptmp)
00980         {
00981                 sprintf(tmp,"%s/www/mapdata/%s.dat",omniDir,ptmp);
00982                 ProcessOneMapFile(tmp,black);
00983         }
00984 }
00985 
00986 // issue the page for the topology map
00987 void BuildTopologyMap()
00988 {
00989         struct NodeType
00990         {
00991                 unsigned hostid;
00992                 char name[128];
00993                 float lat,lon;
00994                 int status; // 0=unknown location, 2=known, 1=computed
00995                 struct OmniStationType *o;
00996                 int cluster;
00997         };
00998 
00999         FILE *f;
01000         char tmp[256];
01001         struct NodeType *node;
01002         int i,j,cluster,c;
01003         int **contact;
01004         int nodeCnt;
01005         struct OmniStationType *cur;
01006 
01007 
01008         // look in the node table, find the hostid, add if not found
01009         int FindByHostid(unsigned h)
01010         {
01011                 int ii;
01012                 for (ii=0; (ii<nodeCnt)&&(node[ii].hostid!=0); ii++)
01013                 {
01014                         if (node[ii].hostid==h)
01015                         {
01016                                 return(ii);
01017                         }
01018                 }
01019                 // not found: add
01020                 node[ii].hostid=h;
01021                 sprintf(node[ii].name,"%x",h);
01022                 return(ii);
01023         }
01024 
01025         void DebugMatrix(void)
01026         {
01027                 int _i,_j;
01028                 puts("<br><br><br>debug<br>");
01029                 // dump the nodes
01030                 for (_i=0; (node[_i].hostid!=0)&&(_i<nodeCnt); _i++)
01031                 {
01032                         //if (node[_i].cluster>0)
01033                         {
01034                                 printf("%8x:%s[%d] ",node[_i].hostid,node[_i].name,node[_i].cluster);
01035                         }
01036                 }
01037                 // dump the matrix
01038                 puts("<br><pre>");
01039                 for (_i=0; (node[_i].hostid!=0)&&(_i<nodeCnt); _i++)
01040                 {
01041                         /*
01042                         if (node[_i].cluster==0)
01043                         {
01044                                 continue;
01045                         }
01046                         */
01047                         for (_j=0; (node[_j].hostid!=0)&&(_j<nodeCnt); _j++)
01048                         {
01049                                 /*
01050                                 if (node[_j].cluster==0)
01051                                 {
01052                                         continue;
01053                                 }
01054                                 */
01055                                 printf("%2x",contact[_i][_j]);
01056                         }
01057                         printf("\n");
01058                 }
01059                 puts("</pre>");
01060         }
01061 
01062 
01063         // count the stations
01064         nodeCnt=0;
01065         for (cur=omniStation; cur; cur=cur->next)
01066         {
01067                 nodeCnt++;
01068         }
01069         nodeCnt*=2; // de la marge
01070         // allocate the contact contact
01071         contact=(int **)calloc(2*nodeCnt,sizeof(int*)); // et encore de la marge
01072         if (contact==0)
01073         {
01074                 exit(2);
01075         }
01076         for (i=0; i<2*nodeCnt; i++)
01077         {
01078                 contact[i]=(int *)calloc(2*nodeCnt,sizeof(int)); // et encore de la marge
01079                 if (contact[i]==0)
01080                 {
01081                         exit(1);
01082                 }
01083         }
01084         // allocate the node table
01085         node=(struct NodeType *)calloc(2*nodeCnt,sizeof(struct NodeType)); // et encore de la marge
01086         if (node==0)
01087         {
01088                 exit(1);
01089         }
01090         // initialise the known nodes
01091         i=0;
01092         for (cur=omniStation; cur; cur=cur->next)
01093         {
01094                 // skip station not running
01095                 if (cur->running==0)
01096                 {
01097                         continue;
01098                 }
01099                 if (1!=sscanf(cur->oif[ndx_comd_Hostid].value.s,"%x",&(node[i].hostid)))
01100                 {
01101                         continue;
01102                 }
01103                 //strtol(nptr, (char **)NULL, 10);
01104                 if ((cur->oif[ndx_gpsd_AvgLat].valid==1)&&(cur->oif[ndx_gpsd_AvgLon].valid==1))
01105                 {
01106                         node[i].lat=cur->oif[ndx_gpsd_AvgLat].value.f;
01107                         node[i].lon=cur->oif[ndx_gpsd_AvgLon].value.f;
01108                         node[i].status=2;
01109                 }
01110                 node[i].o=cur;
01111                 strcpy(node[i].name,cur->name);
01112                 i++;
01113                 if (i>=nodeCnt)
01114                 {
01115                         exit(255);
01116                 }
01117         }
01118         // read the routing table for each known node
01119         for (cur=omniStation; cur; cur=cur->next)
01120         {
01121                 unsigned myHostid;
01122                 int myNode,aNode;
01123                 if (cur->running==0)
01124                 {
01125                         continue;
01126                 }
01127                 if (sscanf(cur->oif[ndx_comd_Hostid].value.s,"%x",&myHostid)!=1)
01128                 {
01129                         continue;
01130                 }
01131                 if (myHostid==0)
01132                 {
01133                         continue;
01134                 }
01135                 // skip station with old information
01136                 if (abs(TimeOfInfo(cur)-time(NULL))>3*3600)
01137                 {
01138                         continue;
01139                 }
01140                 myNode=FindByHostid(myHostid);
01141 
01142                 sprintf(tmp,"%s/%s/%s.oif",omniDir,cur->name,cur->name);
01143                 f=fopen(tmp,"rt");
01144                 if (!f)
01145                 {
01146                         continue;
01147                 }
01148                 // look for the routing table
01149                 i=0;
01150                 while (!feof(f))
01151                 {
01152                         tmp[0]=0;
01153                         fgets(tmp,255,f);
01154                         if (0==strncmp("# Destination      Gateway",tmp,26))
01155                         {
01156                                 i=1;
01157                                 break;
01158                         }
01159                 }
01160                 if (i==0)
01161                 {
01162                         continue;
01163                 }
01164                 // look for gateways
01165                 while (!feof(f))
01166                 {
01167                         char g[64];
01168                         char interface[64];
01169                         unsigned h;
01170                         tmp[0]=0;
01171                         fgets(tmp,255,f);
01172                         if (0==strncmp(tmp,"#####################",15))
01173                         {
01174                                 break;
01175                         }
01176                         g[0]=0;
01177                         sscanf(tmp,"%*s %*s %s",g);
01178                         // skip non GW
01179                         if (strcmp(g,"0.0.0.0")!=0)
01180                         {
01181                                 continue;
01182                         }
01183                         h=0;
01184                         interface[i]=0;
01185                         if (sscanf(tmp,"%*s %*s %*s %x %*s %*s %*s %s",
01186                                         &h,interface)!=2)
01187                         {
01188                                 continue;
01189                         }
01190                         if (h==0)
01191                         {
01192                                 continue;
01193                         }
01194                         aNode=FindByHostid(h);
01195                         // update the contact matrix
01196                         if ((aNode>=0)&&(aNode!=myNode))
01197                         {
01198                                 contact[myNode][aNode]|=CONTACT;
01199                                 if (0==strncmp(interface,"eth",3))
01200                                 {
01201                                         contact[myNode][aNode]|=ETHERNET;
01202                                 }
01203                                 if (0==strncmp(interface,"ppp",3))
01204                                 {
01205                                         contact[myNode][aNode]|=PPP;
01206                                 }
01207                                 if (0==strncmp(interface,"wlan",4))
01208                                 {
01209                                         contact[myNode][aNode]|=WIRELESS;
01210                                 }
01211                                 if (0==strncmp(interface,"tun",3))
01212                                 {
01213                                         contact[myNode][aNode]|=VPN;
01214                                 }
01215                                 if (0==strncmp(interface,"usb",3))
01216                                 {
01217                                         contact[myNode][aNode]|=USB;
01218                                 }
01219                         }
01220                 }
01221                 fclose(f);
01222         // end for
01223         }
01224 
01225         // make the matrix symetric
01226         for (i=0; (node[i].hostid!=0)&&(i<nodeCnt); i++)
01227         {
01228                 for (j=0; (node[j].hostid)&&(j<nodeCnt); j++)
01229                 {
01230                         contact[i][j]|=contact[j][i];
01231                 }
01232         }
01233 
01234         // group by cluster
01235         cluster=1;
01236         // initiate the very first cluster
01237         node[0].cluster=contact[0][0]=cluster;
01238         while (1)
01239         {
01240                 int cont=0;
01241                 // debug
01242                 //DebugMatrix();
01243                 // try to propagate clusters
01244                 // for each node
01245                 for (i=0; i<nodeCnt; i++)
01246                 {
01247                         // if the cluster is defined for this node
01248                         if (node[i].cluster==0) continue;
01249                         // propagate it
01250                         for (j=0; j<nodeCnt; j++)
01251                         {
01252                                 // skip already adopted nodes
01253                                 if (node[j].cluster!=0) continue;
01254                                 if (i==j) continue;
01255                                 if ((contact[i][j]!=0)||(contact[j][i]!=0))
01256                                 {
01257                                         node[j].cluster=node[i].cluster;
01258                                         contact[j][j]=node[i].cluster;
01259                                         cont=1;
01260                                 }
01261                         }
01262                 }
01263                 if (cont) continue;
01264                 // if we are here, than no cluster was propagated: create a new cluster
01265                 cluster++;
01266                 // find a clusterless node
01267                 for (i=0; i<nodeCnt; i++)
01268                 {
01269                         if (node[i].cluster==0)
01270                         {
01271                                 node[i].cluster=cluster;
01272                                 cont=1;
01273                                 break;
01274                         }
01275                 }
01276                 if (cont) continue;
01277                 // if we are there than no more node remains: stop
01278                 break;
01279         }
01280 #if 0
01281         for (i=0; i<nodeCnt; i++)
01282         {
01283                 int alone=1;
01284                 int increase=0;
01285                 if (node[i].hostid==0) continue;
01286                 // if the statring node is not yet defined (the first of a new cluster)
01287                 if (node[i].cluster==0)
01288                 {
01289                         increase=1;
01290                         node[i].cluster=cluster;
01291                         contact[i][i]=cluster;
01292                 }
01293                 // toggle all the nodes that belong to that cluster also
01294                 for (j=0; j<nodeCnt; j++)
01295                 {
01296                         if (i==j) continue;
01297                         //if (node[j].hostid==0) continue;
01298                         if ((contact[i][j]!=0)||(contact[j][i]!=0))
01299                         {
01300                                 if (node[j].cluster<=0)
01301                                 {
01302                                         node[j].cluster=node[i].cluster;
01303                                         contact[j][j]=node[i].cluster;
01304                                 }
01305                                 alone=0;
01306                         }
01307                 }
01308                 if (alone==1)
01309                 {
01310                         node[i].cluster=0;
01311                 }
01312                 else
01313                 {
01314                         cluster+=increase;
01315                 }
01316         }
01317 #endif
01318         // update the location for the non located nodes
01319         for (i=0; (node[i].hostid!=0)&&(i<nodeCnt); i++)
01320         {
01321                 int cnt;
01322                 sprintf(tmp,"%s/%s/%s.geo",omniDir,node[i].name,node[i].name);
01323                 f=fopen(tmp,"rt");
01324                 if (f)
01325                 {
01326                         float lat,lon;
01327                         if (fscanf(f,"%f %f",&lat,&lon)==2)
01328                         {
01329                                 node[i].lat=lat;
01330                                 node[i].lon=lon;
01331                                 node[i].status=2;
01332                         }
01333                 }
01334                 if (node[i].status!=0)
01335                 {
01336                         continue;
01337                 }
01338                 node[i].lat=node[i].lon=0.0;
01339                 cnt=0;
01340                 for (j=0; (node[j].hostid)&&(j<nodeCnt); j++)
01341                 {
01342                         int k;
01343                         if (node[j].status==0)
01344                         {
01345                                 continue;
01346                         }
01347                         k=contact[i][j]*node[j].status;
01348                         node[i].lat+=node[j].lat*(double)k;
01349                         node[i].lon+=node[j].lon*(double)k;
01350                         cnt+=k;
01351                 }
01352                 if (cnt>0)
01353                 {
01354                         node[i].lat/=(double)cnt;
01355                         node[i].lon/=(double)cnt;
01356                         node[i].status=1;
01357                 }
01358         }
01359         // build one map for each cluster
01360         // include the image (map)
01361         puts("<center><h2>Connectivity maps</h2></center>");
01362         puts("<center><a href=/www/cgi-bin/Supervisor>OMNI supervisor page</a></center>");
01363         puts("<br><br>");
01364         // for each cluster
01365         for (c=0; c<cluster; c++) // cluster number is c+1
01366         {
01367                 double minLon=0.,minLat=0.,maxLon=0.,maxLat=0.,delta,shape,scale;
01368                 int first=1;
01369                 int mapX,mapY,count;
01370                 int white,red,black,blue,grey;
01371                 gdImagePtr im;
01372                 char *ptmp;
01373                 // count the number of node for this cluster
01374                 count=0;
01375                 for (i=0; (node[i].hostid!=0)&&(i<nodeCnt); i++)
01376                 {
01377                         if (node[i].cluster==c+1)
01378                         {
01379                                 count++;
01380                         }
01381                 }
01382                 if (count==1)
01383                 {
01384                         for (i=0; (node[i].hostid!=0)&&(i<nodeCnt); i++)
01385                         {
01386                                 if (node[i].cluster==c+1)
01387                                 {
01388                                         node[i].cluster=0;
01389                                 }
01390                         }
01391                 }
01392                 if (count<=2)
01393                 {
01394                         continue;
01395                 }
01396                 if (count<3)
01397                 {
01398                         printf("Cluster %d contains only ",c+1);
01399                         for (i=0; (node[i].hostid!=0)&&(i<nodeCnt); i++)
01400                         {
01401                                 if (node[i].cluster!=c+1) continue;
01402                                 if (node[i].o)
01403                                 {
01404                                         printf("<a href=/www/cgi-bin/SingleStation?%s alt=%s "
01405                                                 "title=\"%s\n%s\">%s </a>\n",
01406                                                 node[i].name,node[i].name,
01407                                                 StationName(node[i].o),
01408                                                 node[i].o->alertTip,StationName(node[i].o));
01409                                 }
01410                                 else
01411                                 {
01412                                         printf("%s ",node[i].name);
01413                                 }
01414                         }
01415                         puts("<br>");
01416                         continue;
01417                 }
01418                 // compute min/max locations
01419                 for (i=0; (node[i].hostid!=0)&&(i<nodeCnt); i++)
01420                 {
01421                         // skip nodes not blonging to the current cluster
01422                         if (node[i].cluster!=c+1)
01423                         {
01424                                 continue;
01425                         }
01426                         // and also the not located nodes
01427                         if (node[i].status==0)
01428                         {
01429                                 continue;
01430                         }
01431                         if (first)
01432                         {
01433                                 minLon=maxLon=node[i].lon;
01434                                 minLat=maxLat=node[i].lat;
01435                         }
01436                         first=0;
01437                         if (node[i].lon>maxLon) maxLon=node[i].lon;
01438                         if (node[i].lat>maxLat) maxLat=node[i].lat;
01439                         if (node[i].lon<minLon) minLon=node[i].lon;
01440                         if (node[i].lat<minLat) minLat=node[i].lat;
01441                 }
01442                 shape=1./cos(M_PI*0.5*(maxLat+minLat)/180.);
01443                 delta=0.0001+(maxLon-minLon)*0.2;
01444                 maxLon+=delta;
01445                 minLon-=delta;
01446                 delta=0.0001+(maxLat-minLat)*0.2;
01447                 maxLat+=delta;
01448                 minLat-=delta;
01449 
01450                 // compute the scale factor
01451                 if (((maxLat-minLat)/(maxLon-minLon))<((double)MAPY/(double)MAPX))
01452                 {
01453                         mapX=(int)((double)MAPX);
01454                         scale=(double)mapX/(maxLon-minLon);
01455                         mapY=(int)((double)MAPY*
01456                                 ((maxLat-minLat)/(maxLon-minLon))/
01457                                 ((double)MAPY/(double)MAPX));
01458                 }
01459                 else
01460                 {
01461                         mapY=MAPY;
01462                         scale=(double)mapY/(maxLat-minLat);
01463                         mapX=(int)((double)MAPX/
01464                                 (((maxLat-minLat)/(maxLon-minLon))/
01465                                 ((double)MAPY/(double)MAPX)));
01466                 }
01467 
01468                 mapY=(int)((double)mapY*shape);
01469 
01470