]> git.ipfire.org Git - thirdparty/sarg.git/blob - grepday.c
Fix the graph plotting to use a computed logarithmic scale when plotting bytes.
[thirdparty/sarg.git] / grepday.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2010
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
24 *
25 */
26
27 #include "include/conf.h"
28 #include "include/defs.h"
29
30 #if defined(HAVE_GD)
31
32 #if defined(HAVE_ICONV_H) && defined(gdFTEX_Unicode)
33 #include <iconv.h>
34 #define USE_ICONV 1
35 #endif
36
37 struct GraphDataStruct
38 {
39 int lavender;
40 int darkblue;
41 int dimgray;
42 int goldenrod;
43 int goldenrod2;
44 int gray;
45 int silver;
46 int black;
47 //! The color of the top side of a graph bar.
48 int color1;
49 //! The color of the right side of a graph bar.
50 int color2;
51 //! The color of the front side of a graph bar.
52 int color3;
53 //! The libgd image we are drawing on.
54 gdImage *im;
55 //! An allocated buffer to convert the string into UTF-8.
56 char *string;
57 //! The number of bytes allocated for the string buffer.
58 size_t string_size;
59 //! The bottom border of the graph.
60 int BottomGraph;
61 //! The top border of the graph.
62 int TopGraph;
63 //! The left border of the graph.
64 int LeftGraph;
65 //! The right border of the graph.
66 int RightGraph;
67 //! The height at which the bottom depth border of the graph extends.
68 int BottomDepth;
69 //! The distance between two ticks on the horizontal axis.
70 double XScale;
71 //! The distance between two ticks on the vertical axis.
72 double YScale;
73 //! The exterior length of a tick on the scales.
74 int TickLength;
75 //! The distance, in pixels, between two ticks along the Y axis.
76 int YTickSpace;
77 };
78
79 enum PlotType
80 {
81 PTG_LinBin,
82 PTG_LogBin,
83 PTG_Time,
84 };
85
86 struct PlotStruct
87 {
88 //! The data points to plot.
89 long long int *datapoints;
90 //! The number of points to plot.
91 int npoints;
92 //! The minimum data to plot along the Y axis.
93 long long int ymin;
94 //! The maximum data to plot along the Y axis.
95 long long int ymax;
96 //! The type of Y axis to draw.
97 enum PlotType ytype;
98 //! The label to write on the Y axis.
99 const char *YLabel;
100 };
101
102 enum TextRefPos
103 {
104 TRP_TopLeft,
105 TRP_TopCenter,
106 TRP_TopRight,
107 TRP_BottomLeft,
108 TRP_BottomCenter,
109 TRP_BottomRight,
110 TRP_CenterLeft,
111 TRP_Center,
112 TRP_CenterRight,
113 };
114
115 #ifdef USE_ICONV
116 //! The iconv object to convert the text from the locale character set to UTF-8.
117 iconv_t localtoutf=(iconv_t)-1;
118 #endif
119
120 static void Sarg_gdImageStringFT (struct GraphDataStruct *gdata, int fg, char *fontlist,
121 double ptsize, double angle, int x, int y, const char *string,enum TextRefPos RefPos)
122 {
123 char *sstring;
124 char *retval;
125 int brect[8];
126 int minx,miny,maxx,maxy;
127 int i;
128
129 #ifdef USE_ICONV
130 if (localtoutf!=(iconv_t)-1) {
131 const char *str;
132 char *sstr;
133 size_t slen, sslen;
134
135 slen = strlen(string) + 1; // We must include string termination character
136 sslen = slen * 3; // We assume that the UTF8 string will not be bigger than 3 times the original size.
137 if (sslen>gdata->string_size) {
138 sstring = (char *)realloc(gdata->string,sslen);
139 if (!sstring) {
140 debuga(_("realloc error (%zu bytes required)\n"),sslen);
141 exit(EXIT_FAILURE);
142 }
143 gdata->string=(char *)sstring;
144 gdata->string_size=sslen;
145 } else {
146 sstring=gdata->string;
147 sslen=gdata->string_size;
148 }
149
150 str = string;
151 sstr = sstring;
152 if (iconv (localtoutf, (ICONV_CONST char **)&str, &slen, &sstr, &sslen)==-1) {
153 debuga(_("(grepday) iconv failed to convert string \"%s\" from %s to UTF-8 - %s\n"),string,CharSet,strerror(errno));
154 sstring=(char *)string; //show something sensible on the graph
155 }
156 } else {
157 sstring=(char *)string; //show something sensible on the graph
158 }
159 #else
160 sstring=(char *)string;
161 #endif
162
163 if (RefPos!=TRP_BottomLeft) {
164 retval = gdImageStringFTEx (NULL, brect, fg, fontlist, ptsize, angle, 0, 0, sstring, gdFTEX_Unicode);
165 if (retval) {
166 debuga(_("libgd failed to calculate the bounding box of the text \"%s\": %s\n"),sstring,retval);
167 exit(EXIT_FAILURE);
168 }
169 /*
170 From libgd documentation, brect contains this without taking into account the angle:
171 0 lower left corner, X position
172 1 lower left corner, Y position
173 2 lower right corner, X position
174 3 lower right corner, Y position
175 4 upper right corner, X position
176 5 upper right corner, Y position
177 6 upper left corner, X position
178 7 upper left corner, Y position
179 */
180 minx=maxx=brect[0];
181 miny=maxy=brect[1];
182 for (i=2 ; i<7 ; i+=2) {
183 if (minx>brect[i]) minx=brect[i];
184 if (maxx<brect[i]) maxx=brect[i];
185 if (miny>brect[i+1]) miny=brect[i+1];
186 if (maxy<brect[i+1]) maxy=brect[i+1];
187 }
188 }
189
190 switch (RefPos)
191 {
192 case TRP_TopLeft:
193 y-=miny;
194 break;
195
196 case TRP_TopCenter:
197 x-=(maxx-minx)/2;
198 y-=miny;
199 break;
200
201 case TRP_TopRight:
202 x-=maxx;
203 y-=miny;
204 break;
205
206 case TRP_BottomLeft:
207 break;
208
209 case TRP_BottomCenter:
210 x-=(maxx-minx)/2;
211 break;
212
213 case TRP_BottomRight:
214 x-=maxx;
215 break;
216
217 case TRP_Center:
218 x-=(maxx-minx)/2;
219 y+=(maxy-miny)/2;
220 break;
221
222 case TRP_CenterLeft:
223 y+=(maxy-miny)/2;
224 break;
225
226 case TRP_CenterRight:
227 x-=maxx;
228 y+=(maxy-miny)/2;
229 break;
230 }
231 retval = gdImageStringFTEx (gdata->im, brect, fg, fontlist, ptsize, angle, x, y, sstring, gdFTEX_Unicode);
232 if (retval) {
233 debuga(_("libgd failed to render the text \"%s\": %s\n"),sstring,retval);
234 exit(EXIT_FAILURE);
235 }
236 }
237
238 static void bar(struct GraphDataStruct *gdata,int x1,double y,const char *label)
239 {
240 gdPoint points[4];
241 int val=0;
242 int width2;
243
244 val=gdata->BottomGraph+5-(int)(y*gdata->YScale+0.5);
245
246 width2=(int)(gdata->XScale/4.);
247 gdImageFilledRectangle(gdata->im, x1-width2, val, x1+width2, gdata->BottomDepth, gdata->color3);
248
249 points[0].x = x1-width2+5;
250 points[0].y = val-5;
251 points[1].x = x1-width2;
252 points[1].y = val;
253 points[2].x = x1+width2;
254 points[2].y = val;
255 points[3].x = x1+width2+5;
256 points[3].y = val-5;
257 gdImageFilledPolygon(gdata->im, points, 4, gdata->color1);
258
259 gdImageLine(gdata->im, x1+2, val-2, x1+2, val-10, gdata->dimgray);
260 gdImageFilledRectangle(gdata->im, x1-8, val-20, x1+12, val-10, gdata->goldenrod);
261 gdImageRectangle(gdata->im, x1-8, val-20, x1+12, val-10, gdata->goldenrod2);
262
263 Sarg_gdImageStringFT(gdata,gdata->black,GraphFont,6,0.0,x1+2,val-12,label,TRP_BottomCenter);
264
265 points[0].x = x1+width2+5;
266 points[0].y = val-5;
267 points[1].x = x1+width2;
268 points[1].y = val;
269 points[2].x = x1+width2;
270 points[2].y = gdata->BottomDepth;
271 points[3].x = x1+width2+5;
272 points[3].y = gdata->BottomGraph;
273 gdImageFilledPolygon(gdata->im, points, 4, gdata->color2);
274
275 return;
276 }
277
278 static int greport_compute_yaxis(struct PlotStruct *pdata,struct GraphDataStruct *gdata)
279 {
280 double symin,symax;
281 double range;
282 double yscale;
283 double ymag;
284
285 if (pdata->ymin<0.) {
286 debuga(_("Minimum for Y scale of the graph is out of range: %lld\n"),pdata->ymin);
287 return(-1);
288 }
289 if (pdata->ymax<=0.) {
290 debuga(_("Maximum for Y scale of the graph is out of range: %lld\n"),pdata->ymax);
291 return(-1);
292 }
293
294 switch(pdata->ytype)
295 {
296 case PTG_LinBin:
297 symin=(double)pdata->ymin;
298 symax=(double)pdata->ymax;
299 ymag=1024.;
300 break;
301
302 case PTG_LogBin:
303 if (pdata->ymin>0.)
304 symin=log(pdata->ymin)/log(1024);
305 else
306 symin=0.;
307 symax=log(pdata->ymax)/log(1024);
308 ymag=1024.;
309 break;
310
311 case PTG_Time:
312 symin=(double)pdata->ymin;
313 symax=(double)pdata->ymax;
314 ymag=1.;
315 break;
316
317 default:
318 debuga(_("Unknown type %d for Y axis scale\n"),pdata->ytype);
319 return(-1);
320 }
321 gdata->YTickSpace=10;
322
323 range=symax-symin;
324 yscale=(double)(gdata->BottomGraph-gdata->TopGraph)/range;
325 gdata->YScale=yscale;
326 return(0);
327 }
328
329 static void greport_formatbin(double yval,int ndigits,char *string,int slen)
330 {
331 int len;
332 char schar[]={'\0','k','M','G','T','P'};
333 int scount;
334
335 for (scount=0 ; scount<sizeof(schar)/sizeof(*schar) && yval>=1024. ; scount++)
336 yval/=1024.;
337 if (ndigits>0)
338 len=snprintf(string,slen,"%.*lg",ndigits,yval);
339 else
340 len=snprintf(string,slen,"%.0lf",yval);
341 if (schar[scount] && len<slen) {
342 string[len++]=schar[scount];
343 string[len]='\0';
344 }
345 }
346
347 static void greport_draw_yaxis(struct PlotStruct *pdata,struct GraphDataStruct *gdata)
348 {
349 double yval;
350 int y0;
351 int y;
352 int yt;
353 char YLabel[50];
354 int xexterior;
355 int xinterior;
356 int xtick;
357
358 y0=gdata->BottomGraph;
359 yt=gdata->BottomDepth-gdata->BottomGraph;
360 xexterior=gdata->LeftGraph-10;
361 xinterior=gdata->LeftGraph;
362 xtick=gdata->LeftGraph-10-gdata->TickLength;
363 for(y=y0-gdata->YTickSpace ; y>=gdata->TopGraph ; y-=gdata->YTickSpace) {
364 gdImageLine(gdata->im, xtick, y+yt, xexterior, y+yt, gdata->dimgray);
365 gdImageLine(gdata->im, xexterior, y+yt, xinterior, y, gdata->dimgray);
366 gdImageLine(gdata->im, xinterior, y, gdata->RightGraph, y, gdata->dimgray);
367 switch (pdata->ytype)
368 {
369 case PTG_LinBin:
370 yval=(double)(y0-y)/gdata->YScale+(double)pdata->ymin;
371 greport_formatbin(yval,0,YLabel,sizeof(YLabel));
372 break;
373
374 case PTG_LogBin:
375 yval=pow(1024.,(double)(y0-y)/gdata->YScale+log(pdata->ymin)/log(1024));
376 greport_formatbin(yval,0,YLabel,sizeof(YLabel));
377 break;
378
379 case PTG_Time:
380 {
381 int t;
382
383 yval=(double)(y0-y)/gdata->YScale+(double)pdata->ymin;
384 t=(int)(yval/60000.);
385 snprintf(YLabel,sizeof(YLabel),"%02d:%02d",t/60,t%60);
386 break;
387 }
388 }
389 Sarg_gdImageStringFT(gdata,gdata->dimgray,GraphFont,7,0.0,xtick,y+yt,YLabel,TRP_CenterRight);
390 }
391 }
392
393 static void greport_plot(const struct userinfostruct *uinfo,struct PlotStruct *pdata)
394 {
395 FILE *pngout;
396 int x, y;
397 int day;
398 int x1;
399 char graph[MAXLEN];
400 char s[15];
401 char ftime[128];
402 time_t t;
403 struct tm *local;
404 gdPoint points[4];
405 struct GraphDataStruct gdata;
406 const int ImgXSize=720;
407 const int ImgYSize=480;
408 const int LeftMargin=60;
409 const int RightMargin=20;
410 const int TopMargin=60;
411 const int BottomMargin=60;
412 const int TickLength=3;
413 const int ZTickLength=5;
414 double yval;
415 char blabel[50];
416
417 memset(&gdata,0,sizeof(gdata));
418
419 gdata.im = gdImageCreate(ImgXSize, ImgYSize);
420 gdata.BottomGraph=ImgYSize-BottomMargin;
421 gdata.LeftGraph=LeftMargin;
422 gdata.RightGraph=ImgXSize-RightMargin;
423 gdata.TopGraph=TopMargin;
424 gdata.BottomDepth=gdata.BottomGraph+5;
425 gdata.XScale=(double)(gdata.RightGraph-gdata.LeftGraph)/(pdata->npoints+1);
426 if (greport_compute_yaxis(pdata,&gdata)<0) return;
427 gdata.TickLength=TickLength;
428
429 // first allocated color is the background
430 gdata.lavender = gdImageColorAllocate(gdata.im, 230, 230, 250);
431 gdata.gray = gdImageColorAllocate(gdata.im, 192, 192, 192);
432 gdata.silver = gdImageColorAllocate(gdata.im, 211, 211, 211);
433 gdata.black = gdImageColorAllocate(gdata.im, 0, 0, 0);
434 gdata.dimgray = gdImageColorAllocate(gdata.im, 105, 105, 105);
435 gdata.darkblue = gdImageColorAllocate(gdata.im, 0, 0, 139);
436 gdata.goldenrod = gdImageColorAllocate(gdata.im, 234, 234, 174);
437 gdata.goldenrod2 = gdImageColorAllocate(gdata.im, 207, 181, 59);
438
439 if(strcmp(GraphDaysBytesBarColor,"orange") == 0) {
440 gdata.color1 = gdImageColorAllocate(gdata.im, 255, 233, 142);
441 gdata.color2 = gdImageColorAllocate(gdata.im, 220, 163, 72);
442 gdata.color3 = gdImageColorAllocate(gdata.im, 255, 198, 107);
443 }
444 else if(strcmp(GraphDaysBytesBarColor,"blue") == 0) {
445 gdata.color1 = gdImageColorAllocate(gdata.im, 62, 80, 167);
446 gdata.color2 = gdImageColorAllocate(gdata.im, 40, 51, 101);
447 gdata.color3 = gdImageColorAllocate(gdata.im, 57, 73, 150);
448 }
449 else if(strcmp(GraphDaysBytesBarColor,"green") == 0) {
450 gdata.color1 = gdImageColorAllocate(gdata.im,120,166,129);
451 gdata.color2 = gdImageColorAllocate(gdata.im,84,113,82);
452 gdata.color3 = gdImageColorAllocate(gdata.im,158,223,167);
453 }
454 else if(strcmp(GraphDaysBytesBarColor,"yellow") == 0) {
455 gdata.color1 = gdImageColorAllocate(gdata.im,185,185,10);
456 gdata.color2 = gdImageColorAllocate(gdata.im,111,111,10);
457 gdata.color3 = gdImageColorAllocate(gdata.im,166,166,10);
458 }
459 else if(strcmp(GraphDaysBytesBarColor,"brown") == 0) {
460 gdata.color1 = gdImageColorAllocate(gdata.im,97,45,27);
461 gdata.color2 = gdImageColorAllocate(gdata.im,60,30,20);
462 gdata.color3 = gdImageColorAllocate(gdata.im,88,41,26);
463 }
464 else if(strcmp(GraphDaysBytesBarColor,"red") == 0){
465 gdata.color1 = gdImageColorAllocate(gdata.im,185,10,10);
466 gdata.color2 = gdImageColorAllocate(gdata.im,111,10,10);
467 gdata.color3 = gdImageColorAllocate(gdata.im,166,10,10);
468 } else {
469 debuga(_("Unknown color \"%s\" requested for the graph. Using orange instead\n"),GraphDaysBytesBarColor);
470 gdata.color1 = gdImageColorAllocate(gdata.im, 255, 233, 142);
471 gdata.color2 = gdImageColorAllocate(gdata.im, 220, 163, 72);
472 gdata.color3 = gdImageColorAllocate(gdata.im, 255, 198, 107);
473 }
474
475 // rectangle around the image
476 gdImageRectangle(gdata.im, 0, 0, ImgXSize-1, ImgYSize-1, gdata.dimgray);
477 // backtround of the graph
478 gdImageFilledRectangle(gdata.im, LeftMargin, gdata.TopGraph, gdata.RightGraph, gdata.BottomGraph, gdata.silver);
479
480 // depth of the left Y axis
481 points[0].x = gdata.LeftGraph-10;
482 points[0].y = gdata.TopGraph+5;
483 points[1].x = gdata.LeftGraph-10;
484 points[1].y = gdata.BottomDepth;
485 points[2].x = gdata.LeftGraph;
486 points[2].y = gdata.BottomGraph;
487 points[3].x = gdata.LeftGraph;
488 points[3].y = gdata.TopGraph;
489 gdImageFilledPolygon(gdata.im, points, 4, gdata.gray);
490
491 // depth of the bottom X axis
492 points[0].x = gdata.LeftGraph;
493 points[0].y = gdata.BottomGraph;
494 points[1].x = gdata.LeftGraph-10;
495 points[1].y = gdata.BottomDepth;
496 points[2].x = gdata.RightGraph-10;
497 points[2].y = gdata.BottomDepth;
498 points[3].x = gdata.RightGraph;
499 points[3].y = gdata.BottomGraph;
500 gdImageFilledPolygon(gdata.im, points, 4, gdata.gray);
501
502 // vertical exterior line of the depth
503 gdImageLine(gdata.im, LeftMargin-10, TopMargin+5, LeftMargin-10, gdata.BottomDepth+ZTickLength, gdata.black);
504 // horizontal exterior line of the depth
505 gdImageLine(gdata.im, LeftMargin-10-ZTickLength, gdata.BottomDepth, gdata.RightGraph-10, gdata.BottomDepth, gdata.black);
506 // diagonal line between the two depths
507 gdImageLine(gdata.im, LeftMargin-10, gdata.BottomDepth, LeftMargin, gdata.BottomGraph, gdata.black);
508 // vertical left line of the graph
509 gdImageLine(gdata.im, LeftMargin, gdata.BottomGraph, LeftMargin, gdata.TopGraph, gdata.black);
510 // horizontal bottom line of the graph
511 gdImageLine(gdata.im, LeftMargin, gdata.BottomGraph, gdata.RightGraph, gdata.BottomGraph, gdata.black);
512 // vertical right line of the graph
513 gdImageLine(gdata.im, gdata.RightGraph, gdata.TopGraph, gdata.RightGraph, gdata.BottomGraph, gdata.black);
514 // diagonal line to close the right of the bottom depth
515 gdImageLine(gdata.im, gdata.RightGraph-10, gdata.BottomDepth, gdata.RightGraph, gdata.BottomGraph, gdata.black);
516
517 // Y axis ticks
518 greport_draw_yaxis(pdata,&gdata);
519
520 // X axis ticks and labels
521 for(y=1; y<=pdata->npoints; y++) {
522 x=gdata.LeftGraph-10+(int)((double)y*gdata.XScale+0.5);
523 gdImageLine(gdata.im, x, gdata.BottomDepth, x, gdata.BottomDepth+TickLength, gdata.dimgray);
524 sprintf(s,"%02d",y);
525 Sarg_gdImageStringFT(&gdata,gdata.dimgray,GraphFont,7,0.0,x,gdata.BottomDepth+TickLength+1,s,TRP_TopCenter);
526 }
527
528 t = time(NULL);
529 local = localtime(&t);
530 if(DateFormat[0]=='u')
531 strftime(ftime, sizeof(ftime), "%b/%d/%Y %H:%M", local);
532 if(DateFormat[0]=='e')
533 strftime(ftime, sizeof(ftime), "%d/%b/%Y-%H:%M", local);
534
535 x=ImgXSize*5/12;
536 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,7,0.0,ImgXSize-10,ImgYSize-10,ftime,TRP_BottomRight);
537 if(ShowSargInfo) Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,10,0.0,x,15,_("SARG, "),TRP_BottomRight);
538 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,10,0.0,x,15,Title,TRP_BottomLeft);
539 sprintf(warea,_("Period: %s"),period.text);
540 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,9,0.0,x,27,warea,TRP_BottomLeft);
541 sprintf(warea,_("User: %s"),uinfo->label);
542 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,9,0.0,x,38,warea,TRP_BottomLeft);
543
544 Sarg_gdImageStringFT(&gdata,gdata.black,GraphFont,10,3.141592/2,20,ImgYSize/2,pdata->YLabel,TRP_CenterLeft);
545 Sarg_gdImageStringFT(&gdata,gdata.black,GraphFont,10,0.0,ImgXSize/2,ImgYSize-20,_("DAYS"),TRP_BottomCenter);
546
547 for (day=0 ; day<pdata->npoints ; day++) {
548 if (pdata->datapoints[day]>0) {
549 x1=gdata.LeftGraph-10+(int)((double)(day+1)*gdata.XScale+0.5);
550 switch (pdata->ytype)
551 {
552 case PTG_LinBin:
553 yval=(double)pdata->datapoints[day];
554 if (yval<pdata->ymin)
555 yval=0.;
556 else if (yval>pdata->ymax)
557 yval=pdata->ymax;
558 else
559 yval-=pdata->ymin;
560 //strcpy(blabel,fixnum(pdata->datapoints[day],0));
561 greport_formatbin(pdata->datapoints[day],2,blabel,sizeof(blabel));
562 break;
563 case PTG_LogBin:
564 yval=(double)pdata->datapoints[day];
565 if (yval<=pdata->ymin)
566 yval=0.;
567 else if (yval>pdata->ymax)
568 yval=log(pdata->ymax)/log(1024)-log(pdata->ymin)/log(1024);
569 else
570 yval=log(yval)/log(1024)-log(pdata->ymin)/log(1024);
571 greport_formatbin(pdata->datapoints[day],2,blabel,sizeof(blabel));
572 //strcpy(blabel,fixnum(pdata->datapoints[day],0));
573 break;
574 case PTG_Time:
575 {
576 int t;
577
578 yval=(double)pdata->datapoints[day];
579 if (yval<pdata->ymin)
580 yval=0.;
581 else if (yval>pdata->ymax)
582 yval=pdata->ymax;
583 else
584 yval-=pdata->ymin;
585 t=(int)(pdata->datapoints[day]/60000.);
586 snprintf(blabel,sizeof(blabel),"%d:%02d",t/60,t%60);
587 break;
588 }
589 }
590 bar(&gdata,x1,yval,blabel);
591 }
592 }
593
594 if (snprintf(graph,sizeof(graph),"%s/%s/graph_day.png",outdirname,uinfo->filename)>=sizeof(graph)) {
595 debuga(_("user name too long for %s/%s/graph_day.png\n"),outdirname,uinfo->filename);
596 exit(EXIT_FAILURE);
597 }
598 if((pngout=fopen(graph,"wb"))==NULL) {
599 debuga(_("(grepday) Cannot open log file %s\n"),graph);
600 exit(EXIT_FAILURE);
601 }
602 gdImagePng(gdata.im, pngout);
603 fclose(pngout);
604 gdImageDestroy(gdata.im);
605
606 if (gdata.string) free(gdata.string);
607 }
608
609 #endif //HAVE_GD
610
611 void greport_prepare(void)
612 {
613 #ifdef HAVE_GD
614 if(access(GraphFont, R_OK) != 0) {
615 debuga(_("(grepday) Fontname %s not found\n"),GraphFont);
616 exit(EXIT_FAILURE);
617 }
618
619 #ifdef USE_ICONV
620 localtoutf = iconv_open ("UTF-8", CharSet);
621 if (localtoutf==(iconv_t)-1) {
622 debuga(_("(grepday) iconv cannot convert from %s to UTF-8 - %s\n"),CharSet,strerror(errno));
623 }
624 #endif
625
626 #endif //HAVE_GD
627 }
628
629 void greport_day(const struct userinfostruct *uinfo)
630 {
631 #ifdef HAVE_GD
632 FILE *fp_in;
633 char wdirname[MAXLEN];
634 char buf[MAXLEN];
635 int day;
636 long long int llday;
637 long long int bytes;
638 long long int datapoints[31];
639 struct getwordstruct gwarea;
640 struct PlotStruct pdata;
641
642 if (snprintf(wdirname,sizeof(wdirname),"%s/%s.day",tmp,uinfo->filename)>=sizeof(wdirname)) {
643 debuga(_("user name too long for %s/%s.day\n"),tmp,uinfo->filename);
644 exit(EXIT_FAILURE);
645 }
646 if(access(wdirname, R_OK) != 0) {
647 return;
648 }
649 if(!Graphs || GraphFont[0]=='\0') {
650 unlink(wdirname);
651 return;
652 }
653
654 if((fp_in=fopen(wdirname,"r"))==NULL) {
655 debuga(_("(grepday) Cannot open log file %s\n"),wdirname);
656 exit(EXIT_FAILURE);
657 }
658
659 memset(datapoints,0,sizeof(datapoints));
660 while(fgets(buf,sizeof(buf),fp_in)!=NULL) {
661 fixendofline(buf);
662 getword_start(&gwarea,buf);
663 if (getword_atoll(&llday,&gwarea,'/')<0) {
664 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),wdirname);
665 exit(EXIT_FAILURE);
666 }
667 if(DateFormat[0]=='u') {
668 if (getword_atoll(&llday,&gwarea,'/')<0) {
669 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),wdirname);
670 exit(EXIT_FAILURE);
671 }
672 }
673 day=(int)llday;
674 if (day<1 || day>31) continue;
675 if (getword_skip(20,&gwarea,'\t')<0 || getword_skip(20,&gwarea,'\t')<0 || getword_atoll(&bytes,&gwarea,'\t')<0) {
676 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),wdirname);
677 exit(EXIT_FAILURE);
678 }
679 datapoints[day-1]+=bytes;
680 }
681 fclose(fp_in);
682 unlink(wdirname);
683
684 memset(&pdata,0,sizeof(pdata));
685 pdata.datapoints=datapoints;
686 pdata.npoints=31;
687 if(datetimeby==DATETIME_BYTE) {
688 pdata.ymin=20LL*1024LL;
689 pdata.ymax=5LL*1024LL*1024LL*1024LL;
690 pdata.ytype=PTG_LogBin;
691 pdata.YLabel=_("BYTES");
692 } else {
693 pdata.ymin=0;
694 pdata.ymax=86400000;
695 pdata.ytype=PTG_Time;
696 pdata.YLabel=_("ELAPSED TIME");
697 }
698 greport_plot(uinfo,&pdata);
699 #endif //HAVE_GD
700
701 return;
702 }
703
704 void greport_cleanup(void)
705 {
706 #ifdef HAVE_GD
707 gdFontCacheShutdown();
708
709 #ifdef USE_ICONV
710 if (localtoutf!=(iconv_t)-1)
711 iconv_close (localtoutf);
712 #endif
713 #endif //HAVE_GD
714 }