Logo Search packages:      
Sourcecode: netams version File versions  Download package

html.c

/*************************************************************************
***   Authentication, authorization, accounting + firewalling package
***   Copyright 1998-2002 Anton Vinokurov <anton@netams.com>
***   Copyright 2002-2008 NeTAMS Development Team
***   This code is GPL v3
***   For latest version and more info, visit this project web page
***   located at http://www.netams.com
***
*************************************************************************/
/* $Id: html.c,v 1.109 2009-08-01 09:23:55 anton Exp $ */

#include "netams.h"

static char mon_name[][12]={ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
//////////////////////////////////////////////////////////////////////////////////////////
typedef struct html_top_item {
      NetUnit *u;
      Policy *p;
      struct pstat s;
} html_top_item;
struct tm tm;
//////////////////////////////////////////////////////////////////////////////////////////
//this bad because refers to hidden variables *file and full_path[]
#define HTML_PUSHD(file, path)      { file=&path[strlen(path)]; sprintf(file, "/"); file++;}
#define HTML_POPD(file)       { file=prefix; }

void cShowBillingHtml(FILE *f, Service_Html *cfg);
void cShowBillingAccountsHtml(FILE *f, Service_Html *cfg, struct tm *tm);

FILE *sHOpenFile(FILE* f, const char *fullname);
int sHSafeMkdir(const char *temp);
void sHPrintHeader(FILE *f, const char *title, const char *back, const char *logopath=NULL);
void sPrintFooter(FILE *f, const char *back);
void sHPrintUnits(FILE *f, Service_Html *cfg);
void sHPrintUnitsRoot(FILE *f, Service_Html *cfg, NetUnit *p);
void sHPrintUnitsTree(FILE *f, Service_Html *cfg, NetUnit *p, u_char isadmintool=0);
void sHPrintUnitST(FILE *f, NetUnit *p, const char *unit_list);
void sHPrintTHeader(FILE *f);
void sHPrintTHeaderTopData(FILE *f, const char* period);
void sHPrintTHeaderTopItem(FILE *f, html_top_item *item);
void sHPrintTHeaderPreincluded(FILE *f);
void HtmlCalendarY(FILE *f, const char *path, char *filename, struct tm *tm, const char *yhref, const char *mhref);
void HtmlCalendarM(FILE *f, const char *path, char *filename, struct tm *tm, const char *href);
void HtmlCalendarD(FILE *f, const char *path, char *filename, struct tm *tm, const char *href);

void HtmlRedirect(const char *path, const char *href);
//////////////////////////////////////////////////////////////////////////////////////////
void sHtmlAction(Service_Html *cfg){
      if (!cfg->path) { aLog(D_INFO, "cannot create pages because no html dir is set!\n"); return; }

      NetUnit *u=NULL;
      FILE *f=NULL;

      struct stat sb;
      bzero(&sb, sizeof (struct stat));

      //=================================================================================
      u_char len=strlen(cfg->path);
      char path[512];         // better change then to dynamic allocation with len [len+256];
      // we have trick here
      // actually cfg->path is presetted - so we can store it permanently and work only via offset
      // pointed by *file
      strncpy(path, cfg->path, len);
      char *prefix=&path[len];      //prefix from cfg->path to actual filename
      char *filename;               //from here filename will be printed

      char tmp[256];

      // first, calculate current year, month, day and hour
      {
            time_t current=time(NULL);
            localtime_r(&current, &tm);
      }

      //create path
      snprintf(prefix, 255, "/%04d/%02d/%02d/%02d", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour);
      if (sHSafeMkdir(path)) return;
      HTML_PUSHD(filename, path);

      aDebug(DEBUG_HTML, "Creation main data in %s\n", path);

      //=================================================================================
      // if this is the end of hour, generate hourly report
      snprintf(filename, 255, "time.html");
      f=sHOpenFile(f, path); if (!f) return;
      snprintf(tmp, 255, Locale(LC_H_TRAFINFO), tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_hour, tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_hour+1);
      sHPrintHeader(f, tmp, "index.html");
      fprintf(f, "<div style=\"margin-left : 5%%; align: right;\">\n");
      sHPrintUnits(f, cfg);
      fprintf(f, "</div> \n");
      sPrintFooter(f, "index.html");
      //=================================================================================
      // create index file
      snprintf(filename, 255, "index.html");
      f=sHOpenFile(f, path); if (!f) return;
      sHPrintHeader(f, Locale(LC_H_RUNTIME), "../../../../index.html");

      fprintf(f, "<h3>%s %02d %s</h3>\n \
            <div style=\"margin-left : 5%%;\"> \n",
            Locale(LC_H_TIMEDERIVED), tm.tm_mday, mon_name[tm.tm_mon]);

      // year table
      HtmlCalendarY(f, path, filename, &tm, "../../../../%04d", "../../../../%04d/%02d/index.html");

      // month table
      HtmlCalendarM(f, path, filename, &tm, "../../%02d/index.html");

      // day table
      HtmlCalendarD(f, path, filename, &tm, "../%02d/time.html");

      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      fprintf(f, "<h3>%s</h3>\n \
            <div style=\"margin-left : 5%%;\"> \n", Locale(LC_H_OBJSTAT));

      netams_rwlock_rdlock(&Units->rwlock);
      if (cfg->cpages==CPAGES_ALL || cfg->cpages==CPAGES_GROUPS || cfg->cpages==CPAGES_GROUPLIST) {
            fprintf(f, "<b>%s:</b><br>\n", Locale(LC_H_GROUPS));
            ELIST_FOR_EACH(Units->groups, u) {
                  if (!u->name) continue;
                  int k=0;
                  if (cfg->cpages==CPAGES_GROUPLIST)
                        for (Html_grouplist_item *item=cfg->grouproot; item!=NULL; item=item->next)
                              if (item->groupid==u->id) k=1;

                  if ((cfg->cpages==CPAGES_GROUPLIST && k) || cfg->cpages!=CPAGES_GROUPLIST)
                        fprintf(f, "<a href=\"../../../../clients/%s/index.html\">%s</a>\n",
                              u->name, u->name);
            }
      }

      if (cfg->cpages==CPAGES_ALL || cfg->cpages==CPAGES_GROUPLIST) {
            fprintf(f, "<br><b>%s:</b><br>\n", Locale(LC_H_UNITS));
            for (u=(NetUnit*)Units->root; u!=NULL; u=(NetUnit*)u->next) {
                  //that's ok because groups are in the beginning
                  if (u->type==NETUNIT_GROUP || !u->name) continue;
                  int k=0;
                  if (cfg->cpages==CPAGES_GROUPLIST) {
                        NetUnit_group *gr;
                        ELIST_FOR_EACH(u->parents, gr) {
                              for (Html_grouplist_item *item=cfg->grouproot; item!=NULL; item=item->next)
                                    if (item->groupid==gr->id) k=1;
                        }
                  }

                  if ((cfg->cpages==CPAGES_GROUPLIST && k) || cfg->cpages!=CPAGES_GROUPLIST)
                        fprintf(f, "<a href=\"../../../../clients/%s/index.html\">%s</a>\n",
                              u->name, u->name);
            }
      }
      netams_rwlock_unlock(&Units->rwlock);
      fprintf(f, "<br><br></div>\n");

      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      if (cfg->display_health){
            fprintf(f, "<h3>%s</h3>\n<div style=\"margin-left : 5%%; \">\n", Locale(LC_H_SYSTAT));
            if (aShowSystemHealth(NULL, 1)) {
                  aCommand("show health", MODE_EXEC, f);
                  fprintf(f, "<br><font color=red><b>%s</b></font>", Locale(LC_H_SYSTAT_WRONG));
            }
            fprintf(f, "</div>\n");
      }
      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      if (cfg->display_top){
            fprintf(f, "<h3>%s</h3>\n<div style=\"margin-left : 5%%; \">\n", Locale(LC_H_TOPUSERS));
            fprintf(f, "%u %s \n</div>\n", cfg->display_top, Locale(LC_H_TOPUSERS_STR));
      }

      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      fprintf(f, "<h3>%s</h3>\n \
            <div style=\"margin-left : 5%%;\"> \n\
            %s <a href=\"software-version.html\">show version</a><br> \n",
            Locale(LC_H_SERVICES), Locale(LC_H_SERV_OUTPUTOF));

      if(Quota)
            fprintf(f, "%s <a href=\"software-quota.html\">%s</a><br> \n",
                  Locale(LC_H_SERV_STATE), Locale(LC_H_SERV_QUOTA));
      if(Login)
            fprintf(f, "%s <a href=\"software-login.html\">%s</a><br> \n",
                  Locale(LC_H_SERV_STATE), Locale(LC_H_SERV_LOGIN));
      fprintf(f, "%s <a href=\"software-config.html\">show config</a><br>",
            Locale(LC_H_SERV_OUTPUTOF));
#ifdef HAVE_BILLING
      if(Billing)
            fprintf(f, "%s <a href=\"software-billing.html\">%s</a><br>\n",
                  Locale(LC_H_SERV_STATE), Locale(LC_H_SERV_BILLING));
#endif
      fprintf(f, "</div>\n");
      sPrintFooter(f, NULL);
      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      // create SW version
      snprintf(filename, 255, "software-version.html");
      f=sHOpenFile(f, path); if (!f) return;
      sHPrintHeader(f, Locale(LC_H_SW_VERSION), "index.html");
      fprintf(f, "<pre>\n");
      aCommand("show version", MODE_EXEC, f);
      fprintf(f, "</pre>\n");
      sPrintFooter(f, "index.html");
      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      // create Quota state
      if(Quota) {
            snprintf(filename, 255, "software-quota.html");
            f=sHOpenFile(f, path); if (!f) return;
            snprintf(tmp, 255, "%s %s", Locale(LC_H_SERV_STATE), Locale(LC_H_SERV_QUOTA));
            sHPrintHeader(f, tmp, "index.html");
            fprintf(f, "<pre>\n");
            aCommand("show quota", MODE_EXEC, f);
            fprintf(f, "</pre>\n");
            sPrintFooter(f, "index.html");
      }
      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      // create Login state
      if(Login) {
            snprintf(filename, 255, "software-login.html");
            f=sHOpenFile(f, path); if (!f) return;
            snprintf(tmp, 255, "%s %s", Locale(LC_H_SERV_STATE), Locale(LC_H_SERV_LOGIN));
            sHPrintHeader(f, tmp, "index.html");
            fprintf(f, "<pre>\n");
            aCommand("show login", MODE_EXEC, f);
            fprintf(f, "</pre>\n");
            sPrintFooter(f, "index.html");
      }
      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      // create SW log
      snprintf(filename, 255, "software-config.html");
      f=sHOpenFile(f, path); if (!f) return;
      sHPrintHeader(f, Locale(LC_H_RUNNING_CONFIG), "index.html");
      fprintf(f, "<pre>\n");
      aCommand("show config unsecure", MODE_EXEC, f);
      fprintf(f, "</pre>\n");
      sPrintFooter(f, "index.html");
      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      // create TOP pages
      if (cfg->display_top){
            html_top_item* table_h = (html_top_item*)aMalloc(cfg->display_top*(sizeof (struct html_top_item)));
            html_top_item* table_d = (html_top_item*)aMalloc(cfg->display_top*(sizeof (struct html_top_item)));
            html_top_item* table_w = (html_top_item*)aMalloc(cfg->display_top*(sizeof (struct html_top_item)));
            html_top_item* table_m = (html_top_item*)aMalloc(cfg->display_top*(sizeof (struct html_top_item)));

            // find top units
            NetUnit *u; policy_data *cpd;
            struct pstat s_h; Policy *p_h;
            struct pstat s_d; Policy *p_d;
            struct pstat s_w; Policy *p_w;
            struct pstat s_m; Policy *p_m;
            html_top_item *item;

            netams_rwlock_rdlock(&Units->rwlock);
            for (u=(NetUnit*)Units->root; u!=NULL; u=(NetUnit*)u->next) {
                  if (u->name == NULL || u->ap==NULL
                  || (u->type!=NETUNIT_HOST && u->type!=NETUNIT_USER))
                        continue;

                  // find sum and policy where counters are MAX
                  bzero(&s_h, sizeof (struct pstat)); p_h=NULL;
                  bzero(&s_d, sizeof (struct pstat)); p_d=NULL;
                  bzero(&s_w, sizeof (struct pstat)); p_w=NULL;
                  bzero(&s_m, sizeof (struct pstat)); p_m=NULL;
                  for (cpd=u->ap->root; cpd!=NULL; cpd=cpd->next) {
                        if (cpd->policy->hidden) continue;
                        if (cpd->h.in+cpd->h.out >= s_h.in+s_h.out) {
                              memcpy(&s_h, &cpd->h, sizeof (struct pstat));
                              p_h=cpd->policy;
                        }
                        if (cpd->d.in+cpd->d.out >= s_d.in+s_d.out) {
                              memcpy(&s_d, &cpd->d, sizeof (struct pstat));
                              p_d=cpd->policy;
                        }
                        if (cpd->w.in+cpd->w.out >= s_w.in+s_w.out) {
                              memcpy(&s_w, &cpd->w, sizeof (struct pstat));
                              p_w=cpd->policy;
                        }
                        if (cpd->m.in+cpd->m.out >= s_m.in+s_m.out) {
                              memcpy(&s_m, &cpd->m, sizeof (struct pstat));
                              p_m=cpd->policy;
                        }
                  }
                  // put the data somewhere onto the table
                  for (int i=0; i<cfg->display_top; i++) {
                        item=&table_h[i];
                        if (item->s.in+item->s.out<=s_h.in+s_h.out) {
                              memmove(&table_h[i+1], &table_h[i], sizeof (struct html_top_item)*(cfg->display_top-i-1));
                              item->u=u;
                              item->p=p_h;
                              memcpy(&item->s, &s_h, sizeof (struct pstat));
                              break;
                        }
                  }
                  for (int i=0; i<cfg->display_top; i++) {
                        item=&table_d[i];
                        if (item->s.in+item->s.out<=s_d.in+s_d.out) {
                              memmove(&table_d[i+1], &table_d[i], sizeof (struct html_top_item)*(cfg->display_top-i-1));
                              item->u=u;
                              item->p=p_d;
                              memcpy(&item->s, &s_d, sizeof (struct pstat));
                              break;
                        }
                  }
                  for (int i=0; i<cfg->display_top; i++) {
                        item=&table_w[i];
                        if (item->s.in+item->s.out<=s_w.in+s_w.out) {
                              memmove(&table_w[i+1], &table_w[i], sizeof (struct html_top_item)*(cfg->display_top-i-1));
                              item->u=u;
                              item->p=p_w;
                              memcpy(&item->s, &s_w, sizeof (struct pstat));
                              break;
                        }
                  }
                  for (int i=0; i<cfg->display_top; i++) {
                        item=&table_m[i];
                        if (item->s.in+item->s.out<=s_m.in+s_m.out) {
                              memmove(&table_m[i+1], &table_m[i], sizeof (struct html_top_item)*(cfg->display_top-i-1));
                              item->u=u;
                              item->p=p_m;
                              memcpy(&item->s, &s_m, sizeof (struct pstat));
                              break;
                        }
                  }
            }
            netams_rwlock_unlock(&Units->rwlock);
            ///////////////////////////////////////////////////////////////////////////////
            // create top pages
            snprintf(filename, 255, "top.html");
            f=sHOpenFile(f, path); if (!f) return;
            snprintf(tmp, 255, "%s %s %s", Locale(LC_H_TOPUSERS), Locale(LC_H_CURRENT), Locale(LC_H_CHOUR));
            sHPrintHeader(f, tmp, "index.html");
            sHPrintTHeaderTopData(f, Locale(LC_H_CHOUR));
            for (u_char i=0; i<cfg->display_top; i++) {
                  item=&table_h[i];
                  sHPrintTHeaderTopItem(f, item);
            }
            fprintf(f, "</table><br>\n");
            sPrintFooter(f, "index.html");
            ///////////////////////////////////////////////////////////////////////////////
            snprintf(filename, 255, "../top.html");
            f=sHOpenFile(f, path); if (!f) return;
            snprintf(tmp, 255, "%s %s %s", Locale(LC_H_TOPUSERS), Locale(LC_H_CURRENT), Locale(LC_H_CDAY));
            sHPrintHeader(f, tmp, "index.html", "../../../..");
            sHPrintTHeaderTopData(f, Locale(LC_H_CDAY));
            for (u_char i=0; i<cfg->display_top; i++) {
                  item=&table_d[i];
                  sHPrintTHeaderTopItem(f, item);
            }
            fprintf(f, "</table><br>\n");
            sPrintFooter(f, "index.html");
            ///////////////////////////////////////////////////////////////////////////////
            snprintf(filename, 255, "../top-week.html");
            f=sHOpenFile(f, path); if (!f) return;
            snprintf(tmp, 255, "%s %s %s", Locale(LC_H_TOPUSERS), Locale(LC_H_CURRENT2), Locale(LC_H_CWEEK2));
            sHPrintHeader(f, tmp, "index.html", "../../../..");
            sHPrintTHeaderTopData(f, Locale(LC_H_CWEEK));
            for (u_char i=0; i<cfg->display_top; i++) {
                  item=&table_w[i];
                  sHPrintTHeaderTopItem(f, item);
            }
            fprintf(f, "</table><br>\n");
            sPrintFooter(f, "index.html");
            ///////////////////////////////////////////////////////////////////////////////
            snprintf(filename, 255, "../../top.html");
            f=sHOpenFile(f, path); if (!f) return;
            snprintf(tmp, 255, "%s %s %s", Locale(LC_H_TOPUSERS), Locale(LC_H_CURRENT), Locale(LC_H_CMONTH));
            sHPrintHeader(f, tmp, "index.html", "../../..");
            sHPrintTHeaderTopData(f, Locale(LC_H_CMONTH));
            for (u_char i=0; i<cfg->display_top; i++) {
                  item=&table_m[i];
                  sHPrintTHeaderTopItem(f, item);
            }
            fprintf(f, "</table><br>\n");
            sPrintFooter(f, "index.html");
            ///////////////////////////////////////////////////////////////////////////////
            aFree(table_h); aFree(table_d); aFree(table_w); aFree(table_m);
      }

      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#ifdef HAVE_BILLING
      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      // create billing log
      if(Billing) {
            snprintf(filename, 255, "software-billing.html");
            f=sHOpenFile(f, path); if (!f) return;
            snprintf(tmp, 255, "%s %s", Locale(LC_H_SERV_STATE), Locale(LC_H_SERV_BILLING));
            sHPrintHeader(f, tmp, "index.html");
            cShowBillingHtml(f, cfg);
            sPrintFooter(f, "index.html");
            if (cfg->apages==APAGES_ALL)
                  cShowBillingAccountsHtml(f, cfg, &tm);
      }
#endif
      HTML_POPD(filename);

      //=================================================================================
      // generate month index page
      snprintf(prefix, 255, "/%04d/%02d", tm.tm_year+1900, tm.tm_mon+1);
      HTML_PUSHD(filename, path);

      snprintf(filename, 255, "index.html");
      f=sHOpenFile(f, path); if (!f) return;
      sHPrintHeader(f, Locale(LC_H_RUNTIME), "../../index.html", "../../..");

      fprintf(f, "<h3>%s: %s</h3>\n <div style=\"margin-left : 5%%;\"> \n",
            Locale(LC_H_INDEX_MONTH), mon_name[tm.tm_mon]);

      // year table
      HtmlCalendarY(f, path, filename, &tm, "../../%04d", "../../%04d/%02d/index.html");

      // month table
      filename[0]=0;
      HtmlCalendarM(f, path, filename, &tm, "%02d/index.html");

      fprintf(f, "<br></div><br>\n");
      sPrintFooter(f, "../../index.html");
      ///////////////////////////////////////////////////////////////////////////////
      //change file and cleanup
      HTML_POPD(filename);

      //=================================================================================
      // create a master index file at path root, pointing to the current file
      snprintf(filename, 255, "/index.html");
      snprintf(tmp, 255, "%04d/%02d/%02d/%02d/index.html", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour);
      HtmlRedirect(path, tmp);

      //=================================================================================
      // generate day index redirect page
      snprintf(filename, 255, "/%04d/%02d/%02d/index.html", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
      snprintf(tmp, 255, "%02d/index.html", tm.tm_hour);
      HtmlRedirect(path, tmp);
      //=================================================================================

      if (cfg->cpages == CPAGES_NONE) goto ACCESS; //skip clients

      //=================================================================================
      // generate per-client pages
      aDebug(DEBUG_HTML, "Generate clients pages\n");

      netams_rwlock_rdlock(&Units->rwlock);
      for (u=(NetUnit*)Units->root; u!=NULL; u=(NetUnit*)u->next) {
            if (u->name == NULL) continue;

            if (!(cfg->cpages==CPAGES_ALL || cfg->cpages==CPAGES_GROUPLIST ||
                  (cfg->cpages==CPAGES_GROUPS && u->type==NETUNIT_GROUP))) continue;       // CPAGES_CHECK

            if (cfg->cpages==CPAGES_GROUPLIST) {
                  if (u->type==NETUNIT_GROUP) {
                        int k=0;
                        for (Html_grouplist_item *item=cfg->grouproot; item!=NULL; item=item->next)
                              if (item->groupid==u->id) k=1;

                        if (k==0) continue; // skip this group as it is not belongs to group listed in GROUPLIST
                  }
                  else
                  {
                        NetUnit_group *gr;
                        int k=0;
                        ELIST_FOR_EACH(u->parents, gr) {
                              for (Html_grouplist_item *item=cfg->grouproot; item!=NULL; item=item->next)
                                    if (item->groupid==gr->id) k=1;
                        }
                        if (k==0) continue; // skip this unit as it is not belongs to group listed in GROUPLIST
                  }
            }

            ///////////////////////////////////////////////////////////////////////////////
            //create path
            snprintf(prefix, 255, "/clients/%s/%04d/%02d", u->name, tm.tm_year+1900, tm.tm_mon+1);
            if (sHSafeMkdir(path)) return;
            HTML_PUSHD(filename, path);
            aDebug(DEBUG_HTML, "Creation client %s pages in %s\n", u->name, path);

            ///////////////////////////////////////////////////////////////////////////////
            snprintf(filename, 255, "index-day-%02d.html", tm.tm_mday);
            f=sHOpenFile(f, path); if (!f) return;
            sHPrintHeader(f, Locale(LC_H_TRAFINFO_SELECTED), "javascript:history.go(-1)");

            switch (u->type) {
            case NETUNIT_HOST: {
                  NetUnit_host *h;
                  h = (NetUnit_host*)u;
                  inet_ntop(AF_INET, &(h->ip), tmp, 32);
                  fprintf(f, "HOST: <b>%s</b><br>OID: <b>%06X</b><br> IP: <b>%-12s</b><br>\n",
                        h->name, h->id, tmp);
                  break;
            }
            case NETUNIT_USER: {
                  NetUnit_user *h;
                  h = (NetUnit_user*)u;
                  inet_ntop(AF_INET, &(h->ip), tmp, 32);
                  fprintf(f, "USER: <b>%s</b><br>OID: <b>%06X</b><br> IP: <b>%-12s</b><br>\n",
                        h->name, h->id, tmp);
                  break;
            }
            case NETUNIT_CLUSTER: {
                  NetUnit_cluster *h;
                  NetUnit_net *t;
                  h = (NetUnit_cluster*)u;
                  fprintf(f, "CLUSTER: <b>%s</b><br>OID: <b>%06X</b><br>IPs:<b>\n",
                        h->name, h->id);
                  for (t=h->root; t!=NULL; t=t->next) {
                        inet_ntop(AF_INET, &(t->ip), tmp, 32);
                        fprintf(f, " %s/%u", tmp, MASK2MLEN(t->mask));
                  }
                  fprintf(f, "</b><br>\n");
                  break;
            }
            case NETUNIT_GROUP: {
                  NetUnit *t;
                  NetUnit_group *h;
                  h = (NetUnit_group*)u;
                  fprintf(f, "GROUP: <b>%s</b><br>OID: <b>%06X</b><br>Subs:<b>",
                        h->name, h->id);
                  ELIST_FOR_EACH(h->childrens, t){
                        if (!t->name) continue;
                        if (cfg->cpages==CPAGES_ALL || cfg->cpages==CPAGES_GROUPLIST)
                              fprintf(f, " <a href=\"../../../%s/index.html\">%s</a>",
                                    t->name, t->name);
                        else
                              fprintf(f, " %s", t->name);
                  }
                  fprintf(f, "</b><br>\n");
                  break;
            }
            case NETUNIT_NET: {
                  NetUnit_net *h;
                  h = (NetUnit_net*)u;
                  inet_ntop(AF_INET, &(h->ip), tmp, 32);
                  fprintf(f, "NET: <b>%s</b><br>OID: <b>%06X</b><br>NETWORK: <b>%s</b>\n",
                        h->name, h->id, tmp);
                  inet_ntop(AF_INET, &(h->mask), tmp, 32);
                  fprintf(f, " NET_MASK: <b>%s</b><br>\n", tmp);
                  break;
            }
            default:
                  fprintf(f, "&lt;UNKNOWN&gt;<br> OID: <b>%06X</b>\n", u->id);
                  break;
            }

            if(u->parents) {
                  NetUnit_group *gr;
                  fprintf(f, "PARENTS:");
                  ELIST_FOR_EACH(u->parents, gr) {
                        fprintf(f, " <b><a href=\"../../../%s/index.html\">%10s</a></b>",
                              gr->name,gr->name);
                  }
                  fprintf(f, "<br>\n");
            }
            if (u->description)
                  fprintf(f, "DESCRIPTION: <b>%s</b><br>\n", u->description);

            //++++++++++++++++++++++++++++++++++++++++++
            // year/month table (client)
            fprintf(f, "<br><b>%s:</b><br>", Locale(LC_H_CALENDAR));
            HtmlCalendarY(f, path, filename, &tm, "../../%04d", "../../%04d/%02d/index.html");

            // month table (client)
            HtmlCalendarM(f, path, filename, &tm, "index-day-%02d.html");
            //+++++++++++++++++++++++++++++++++++++++++

            fprintf(f, "<h3>%s %s, %s</h3>\n <div style=\"margin-left : 5%%;\"> \n",
                  Locale(LC_H_TRAFINFO_FOR), u->name, Locale(LC_H_TRAFINFO_ACTUAL));

            if (u->type!=NETUNIT_GROUP)
                  sHPrintTHeader(f);
            sHPrintUnitsTree(f, cfg, u);
            if (u->type!=NETUNIT_GROUP)
                  fprintf(f, "</table><br>\n");

            fprintf(f, "</div><br>");
            sPrintFooter(f, "javascript:history.go(-1)");
            ///////////////////////////////////////////////////////////////////////////////
            // generate month index page
            snprintf(filename, 255, "index.html");
            f=sHOpenFile(f, path); if (!f) return;
            sHPrintHeader(f, Locale(LC_H_RUNTIME), "../../index.html");
            fprintf(f, "<h3>%s: %s</h3>\n <div style=\"margin-left : 5%%;\"> \n",
                  Locale(LC_H_INDEX_MONTH), mon_name[tm.tm_mon]);

            // month table
            HtmlCalendarM(f, path, filename, &tm, "index-day-%02d.html");

            fprintf(f, "<br></div><br>\n");
            sPrintFooter(f, "../../index.html");
            ///////////////////////////////////////////////////////////////////////////////
            //cleanup and  restore *file
            HTML_POPD(filename);

            // create a master index file at client root, pointing to the current file
                snprintf(filename, 255, "/clients/%s/index.html", u->name);
                snprintf(tmp, 255, "%04d/%02d/index-day-%02d.html", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
                HtmlRedirect(path, tmp);

            if (cfg->is_htaccess && u->flags&NETUNIT_CHANGED) {
                  if (u->password) {
                        snprintf(filename, 255, "/clients/%s/.htaccess", u->name);
                        f=sHOpenFile(f, path); if (!f) return;
                        fprintf(f, "AuthName \"NeTAMS User Login\"\n Require user");
                        Users->listUsersHtml(f);
                        if (cfg->is_htaccess==2)
                              fprintf(f, " %s\n<FilesMatch \"\\.(gif|jpe?g|png)$\">\nRequire valid-user\nSatisfy Any\n</FilesMatch>\nAuthType Basic\n\n", u->name);
                        else if (cfg->is_htaccess==1)
                              fprintf(f, " %s\n<FilesMatch \"\\.(gif|jpe?g|png)$\">\nRequire valid-user\nSatisfy Any\n</FilesMatch>\nAuthType Basic\nAuthUserFile %s/.htpasswd\n\n", u->name, cfg->path);
                        u->flags&=~NETUNIT_CHANGED;
                  }
            }
      } // 'for' loop, all clients
      netams_rwlock_unlock(&Units->rwlock);

ACCESS:
      //=================================================================================
      // if htaccess==1 AND UserList changed flag is set, generate new .htaccess and .htpasswd
      if (cfg->is_htaccess) {
            if (Users->changed_user) {
                  snprintf(filename, 255, "/.htaccess");
                  f=sHOpenFile(f, path); if (!f) return;
                  fprintf(f, "AuthName \"NeTAMS Administrators Only\"\n Require user");
                  Users->listUsersHtml(f);
                  if (cfg->is_htaccess==2)
                        fprintf(f, "\n<FilesMatch \"\\.(gif|jpe?g|png)$\">\nRequire valid-user\nSatisfy Any\n</FilesMatch>\nAuthType Basic\n\n");
                  else if (cfg->is_htaccess==1)
                        fprintf(f, "\n<FilesMatch \"\\.(gif|jpe?g|png)$\">\nRequire valid-user\nSatisfy Any\n</FilesMatch>\nAuthType Basic\nAuthUserFile %s/.htpasswd\n\n", cfg->path);
                  Users->changed_user=0;
            }

            if (cfg->is_htaccess==1 && Users->changed_pw) {
                  snprintf(filename, 255, "/.htpasswd");
                  f=sHOpenFile(f, path); if (!f) return;
                  Users->listPasswordsHtml(f);
                  Units->listPasswordsHtml(f);
            }
      }
      //=================================================================================
      //clear connection
      if(f) fclose(f);
}
//////////////////////////////////////////////////////////////////////////////////////////
FILE* sHOpenFile(FILE *file, const char *filename){
      int f;

      if(file) fclose(file);

      f=open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644);
      if(f==-1) {
            aLog(D_ERR, "Can't create file %s : %s\n", filename, strerror(errno));
            return NULL;
      }
      aDebug(DEBUG_HTML, "Creating file %s\n", filename);
      return fdopen(f, "w");
}
//////////////////////////////////////////////////////////////////////////////////////////
int sHSafeMkdir(const char *temp){  // this equal to  mkdir -p
      struct stat sb;
      bzero(&sb, sizeof (struct stat));

      int i=stat(temp, &sb);
      if (!(sb.st_mode & S_IFDIR) || i) {
            i=mkdir(temp, 0711);
            if (i) {
                  i=(strrchr(temp, '/')-temp);
                  if(i>0) {
                        char *prefix=(char*)aMalloc(i+1);
                        strncpy(prefix, temp, i);     //find prefix

                        i=sHSafeMkdir(prefix);        //recurse
                        aFree(prefix);

                        if(i) return -1;        //if error on previous level no need to continue

                        i=mkdir(temp, 0711);          //there is no error, retry to create
                  } else  i=-1;     //ensure this is error

                  if(i) {
                        aLog(D_INFO, "failed to create %s: %s \n", temp, strerror(errno));
                        return -1;
                  }
            }
            aDebug(DEBUG_HTML, "make directory %s\n", temp);
      } else if (!(sb.st_mode & S_IFDIR)) {
            aLog(D_INFO, "failed to create %s, file already exist and not directory\n", temp);
            return -1;
      }
      return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////
void sHPrintHeader(FILE *f, const char *title, const char *back, const char *logopath){

      fprintf(f, "<html><head><title>NeTAMS - %s</title><META http-equiv=\"Pragma\" content=\"no-cache\"><META http-equiv=\"Expires\" content=\"-1\"><META http-equiv=\"Cache-Control\" content=\"no-cache\"><META http-equiv=\"Content-type\" content=\"text/html; charset=%s\">\n</HEAD> \n\
            <body bgcolor=white marginheight=0 leftmargin=0 topmargin=0 marginwidth=0> \n\
            <table width=100%% align=left border=0 cellpadding=5 cellspacing=0> \n\
            <tr bgcolor='white' align=left><td width=376> \n\
            <A href=\"http://www.netams.com/index.html\"> \n\
            <img src=\"%s/images/logo_sm.jpg\" width=376 height=60 border=0></a></td> \n\
            <td valign=middle align=left width=80%%> %s     <a href=\"http://www.netams.com/index.html\"><b>NeTAMS</b></a><br> \
            <b>%s: </b>", title, language_charset_str[lang], logopath?logopath:"../../../../..", Locale(LC_H_REPORT), Locale(LC_H_SW_VERSION));
      fprintf(f, "%s<br>\n", SHOW_VERSION);

      char buff[32];
      fprintf(f, "<b>%s:</b> %s<br> </td></tr> <tr bgcolor='#ccccff'><td colspan=2> \n\
            <h3>%s", Locale(LC_H_CR_TIME), timeU2T(time(NULL), buff), title);
      if (back)
            fprintf(f, "<font face=monospace size=-1><b> [<a href=\"%s\"> <- %s</a> ]</b></font>",
                  back, Locale(LC_H_BACK));
      fprintf(f, "</h3></td></tr><tr><td colspan=2>\n");
}
//////////////////////////////////////////////////////////////////////////////////////////
void sPrintFooter(FILE *f, const char *back){
      fprintf(f, "</td></tr>\n");
      if (back)
            fprintf(f, "<tr bgcolor='#ccccff'><td colspan=2><font face=monospace size=-1><b>[<a href=\"%s\"> <- %s</a> ]</b></font></td></tr>", back, Locale(LC_H_BACK));
      fprintf(f, "</table>\n</body></html> \n");
}
//////////////////////////////////////////////////////////////////////////////////////////
void sHPrintUnits(FILE *f, Service_Html *cfg){
      NetUnit *u;

      netams_rwlock_rdlock(&Units->rwlock);
      //print groups with childs
      ELIST_FOR_EACH(Units->groups, u) {
            if(!u->parents) {
                  sHPrintUnitsTree(f, cfg, u, 1);
            }
      }

      sHPrintTHeader(f);

      for (u=(NetUnit*)Units->root; u!=NULL; u=(NetUnit*)u->next) {
            if(u->type!=NETUNIT_GROUP && !u->parents) {
                  sHPrintUnitsTree(f, cfg, u, 1);
            }
      }
      netams_rwlock_unlock(&Units->rwlock);

      fprintf(f, "</table><br>\n");
}
//////////////////////////////////////////////////////////////////////////////////////////
void sHPrintUnitsRoot(FILE *f, Service_Html *cfg, NetUnit *p){
      NetUnit *u;
      NetUnit_group *gr = (NetUnit_group*)p;

      if(!gr->childrens) return;

      ELIST_FOR_EACH(gr->childrens, u){
            if(u->type==NETUNIT_GROUP)
                  sHPrintUnitsTree(f, cfg, u, 1);
      }

      sHPrintTHeader(f);

      ELIST_FOR_EACH(gr->childrens, u){
            if(u->type!=NETUNIT_GROUP) {
                  sHPrintUnitsTree(f, cfg, u, 1);
            }
      }
      fprintf(f, "</table><br>\n");
}
//////////////////////////////////////////////////////////////////////////////////////////
void sHPrintUnitsTree(FILE *f, Service_Html *cfg, NetUnit *u, u_char isadmintool){
      char buffer[32];
      unsigned is_zero_counters=1;
      policy_data *cpd;
      char tmp[2048];

      *tmp=0;
      if (u->ap) {
            netams_rwlock_rdlock(&u->ap->rwlock);
            for (cpd=u->ap->root; cpd!=NULL; cpd=cpd->next) {
                if (cpd->policy->hidden) continue;
                if (cpd->h.in!=0 || cpd->h.out!=0 ||
                  cpd->d.in!=0 || cpd->d.out!=0 ||
                  cpd->w.in!=0 || cpd->w.out!=0 ||
                  cpd->m.in!=0 || cpd->m.out!=0)      is_zero_counters=0;
                if (cfg && cfg->is_graphs)
                  sprintf(tmp+strlen(tmp), "%06X,", cpd->policy->id);
            }
            netams_rwlock_unlock(&u->ap->rwlock);
      }

      if(is_zero_counters) return;  // do not show empty units

      if (u->type==NETUNIT_GROUP) {
            sHPrintTHeader(f);
            fprintf(f, "<tr bgcolor='#000000'><td colspan=11 height=2> </td></tr><tr bgcolor='#ffffcc'><td colspan=11>");
            if (!is_zero_counters && *tmp) {
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%06X&policy=%s&year=%u&month=%u&day=%u\">D</a>", u->id, tmp, tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%06X&policy=%s&year=%u&week=d2w-%u-%u-%u\">W</a>", u->id, tmp, tm.tm_year+1900, tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%06X&policy=%s&year=%u&month=%u\">M</a>", u->id, tmp, tm.tm_year+1900, tm.tm_mon+1);
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%06X&policy=%s&year=%u\">Y</a>", u->id, tmp, tm.tm_year+1900);
                if (isadmintool) fprintf(f, "<A href=\"../../../../../cgi-bin/admin/graph.cgi?action=form_view&urls=@oid=%06X@policy=%s@year=%u@month=%u@day=%u@inout=both\">", u->id, tmp, tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday );
                fprintf(f, "<img src=\"../../../../../images/rrdgraph-logo.gif\" width=20 height=20 border=1 align=absmiddle>");
                if (isadmintool) fprintf(f, "</a>" );
                fprintf(f, "&nbsp;&nbsp;");

                *tmp=0;
                NetUnit_group *gr = (NetUnit_group*)u;
                NetUnit *ch;
                ELIST_FOR_EACH(gr->childrens, ch){
                        sprintf(tmp+strlen(tmp), "%06X,", ch->id);
                }
            } else
                *tmp=0;

            fprintf(f, "GROUP: <b>%s</b> <font size=-1>oid %06X</font></td></tr>\n", u->name?u->name:"", u->id);
            sHPrintUnitST(f, u, *tmp?tmp:NULL);
            fprintf(f, "<tr bgcolor='#ccffcc'><td colspan=11 align=right>\n");

            sHPrintUnitsRoot(f, cfg, u);

            fprintf(f, "</td></tr>\n");
            fprintf(f, "</table><br>\n");
    } else {
            fprintf(f, "<tr bgcolor='#ffffcc'><td colspan=11>");
            if (isadmintool) fprintf(f, "<A href=\"../../../../../cgi-bin/admintool.cgi?oid=%06X\"><img src=\"../../../../../images/admintool-logo.gif\" width=20 height=20 border=1 align=absmiddle></a> ", u->id);
            if (!is_zero_counters && *tmp) {
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%06X&policy=%s&year=%u&month=%u&day=%u\">D</a>", u->id, tmp, tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%06X&policy=%s&year=%u&week=d2w-%u-%u-%u\">W</a>", u->id, tmp, tm.tm_year+1900, tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%06X&policy=%s&year=%u&month=%u\">M</a>", u->id, tmp, tm.tm_year+1900, tm.tm_mon+1);
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%06X&policy=%s&year=%u\">Y</a>", u->id, tmp, tm.tm_year+1900);
                if (isadmintool) fprintf(f, "<A href=\"../../../../../cgi-bin/admin/graph.cgi?action=form_view&urls=@oid=%06X@policy=%s@year=%u@month=%u@day=%u@inout=both\">", u->id, tmp, tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday );
                fprintf(f, "<img src=\"../../../../../images/rrdgraph-logo.gif\" width=20 height=20 border=1 align=absmiddle>");
                if (isadmintool) fprintf(f, "</a>" );
                fprintf(f, "&nbsp;&nbsp;");
            }

            if (u->type==NETUNIT_HOST) fprintf(f, "HOST");
            else if (u->type==NETUNIT_USER) fprintf(f, "USER");
            else if (u->type==NETUNIT_NET) fprintf(f, "NET");
            else fprintf(f, "CLUSTER");
            fprintf(f, " <b>%s</b> <font size=-1>oid %06X</font>", u->name?u->name:"", u->id);

            if (u->type==NETUNIT_HOST)
                  fprintf(f, " IP: <i>%-12s</i>", inet_ntop(AF_INET, &(((NetUnit_host*)u)->ip), buffer, 32));
            else if (u->type==NETUNIT_USER)
                  fprintf(f, " IP: <i>%-12s</i>", inet_ntop(AF_INET, &(((NetUnit_user*)u)->ip), buffer, 32));
            else if (u->type==NETUNIT_NET) {
                  fprintf(f, " IP: <i>%-12s</i>", inet_ntop(AF_INET, &(((NetUnit_net*)u)->ip), buffer, 32));
                  fprintf(f, " MASK: <i>%-12s</i>", inet_ntop(AF_INET, &(((NetUnit_net*)u)->mask), buffer, 32));
            }
            if (isadmintool && cfg && u->ap && cfg->servlet_url) {
                  policy_data *cpd;
                  char *p=NULL;
                  time_t now=time(NULL);

                  netams_rwlock_rdlock(&u->ap->rwlock);
                  for (cpd=u->ap->root; cpd!=NULL; cpd=cpd->next) {
                        if (cpd->policy->hidden) continue;
                        print_to_string(&p, "%d:", cpd->policy->id);
                  }
                  netams_rwlock_unlock(&u->ap->rwlock);

                  if (p) fprintf(f, "&nbsp;<A href=\"%s/NetamsView/netams?action=table&unit_oid=%d&policies_oids=%s&time_from=%ld000&time_to=%ld000&timespan=M\"><img src=\"../../../../../images/showtable-logo.gif\" width=20 height=20 border=1 align=absmiddle></a>", cfg->servlet_url, u->id, p, now, now);
                  aFree(p);
            }

            if (u->description) fprintf(f, "&nbsp;&nbsp;&nbsp;<font color=navy>%s</font>", u->description);

            if (is_zero_counters) fprintf(f, "&nbsp;&nbsp;&nbsp;<font color=navy>(%s)</font>", Locale(LC_H_ALL_ZERO));
            fprintf(f, "</td></tr>\n\n");
            if (!is_zero_counters) sHPrintUnitST(f, u, NULL);
      }
}
//////////////////////////////////////////////////////////////////////////////////////////
void sHPrintUnitST(FILE *f, NetUnit *u, const char *unit_list){
      if(!u->ap) return; //nothing to do
      policy_data *cpd;
      static char b2qt[8][32];

      netams_rwlock_rdlock(&u->ap->rwlock);
      for (cpd=u->ap->root; cpd!=NULL; cpd=cpd->next) {
            if (cpd->policy->hidden) continue;
            fprintf(f, "<tr align=right>");
            if (unit_list) {
                fprintf(f, "<td align=left valign=middle bgcolor='#ffffaa'>");
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%s&policy=%06X&year=%u&month=%u&day=%u&oids=unit\">D</a>", unit_list, cpd->policy->id, tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%s&policy=%06X&year=%u&week=d2w-%u-%u-%u&oids=unit\">W</a>", unit_list, cpd->policy->id, tm.tm_year+1900, tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%s&policy=%06X&year=%u&month=%u&oids=unit\">M</a>", unit_list, cpd->policy->id, tm.tm_year+1900, tm.tm_mon+1);
                fprintf(f, "<A href=\"../../../../../cgi-bin/netams_graph.cgi?oid=%s&policy=%06X&year=%u&oids=unit\">Y</a>", unit_list, cpd->policy->id, tm.tm_year+1900);
                fprintf(f, "<img src=\"../../../../../images/rrdgraph-logo.gif\" width=20 height=20 border=1 align=absmiddle>");
                fprintf(f, "&nbsp;&nbsp;");
                fprintf(f, "%s</td>\n", cpd->policy->name?cpd->policy->name:"<\?\?>");
            } else
                fprintf(f, "<td valign=middle bgcolor='#ffffaa'>%s</td>\n", cpd->policy->name?cpd->policy->name:"<\?\?>");

            fprintf(f, "<td>%10s</td><td>%10s</td>", bytesQ2T(cpd->h.in, b2qt[0]), bytesQ2T(cpd->h.out, b2qt[1]));
            fprintf(f, "<td>%10s</td><td>%10s</td>", bytesQ2T(cpd->d.in, b2qt[2]), bytesQ2T(cpd->d.out, b2qt[3]));
            fprintf(f, "<td>%10s</td><td>%10s</td>", bytesQ2T(cpd->w.in, b2qt[4]), bytesQ2T(cpd->w.out, b2qt[5]));
            fprintf(f, "<td>%10s</td><td>%10s</td></tr>\n", bytesQ2T(cpd->m.in, b2qt[6]), bytesQ2T(cpd->m.out, b2qt[7]));
      }
      netams_rwlock_unlock(&u->ap->rwlock);
}
//////////////////////////////////////////////////////////////////////////////////////////
void sHPrintTHeader(FILE *f){

      fprintf(f, "<table cellpadding=3 cellspacing=0 border=1 width=95%% bgcolor=white>\n");
      fprintf(f, "<tr bgcolor=navy align=center><td rowspan=2 valign=middle><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td colspan=2><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td colspan=2><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td colspan=2><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td colspan=2><font face=monospace size=-1 color=yellow>%s</font></td> \
            </tr><tr bgcolor=black align=center> \
            <td><font color=white size=-1>%s</font></td><td><font color=white size=-1>%s</font></td> \
            <td><font color=white size=-1>%s</font></td><td><font color=white size=-1>%s</font></td> \
            <td><font color=white size=-1>%s</font></td><td><font color=white size=-1>%s</font></td> \
            <td><font color=white size=-1>%s</font></td><td><font color=white size=-1>%s</font></td> \
            </tr>\n", Locale(LC_H_ACCT_POLICY), Locale(LC_H_CHOUR), Locale(LC_H_CDAY), Locale(LC_H_CWEEK), Locale(LC_H_CMONTH),
            Locale(LC_H_IN), Locale(LC_H_OUT), Locale(LC_H_IN), Locale(LC_H_OUT), Locale(LC_H_IN), Locale(LC_H_OUT), Locale(LC_H_IN), Locale(LC_H_OUT));
}
//////////////////////////////////////////////////////////////////////////////////////////
void sHPrintTHeaderTopData(FILE *f,const char *period){

      fprintf(f, "<table cellpadding=3 cellspacing=0 border=1 width=95%% bgcolor=white>\n");
      fprintf(f, "<tr bgcolor=navy align=center><td rowspan=2 valign=middle><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td rowspan=2 valign=middle><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td rowspan=2 valign=middle><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td rowspan=2 valign=middle><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td rowspan=2 valign=middle><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td colspan=2><font face=monospace size=-1 color=yellow>%s</font></td> \
            </tr><tr bgcolor=black align=center> \
            <td><font color=white size=-1>%s</font></td><td><font color=white size=-1>%s</font></td> \
            </tr>\n", Locale(LC_H_TYPE), Locale(LC_H_NAME), Locale(LC_H_DESCR), Locale(LC_H_IP), Locale(LC_H_POLICY), period, Locale(LC_H_IN), Locale(LC_H_OUT));
}
//////////////////////////////////////////////////////////////////////////////////////////
void sHPrintTHeaderTopItem(FILE *f, html_top_item *item){
      const char *unit_type; static char b2qt[2][32];
      static char buffer[32];

      if (item->u!=NULL && item->p!=NULL) {
            if (item->u->type==NETUNIT_HOST) {
                  unit_type="HOST";
                  inet_ntop(AF_INET, &(((NetUnit_host*)item->u)->ip), buffer, 32);
            } else {
                  unit_type="USER";
                  inet_ntop(AF_INET, &(((NetUnit_user*)item->u)->ip), buffer, 32);
            }
            fprintf(f, "<tr align=right><td>%s</td><td bgcolor='#ffffcc'><b>%s</b></td><td align=left>%s</td><td>%s</td><td bgcolor='#ffffaa'>%s</td><td>%10s</td><td>%10s</td></tr>\n",
                  unit_type, item->u->name?item->u->name:"<\?\?>", item->u->description?item->u->description:"&nbsp", buffer, item->p->name, bytesQ2T(item->s.in, b2qt[0]), bytesQ2T(item->s.out, b2qt[1]));
      }
}
//////////////////////////////////////////////////////////////////////////////////////////
void sHPrintTHeaderPreincluded(FILE *f){

      fprintf(f, "<table cellpadding=3 cellspacing=0 border=1 width=95%% bgcolor=white>\n");
      fprintf(f, "<tr bgcolor=navy align=center><td rowspan=2 valign=middle><font face=monospace size=-1 color=yellow>%s</font></td><td rowspan=2 valign=middle><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td colspan=2><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td colspan=2><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td colspan=2><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td colspan=2><font face=monospace size=-1 color=yellow>%s</font></td> \
            </tr><tr bgcolor=black align=center> \
            <td><font color=white size=-1>%s</font></td><td><font color=white size=-1>%s</font></td> \
            <td><font color=white size=-1>%s</font></td><td><font color=white size=-1>%s</font></td> \
            <td><font color=white size=-1>%s</font></td><td><font color=white size=-1>%s</font></td> \
            <td><font color=white size=-1>%s</font></td><td><font color=white size=-1>%s</font></td> \
            </tr>\n", Locale(LC_H_SUBPLAN_ID), Locale(LC_H_ACCT_POLICY), Locale(LC_H_CHOUR), Locale(LC_H_CDAY), Locale(LC_H_CWEEK), Locale(LC_H_CMONTH),
            Locale(LC_H_IN), Locale(LC_H_OUT), Locale(LC_H_IN), Locale(LC_H_OUT), Locale(LC_H_IN), Locale(LC_H_OUT), Locale(LC_H_IN), Locale(LC_H_OUT));
}
//////////////////////////////////////////////////////////////////////////////////////////
void HtmlCalendarY(FILE *f, const char *path, char *file, struct tm *tm, const char *yhref, const char *mhref) {
      struct stat sb; bzero(&sb, sizeof (struct stat));

      // years table
      fprintf(f, "<table border=1 cellpadding=3 cellspacing=0> \n");
      for (u_short yr=2000; yr<=tm->tm_year+1900; yr++) {
            snprintf(file, 255, yhref, yr);
            if (!stat(path, &sb)) {
                  fprintf(f, "<tr><td bgcolor=silver><b>%d</b></td>\n", yr);
                  for (int mon=1; mon<=12; mon++) {
                        snprintf(file, 255, mhref, yr, mon);
                        if (!stat(path, &sb)) {
                              fprintf(f, "<td><a href=\"");
                              fprintf(f, mhref, yr, mon);
                              fprintf(f, "\">%s</a></td>", mon_name[mon-1]);
                        } else
                              fprintf(f, "<td>%s</td>", mon_name[mon-1]);
                  }
                  fprintf(f, "</tr>\n");
            }
      }
      fprintf(f, "</table>\n");
}

void HtmlCalendarM(FILE *f, const char *path, char *file, struct tm *tm, const char *href) {
      struct stat sb; bzero(&sb, sizeof (struct stat));

      // month table
      fprintf(f, "<b>%s:</b><br>\n", Locale(LC_H_THIS_MONTH));
      for (u_char day=1; day<=31; day++){
            snprintf(file, 255, href, day);
            if (!stat(path, &sb)) {
                  fprintf(f, "<a href=\"");
                  fprintf(f, href, day);
                  fprintf(f, "\">%d</a> ", day);
            } else
                  fprintf(f, "%d ", day);
      }
      fprintf(f, "<br>\n");
}

void HtmlCalendarD(FILE *f, const char *path, char *file, struct tm *tm, const char *href) {
      struct stat sb; bzero(&sb, sizeof (struct stat));

      // day table
      fprintf(f, "<b>%s:</b><br>\n", Locale(LC_H_THIS_DAY));
      for (u_char hour=0; hour<=11; hour++){
            snprintf(file, 255, href, hour);
            if (!stat(path, &sb)) {
                  fprintf(f, "<a href=\"");
                  fprintf(f, href, hour);
                  fprintf(f, "\">%02d-%02d</a> ", hour, hour+1);
            } else
                  fprintf(f, "%02d-%02d ", hour, hour+1);
      }

      fprintf(f, "<br>\n");

      for (u_char hour=12; hour<=23; hour++){
            snprintf(file, 255, href, hour);
            if (!stat(path, &sb)) {
                  fprintf(f, "<a href=\"");
                  fprintf(f, href, hour);
                  fprintf(f, "\">%02d-%02d</a> ", hour, hour+1);
            } else
                  fprintf(f, "%02d-%02d ", hour, hour+1);
      }
      fprintf(f, "<br></div>\n");
}
//////////////////////////////////////////////////////////////////////////////////////////
void HtmlRedirect(const char *path, const char *href) {
      FILE *f=fopen(path, "w");

      if(!f) {
            aLog(D_ERR, "Can't create file %s : %s\n", path, strerror(errno));
            return;
      }

      fprintf(f, "<html><HEAD><META http-equiv=\"Pragma\" content=\"no-cache\"><META http-equiv=\"Expires\" content=\"-1\"><META http-equiv=\"Cache-Control\" content=\"no-cache\"></HEAD><body><h1>Redirecting to this day index...</h1><script> \
            document.location.href=\"%s\"</script></body></html>\n", href);

      fclose(f);
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_BILLING

void cShowBillingHtml(FILE *f, Service_Html *cfg){
      Service *s=Billing;
      if(!s) return;

      Account *ac;
//    Account *acx=NULL;
//    int isfull=0;
      const char *blocked, *bcolor;

      fprintf(f, "<table cellpadding=3 cellspacing=0 border=1 width=95%% bgcolor=white>\n");
      fprintf(f, "<tr bgcolor=navy align=center><td valign=middle><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td><font face=monospace size=-1 color=yellow>%s</font></td> \
            <td><font face=monospace size=-1 color=yellow>%s</font></td></tr>\n",
            Locale(LC_H_B_ACNAME), Locale(LC_H_B_BALANCE), Locale(LC_H_B_STATUS),
            Locale(LC_H_B_PLAN), Locale(LC_H_B_UNITS));

      netams_rwlock_rdlock(&bAccounts->rwlock);
      for (ac=(Account*)bAccounts->root; ac!=NULL; ac=(Account*)ac->next){
            if (ac->status&ACCOUNT_DELETED) continue; //this account deleted
            if(ac->status&ACCOUNT_BLOCKED ) {
                  blocked=Locale(LC_H_B_BLOCKED);
                  bcolor="pink";
            } else if (ac->status&ACCOUNT_BEBLOCKED) {
                  blocked=Locale(LC_H_B_BEBLOCKED);
                  bcolor="#ffffe0";
            } else {
                  blocked=Locale(LC_H_B_UNBLOCKED);
                  bcolor="white";
            }

            fprintf(f, "<tr><td><a href=\"../../../../accounts/%s/index.html\">%s</a></td><td align=center bgcolor=%s>%.4f</td><td align=center bgcolor=%s>%s</td><td>%s</td><td>&nbsp;",
                  ac->name, ac->name, ac->balance>0?"white":"#ffffe0",
                  ac->balance, bcolor, blocked,
                  ac->plan?(ac->plan->name?ac->plan->name:"<\?\?>"):"-");
            for (bUlist *bu=ac->bUroot; bu!=NULL; bu=bu->next) {
                  NetUnit *u=bu->u;
                  if(cfg->cpages==CPAGES_ALL)
                        fprintf(f, "<a href=\"../../../../clients/%s/index.html\">%s</a>",
                              u->name?u->name:"<\?\?>", u->name?u->name:"-");
                  else
                        fprintf(f, "%s", u->name?u->name:"<\?\?>");
            }
            fprintf(f, "</td></tr>\n");
      } // for
      netams_rwlock_unlock(&bAccounts->rwlock);
      fprintf(f, "</table>\n");
}
//////////////////////////////////////////////////////////////////////////////////////////
void cShowBillingAccountsHtml(FILE *f, Service_Html *cfg, struct tm *tm){
      Service *s=Billing;
      if(!s) return;

      Account *ac;
      struct stat sb;
      bzero(&sb, sizeof (struct stat));
      const char *blocked, *bcolor;

      u_char len=strlen(cfg->path);
      char path[512];               // better change then to dynamic allocation with len [len+256];
      strncpy(path, cfg->path, len);
      char *prefix=&path[len];        //prefix from cfg->path to actual filename
      char *filename;                 //from here filename will be printed
      char tmp[256];

      netams_rwlock_rdlock(&bAccounts->rwlock);
      for (ac=(Account*)bAccounts->root; ac!=NULL; ac=(Account*)ac->next){
            if (ac->status&ACCOUNT_DELETED) continue; //this account deleted
            if(ac->status&ACCOUNT_BLOCKED ) {
                  blocked=Locale(LC_H_B_BLOCKED);
                  bcolor="pink";
            } else if (ac->status&ACCOUNT_BEBLOCKED) {
                  blocked=Locale(LC_H_B_BEBLOCKED);
                  bcolor="#ffffe0";
            } else {
                  blocked=Locale(LC_H_B_UNBLOCKED);
                  bcolor="white";
            }

            //create path
            snprintf(prefix, 255, "/accounts/%s/%04d/%02d", ac->name, tm->tm_year+1900, tm->tm_mon+1);
            if (sHSafeMkdir(path)) return;
            HTML_PUSHD(filename, path);
            aDebug(DEBUG_HTML, "Creation account %s pages in %s\n", ac->name, path);

            // account current page
            snprintf(filename, 255, "index-day-%02d.html", tm->tm_mday);
            f=sHOpenFile(f, path); if (!f) return;
            sHPrintHeader(f, Locale(LC_H_B_BALANCE_FOR), "javascript:history.go(-1)");

            fprintf(f, "<b>%s:</b> %s<br>\n", Locale(LC_H_B_ACNAME), ac->name);
            fprintf(f, "<b>%s:</b> %.4f (<small>%s</small>)<br>\n",
                  Locale(LC_H_B_BALANCE), ac->balance, Locale(LC_H_TRAFINFO_ACTUAL));
            fprintf(f, "<b>%s:</b> <font style=\"background-color:%s\";>&nbsp;%s&nbsp;</font><br>\n",
                  Locale(LC_H_B_STATUS), bcolor, blocked);
            fprintf(f, "<b>%s:</b> %s (<small>%s</small>)<br>\n",
                  Locale(LC_H_B_PLAN),
                  ac->plan?(ac->plan->name?ac->plan->name:"<\?\?>"):"-",
                  ac->plan?(ac->plan->description?ac->plan->description:""):"");

            //++++++++++++++++++++++++++++++++++++++++++
            // year/month table (account)
            fprintf(f, "<br><b>%s:</b><br>", Locale(LC_H_CALENDAR));
            HtmlCalendarY(f, path, filename, tm, "../../%04d", "../../%04d/%02d/index.html");

            // days table (account)
            HtmlCalendarM(f, path, filename, tm, "index-day-%02d.html");
            //+++++++++++++++++++++++++++++++++++++++++

            fprintf(f, "<h3>%s %s, %s</h3>\n <div style=\"margin-left : 5%%;\"> \n",
                  Locale(LC_H_TRAFINFO_FOR), ac->name, Locale(LC_H_TRAFINFO_ACTUAL));

            sHPrintTHeader(f);
            for (bUlist *bu=ac->bUroot; bu!=NULL; bu=bu->next) {
                  sHPrintUnitsTree(f, cfg, bu->u);
            }
            fprintf(f, "</table></div><br>");

            if (ac->plan) {
                  Policy *p;
                  static char b2qt[8][32];
                  u_char poz=0;
                  fprintf(f, "<h3>%s %s, %s</h3>\n <div style=\"margin-left : 5%%;\">\n",
                        Locale(LC_H_PREINCLUDED_LEFT), ac->name, Locale(LC_H_TRAFINFO_ACTUAL));
                  sHPrintTHeaderPreincluded(f);
                  for(bSPlist *bsp=ac->plan->root;bsp!=NULL; bsp=bsp->next, poz++) {
                        p = (Policy*)PolicyL->getById(bsp->sp->pid);
                        if (!p || !p->name) break;
                        fprintf(f, "<tr align=right><td bgcolor='#ffffcc'>%06X</td><td bgcolor='#ffffaa'>%s</td>",
                              bsp->sp->id,p->name);
                        billing_data *bd = &ac->data[poz];
                        bstat *stat[4] = { &bd->h, &bd->d, &bd->w, &bd->m };
                        for(u_char i=0; i<4; i++) {
                              fprintf(f, "<td>%10s</td><td>%10s</td>",
                                    (stat[i]->in<0) ?bytesQ2T(-stat[i]->in, b2qt[0]):"",
                                    (stat[i]->out<0)?bytesQ2T(-stat[i]->out, b2qt[1]):"");
                        }
                        fprintf(f, "</tr>\n");
                  }
                  fprintf(f, "</table></div><br>");
                  fprintf(f, "</div><br>");
            }

            sPrintFooter(f, "javascript:history.go(-1)");

            snprintf(filename, 255, "index.html");
            f=sHOpenFile(f, path); if (!f) return;
            sHPrintHeader(f, Locale(LC_H_RUNTIME), "../../index.html");

            fprintf(f, "<h3>%s: %s</h3>\n <div style=\"margin-left : 5%%;\"> \n",
                  Locale(LC_H_INDEX_MONTH), mon_name[tm->tm_mon]);

            //month table
            HtmlCalendarM(f, path, filename, tm, "index-day-%02d.html");

            fprintf(f, "<br></div><br>\n");
            sPrintFooter(f, "../../index.html");

            //change file and cleanup
            HTML_POPD(filename);

            // create a master index file at account root, pointing to the current file
            snprintf(filename, 255, "/accounts/%s/index.html", ac->name);
            snprintf(tmp, 255, "%04d/%02d/index-day-%02d.html", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
            HtmlRedirect(path, tmp);

            // check if .htaccess file should be created or changed
            // for billing accounts, ask for passwords in MySQL instead of local database or RADIUS
            snprintf(filename, 255, "/accounts/%s/.htaccess", ac->name);
            if (cfg->is_htaccess && stat(path, &sb)) {
                  snprintf(filename, 255, "/accounts/%s/.htaccess", ac->name);
                  f=sHOpenFile(f, path); if (!f) return;
                  fprintf(f, "AuthName \"NeTAMS Account Login\"\n Require user");
                  Users->listUsersHtml(f);
                  fprintf(f, " %s\n<FilesMatch \"\\.(gif|jpe?g|png)$\">\nRequire valid-user\nSatisfy Any\n</FilesMatch>\nAuthType Basic\n\n", ac->name);
                  if (cfg->is_htaccess==1) {
                        fprintf(f, "AuthMySQLAuthoritative        on\n");
                        //21.07.2006 changed to defaults due Service_Storage changes
                        fprintf(f, "AuthMySQLUser                 %s\n",            "root");
                        //if (st->password) fprintf(f, "AuthMySQLPassword           %s\n",      "");
                        fprintf(f, "AuthMySQLDB       %s\n",                        "netams");
                        fprintf(f, "AuthMySQLHost           %s\n",                  "localhost");
                        //
                        fprintf(f, "AuthMySQLUserTable            billing\n");
                        fprintf(f, "AuthMySQLNameField            name\n");
                        fprintf(f, "AuthMySQLPasswordField        passwd\n");
                        fprintf(f, "AuthMySQLNoPasswd       off\n");
                        fprintf(f, "AuthMySQLCryptedPasswords     off\n");
                  }

            }

      } // loop for all accounts
      netams_rwlock_unlock(&bAccounts->rwlock);
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index