#include <sys/cdefs.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <syslog.h>
#include <net/if.h>
#include <dirent.h>
#include "flate.h"
#include "iniparser/iniparser.h"
#include "ooma/types.h"
#include "ooma/util.h"
#include "oomatrace.h"
#include "ooma/netmgr.h"
#include "ooma/net.h"
#include "msglib/msglib.h"

#ifndef SOCKET
#define SOCKET int
#endif

#define PAGE_HOME   	"home"
#define PAGE_NETWORK 	"network"
#define PAGE_PHONE 		"phone"
#define PAGE_LOGGING 	"logging"
#define PAGE_IFCONFIG	"ifconfig"
#define PAGE_STATUS		"status"
#define PAGE_SYSLOG		"logread"
#define PAGE_LAN		"lan"
#define PAGE_ADD_PORT_FORWARD "add_port_forward"

#define TEMPLATE_HOME	 	"/home/httpd/ooma_home.html"
#define TEMPLATE_NETWORK 	"/home/httpd/net_options.html"
#define TEMPLATE_PHONE 		"/home/httpd/phone_options.html"
#define TEMPLATE_LOGGING	"/home/httpd/logging_options.html"
#define TEMPLATE_STATUS 	"/home/httpd/device_status.html"
#define TEMPLATE_IFCONFIG	"/home/httpd/ifconfig.html"
#define TEMPLATE_SYSLOG  	"/home/httpd/logread.html"
#define TEMPLATE_LAN		"/home/httpd/lan_options.html"
#define TEMPLATE_ADD_PORT_FORWARD "/home/httpd/add_port_forward.html"

/* define DO_SYSLOG to enable logging */
#define DO_SYSLOG

#define MAX_TRACE_LEVEL		7
#define DEFAULT_TRACE_LEVEL	"3"

#define OOMA_NET_CFG_FILE  "/opt/etc/ooma/netmgr.cfg"
#define OOMA_QOS_CFG_FILE  "/opt/etc/ooma/netmgr_qos.cfg"
#define OOMA_MDM_CFG_FILE  "/opt/etc/ooma/mdm.cfg"
#define OOMA_TRACE_CFG_FILE  "/opt/etc/ooma/trace.cfg"
#define OOMA_MDM_STATUS_FILE  "/var/tmp/mdm_status"

#define OOMACGI_WAN_ETH	"eth1"
#define OOMACGI_LAN_ETH	"eth0"
#define OOMACGI_TUN_IF	"tun0"

#define NUM_PORT_FORWARD_RULES 50

#define UNCHANGED_PPPOE_PASSWORD "****************"

#define OOMA_MAX_NAME_LEN	50

extern int shark(void);

void gen_page(const char * page);
void upd_page(const char * page);

void update_network();
void update_phone();
void update_logging();
void update_lan();
void update_add_port_forward_rule();

void generate_home();
void generate_network();
void generate_phone();
void generate_logging();
void generate_status();
void generate_ifconfig();
void generate_syslog();
void generate_lan();

int get_network_data();
int get_phone_data();
int get_diags_data();

int main (int argc, const char * argv[]) 
{
    opm_init(OPM_SLOT_CGI);

    if (shark())
    {
        printf("Shark failed");
    	return(1);
    }
        
    char * generate_page = getenv("sharkg_makepage");
    char * update_page = getenv("sharkg_page");
    
#ifdef DO_SYSLOG
   // setlogmask(LOG_UPTO(LOG_DEBUG));
#endif
    
    if(update_page)
        upd_page(update_page);
    else if(generate_page)
        gen_page(generate_page);
    else
        shark__perr("No page specified");
    
    opm_exit();
    
    return 0;
}

void upd_page(const char * page)
{
	system("set > /tmp/env");

#ifdef DO_SYSLOG
   syslog(LOG_DEBUG, "running cgi_script %s", page);
#endif
    if(!strncmp(page, PAGE_NETWORK, sizeof(PAGE_NETWORK)))
        update_network();
    else if(!strncmp(page, PAGE_PHONE, sizeof(PAGE_PHONE)))
        update_phone();
    else if(!strncmp(page, PAGE_LOGGING, sizeof(PAGE_LOGGING)))
        update_logging();
    else if(!strncmp(page, PAGE_LAN, sizeof(PAGE_LAN)))
        update_lan();
    else if(!strncmp(page, PAGE_ADD_PORT_FORWARD, sizeof(PAGE_ADD_PORT_FORWARD)))
        update_add_port_forward_rule();
    else
        shark__perr("Unknown update page");
}

void gen_page(const char * page)
{
#ifdef DO_SYSLOG
    syslog(LOG_DEBUG, "running cgi_script %s", page);
#endif
    if(!strncmp(page, PAGE_HOME, sizeof(PAGE_HOME)))
        generate_home();
    else if(!strncmp(page, PAGE_NETWORK, sizeof(PAGE_NETWORK)))
        generate_network();
    else if(!strncmp(page, PAGE_PHONE, sizeof(PAGE_PHONE)))
        generate_phone();
    else if(!strncmp(page, PAGE_STATUS, sizeof(PAGE_STATUS)))
        generate_status();
    else if(!strncmp(page, PAGE_IFCONFIG, sizeof(PAGE_IFCONFIG)))
        generate_ifconfig();
    else if(!strncmp(page, PAGE_LOGGING, sizeof(PAGE_LOGGING)))
        generate_logging();
    else if(!strncmp(page, PAGE_SYSLOG, sizeof(PAGE_SYSLOG)))
        generate_syslog();
    else if(!strncmp(page, PAGE_LAN, sizeof(PAGE_LAN)))
        generate_lan();
    else
        shark__perr("Unknown page");    
}


void convert_tabs_to_table(const char * raw, char * html, int len)
{
    int i, j;
    int raw_len = strlen(raw);
    char tmp[2];
    int space_count = 0;
    char str_td[] = "</td><td>";
    char str_td_td[] = "</td></td><td><td>";
    char str_td_tr[] = "</td></tr>\n<tr><td>";
    int td_len = strlen(str_td);
    int td_td_len = strlen(str_td_td);   
    int td_tr_len = strlen(str_td_tr);   
    
    tmp[1] = 0;
    
    strcpy(html, "<table><tbody><tr><td>");
    j = strlen(html);
    
    for( i = 0; i < raw_len && j < (len - 1 - td_tr_len); i++)
    {
        switch(raw[i]) {
            case '\t':
                strcpy(&html[j], str_td);
                j += td_len;
                space_count = 0;
                break;
            case '\n':
                strcpy(&html[j], str_td_tr);
                j += td_tr_len;
                space_count = 0;
                break;              
            case '\r':
                break;
            case ' ':
                space_count++;
                if(space_count == 4)
                {
                    strcpy(&html[j], str_td_td);
                    j += td_td_len;
                }
                /* compress all space to 1 space character */
                if(space_count == 1)
                {
                    html[j] = ' ';
                    j++;     
                }
	        break;
            default:
                html[j] = raw[i];
                j++;
                space_count = 0;
                break;
        }
    }
    strncat(html, "</td></tr>\n</tbody></table>\n", len);
}

void convert_crs_to_html(const char * raw, char * html, int len)
{
    int i, j;
    int raw_len = strlen(raw);
    char tmp[2];
    int space_count = 0;
    int br_len = strlen("<br>");
    
    tmp[1] = 0;
    
    strcpy(html, "<br>");
    
    for( i = 0, j = br_len; i < raw_len && j < (len - 1 - br_len); i++)
    {
        switch(raw[i]) {
            case '\n':
                strcpy(&html[j], "<br>");
                space_count = 0;
                j += br_len;
				break;              
            case '\r':
                break;
            default:
                html[j] = raw[i];
                j++;
                break;
        }
    }
    html[j] = 0;
}

int is_valid_mask(unsigned int netmask)
{
    unsigned int mask = 0x80000000;
    do {
	if (netmask & mask) {
	    mask >>= 1; 
	} else {
	    mask--;
	    if (netmask&mask) return 0;
	    break;
	}
    } while (mask!=0);
    return 1;
}

int is_number_only(const char * str, int max_val)
{
    int i;
    
    if(!str)
        return 0;

    for(i = 0; i < strlen(str); i++)
    {
        char numbers[] = "0123456789";
        if(!strchr(numbers, str[i]))
        {
            return 0;
        }
    }
    if(atoi(str) > max_val)
        return 0;
    return 1;
}

int is_hex_only(const char * str, int max_val, unsigned int * val)
{
    int i;
    
    if(!str)
        return 0;
    
    for(i = 0; i < strlen(str); i++)
    {
        char numbers[] = "0123456789abcdefABCDEF";
        if(!strchr(numbers, str[i]))
        {
            return 0;
        }
    }
    if((*val = strtol(str, NULL, 16)) > max_val)
        return 0;
    return 1;
}

char * get_shark_env(char * var)
{
    char tmp[100];
    char * rc;
    sprintf(tmp, "sharkg_%s", var);
    rc = getenv(tmp);
    return rc;
}

int get_mac_address(const char * name, char * class_a, char * class_b, char * class_c, char * class_d, char * class_e, char * class_f, char * ip_out)
{
    char * addr_a = get_shark_env(class_a);
	char * addr_b = get_shark_env(class_b);
	char * addr_c = get_shark_env(class_c);
	char * addr_d = get_shark_env(class_d);    
	char * addr_e = get_shark_env(class_e);    
	char * addr_f = get_shark_env(class_f);    
    int rc = TRUE;
    unsigned int int_a, int_b, int_c, int_d, int_e, int_f; 
    
    rc = rc && is_hex_only(addr_a, 0xFF, &int_a);
    rc = rc && is_hex_only(addr_b, 0xFF, &int_b);
    rc = rc && is_hex_only(addr_c, 0xFF, &int_c);
    rc = rc && is_hex_only(addr_d, 0xFF, &int_d);
    rc = rc && is_hex_only(addr_e, 0xFF, &int_e);
    rc = rc && is_hex_only(addr_f, 0xFF, &int_f);
    
	if(!rc)
    {
	    shark__perr("<big>Bad %s.<BR> Enter a MAC Address with numbers 0-9 or letters A-F only <br><br>"
    	            "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings</a></big>\n", name);    
    }
    else
    {
        ooma_eth_addr_t eth_addr;
        
        sprintf(ip_out, "%02X:%02X:%02X:%02X:%02X:%02X", int_a, int_b, int_c, int_d, int_e, int_f);
#ifdef DO_SYSLOG
     //   syslog(LOG_DEBUG, "http_cgi: mac addr %s", ip_out);
#endif
        /* validate mac address */
        rc = util_parse_eth_addr(ip_out, &eth_addr);
        if(!rc)
        {
            shark__perr("<big>Bad %s.<BR> Enter a MAC Address with numbers 0-9 or letters A-F only <br><br>"
                        "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings</a></big>\n", name);    
        }
    }
    
    return rc;
}

int get_ip_address(const char * name, char * class_a, char * class_b, char * class_c, char * class_d, char * ip_out, const char * page)
{
    char * addr_a = get_shark_env(class_a);
	char * addr_b = get_shark_env(class_b);
	char * addr_c = get_shark_env(class_c);
	char * addr_d = get_shark_env(class_d);    
    int rc = TRUE;
    
    if(!strlen(addr_a) && !strlen(addr_b) && !strlen(addr_c) && !strlen(addr_d))
    {
        ip_out[0] = 0;
        return TRUE;
    }
    
    if(!strlen(addr_a) || !strlen(addr_b) || !strlen(addr_c) || !strlen(addr_d))
    {
		char err_str[512];
		
	    sprintf(err_str, "<big>%s is an invalid IP Address.<BR> Enter all fields of the IP Address with numbers less than 256, e.g. 192.168.1.1 <br><br>"
    	            "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=%s\" target=\"_self\">Return to %s Settings</a></big>\n", name, page, page);    
		shark__perr(err_str);
		ip_out[0] = 0;
        return FALSE;
    }
    
    rc = rc && is_number_only(addr_a, 255);
    rc = rc && is_number_only(addr_b, 255);
    rc = rc && is_number_only(addr_c, 255);
    rc = rc && is_number_only(addr_d, 255);

	if(!rc)
    {
	char err_str[512];
	sprintf(err_str, "<big>%s is an invalid IP Address.<BR> Enter an IP Address with numbers less than 256, e.g. 192.168.1.1 <br><br>"
    	            "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=%s\" target=\"_self\">Return to %s Settings</a></big>\n", name, page, page);    
	shark__perr(err_str);
	ip_out[0] = 0;
    }
    else
    {
        sprintf(ip_out, "%s.%s.%s.%s", addr_a, addr_b, addr_c, addr_d);
#ifdef DO_SYSLOG
     //   syslog(LOG_DEBUG, "http_cgi: %s %s", name, ip_out);
#endif
    }
    
    return rc;
}

int send_netmgr_reconfig()
{
    ooma_msg_err_t      ret;
    char msg[] = "type:read-cfg";
    char * msg2 = msg;
    ret = ooma_msg_init(NULL, NULL, NULL);
    if (ret != OOMA_MSG_SUCCESS) {
#ifdef DO_SYSLOG
      //  syslog(LOG_DEBUG, "MsgLib init error: %s\n", ooma_msg_err_str(ret));
#endif
        exit (EXIT_FAILURE);
    }
    
    ret = ooma_msg_send("netmgr", 1, &msg2, 1);
    if (ret != OOMA_MSG_SUCCESS) {
#ifdef DO_SYSLOG
      //  syslog(LOG_DEBUG, "MsgLib send error: %s\n", ooma_msg_err_str(ret));
#endif
        exit (EXIT_FAILURE);
    }          
#ifdef DO_SYSLOG
    //syslog(LOG_DEBUG, "http_cgi: netmgr send OK");
#endif
    
    return (EXIT_SUCCESS);
}

void update_network()
{
    /* extract the network info */
    char ip_addr[25] = "";
    char dns1[25] = "";
    char dns2[25] = "";
    char router[25] = "";
    char netmask[25] = "";
    char mac_addr[25] = "";
    char home_mac_addr[25] = "";
    char password[100] = "";
    char * protocol = getenv("sharkg_protocol");
    char * pppoe_username = getenv("sharkg_pppoe_username");
    char * pppoe_password = getenv("sharkg_pppoe_password");
    char * pppoe_service = getenv("sharkg_pppoe_service");
    char * mac_type = getenv("sharkg_mac_addr");
	char err_str[512];
    FILE * ini_file;
    dictionary          *ooma_dict = 0;

    if(strlen(pppoe_username) > OOMA_MAX_NAME_LEN)
    {
        shark__perr("<big>Username too long.<BR> Enter a username with no more than 50 characters.<br><br>"
                    "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings</a></big>\n");    
        return;
    }
    if(strlen(pppoe_password) > OOMA_MAX_NAME_LEN)
    {
        shark__perr("<big>Password too long.<BR> Enter a username with no more than 50 characters.<br><br>"
                    "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings</a></big>\n");    
        return;
    }
    if(strlen(pppoe_service) > OOMA_MAX_NAME_LEN)
    {
        shark__perr("<big>Servicename too long.<BR> Enter a username with no more than 50 characters.<br><br>"
                    "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings</a></big>\n");    
        return;
    }
    if(!get_ip_address("IP Address", "ip_address_a", "ip_address_b", "ip_address_c", "ip_address_d", ip_addr, "network") ||
 	   !get_ip_address("Netmask", "netmask_a", "netmask_b", "netmask_c", "netmask_d", netmask, "network") ||
 	   !get_ip_address("DNS 1 Address", "dns1_address_a", "dns1_address_b", "dns1_address_c", "dns1_address_d", dns1, "network") ||
	   !get_ip_address("DNS 2 Address", "dns2_address_a", "dns2_address_b", "dns2_address_c", "dns2_address_d", dns2, "network") ||
       !get_ip_address("Router Address", "router_address_a", "router_address_b", "router_address_c", "router_address_d", router, "network"))
    {
        return;
    } 
    
    if (!strcmp(protocol, "static")) {
        long lIpAddr=0, lNetmask=0, lRouter=0;

        if (!strlen(ip_addr) || !strlen(netmask) || !strlen(router)) {
            sprintf(err_str, "<big>For a Static IP configuration you must fill in the IP address, Netmask and Router Address fields.<br><br>"
                             "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings to correct</a></big>\n");
            shark__perr(err_str);
            return;
        }
        inet_pton(AF_INET, ip_addr, &lIpAddr);
        inet_pton(AF_INET, netmask, &lNetmask);
        inet_pton(AF_INET, router, &lRouter);

        if (!is_valid_mask(lNetmask)) {
            shark__perr("<big> The Netmask is Invalid.<br><br>"
                        "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings to correct</a></big>\n");
            return;
        }

        if ((lIpAddr&lNetmask) != (lRouter&lNetmask)) {
            sprintf(err_str, "<big> IP address and Router address are NOT on the same subnet.<br><br>"
                             "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings to correct</a></big>\n");
            shark__perr(err_str);
            return;
        }
    }

    /* if the user selected a custom IP address then validate and use it */
    switch(mac_type[0]) {
    case '0': /* custom */
        get_if_mac_address(OOMACGI_LAN_ETH, home_mac_addr);
        if(!get_mac_address("MAC Address", "mac_a", "mac_b", "mac_c", "mac_d", "mac_e", "mac_f", mac_addr))
        {
            return;
        }
        if(!strcmp(mac_addr, home_mac_addr))
        {
            sprintf(err_str, "<big> The MODEM Port MAC Address is set to the same as the HOME Port MAC Address, they must be different.<br><br>"
                             "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings to correct</a></big>\n");
            shark__perr(err_str);
            return;
        }
        break;
    case '1': /* built in */
        get_default_wan_mac_addr(mac_addr);
        break;
    default:
    case '2': /* automatic */
        memset(mac_addr, 0, sizeof(mac_addr));
        break;
    }

    /* read the password from the old configuration */
  	ooma_dict = iniparser_new(OOMA_NET_CFG_FILE);
    if(ooma_dict)
    {
		char * value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_PPPOE_PASSWD);
        if(value)
        {
            strncpy(password, value, sizeof(password));
        }
        iniparser_free(ooma_dict);
    }
  	ooma_dict = iniparser_new(OOMA_NET_CFG_FILE);
    if (ooma_dict) 
    {
        /* set all the configuration options from the isp.cfg file */
        iniparser_setstr(ooma_dict, "default", NULL);
        if(strlen(pppoe_username))
	        iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_PPPOE_USER, pppoe_username);
        /* only update the password if the user edited the stars we displayed */
        if(strcmp(UNCHANGED_PPPOE_PASSWORD, pppoe_password) && strlen(pppoe_password))
	        iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_PPPOE_PASSWD, pppoe_password);
        else if(!strcmp(UNCHANGED_PPPOE_PASSWORD, pppoe_password) && strlen(password))
	        iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_PPPOE_PASSWD, password);
        if(strlen(pppoe_service))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_PPPOE_SERVICE, pppoe_service);
        if(strlen(protocol))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_PROTO, protocol);
        if(strlen(ip_addr))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_IP_ADDR, ip_addr);
	else iniparser_unset(ooma_dict, NETMGR_CFG_KEY_IP_ADDR);
        if(strlen(netmask))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_NETMASK, netmask);
	else iniparser_unset(ooma_dict, NETMGR_CFG_KEY_NETMASK);
        if(strlen(dns1))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_DNS1, dns1);
	else iniparser_unset(ooma_dict, NETMGR_CFG_KEY_DNS1);
        if(strlen(dns2))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_DNS2, dns2);
	else iniparser_unset(ooma_dict, NETMGR_CFG_KEY_DNS2);
        if(strlen(router))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_ROUTER, router);
	else iniparser_unset(ooma_dict, NETMGR_CFG_KEY_ROUTER);
        if(strlen(mac_addr))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_WAN_ETH_ADDR, mac_addr);
	else
            iniparser_unset(ooma_dict, NETMGR_CFG_KEY_WAN_ETH_ADDR);
        ini_file = fopen(OOMA_NET_CFG_FILE, "w");
        iniparser_dump_ini(ooma_dict, ini_file);
        fclose(ini_file);
        iniparser_free(ooma_dict);
    }
    
    send_netmgr_reconfig();
    
    
    printf("Content-Type: text/html\r\n\r\n"
           "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
           "<HTML><HEAD>\n"
           "<TITLE>Network Parameters Updated</TITLE>\n"
           "</HEAD><BODY>\n"
           "<H1>Network Parameters Updated OK!</H1>\n"
           "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=network\" target=\"_self\">Return to Network Settings</a>\n"
           "<HR>\n"
           "</BODY></HTML>\n");
    fflush(stdout);
}

void update_phone()
{
    /* extract the phone info */
    char * phone_number = getenv("sharkg_phone_number");
    char cmd[35];
    int rc, i;
    if(!phone_number)
    {
        shark__perr("Error reading new phone number level");    
        return;
    }
    if(strlen(phone_number) != 11)
    {
        shark__perr("<big>Illegal phone number.<BR> Enter the phone number with digits only and no spaces hyphens or brackets, e.g. 14085551212 <br><br>"
                    "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=phone\" target=\"_self\">Return to Phone Settings</a></big>\n");    
        return;
    }
    for(i = 0; i < strlen(phone_number); i++)
    {
        char numbers[] = "0123456789";
        if(!strchr(numbers, phone_number[i]))
        {
            shark__perr("<big>Illegal phone number.<BR> Enter the phone number with digits only and no spaces hyphens or brackets, e.g. 14085551212 <br><br>"
            "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=phone\" target=\"_self\">Return to Phone Settings</a></big>\n");    
            return;
        }
    }
    
    sprintf(cmd, "chgcfg %s MY_PHONE %s", OOMA_MDM_CFG_FILE, phone_number);
    rc = system(cmd);
    
    util_send_parameter_update_to_mdm(OOMA_PARAM_PHONE_NUMBER);
    
    printf("Content-Type: text/html\r\n\r\n"
           "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
           "<HTML><HEAD>\n"
           "<TITLE>Phone Parameters Updated</TITLE>\n"
           "</HEAD><BODY>\n"
           "<H1>Phone Parameters Updated OK!</H1>\n"
           "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=phone\" target=\"_self\">Return to Phone Settings</a>\n"
           "<HR>\n"
           "</BODY></HTML>\n");
    fflush(stdout);
}


int get_new_trace_level(char * trace_name, char * new_level)
{
    char * trace_level = getenv(trace_name);
    char numbers[] = "0123456789";
    
    if(!trace_level)
    {
        shark__perr("Error reading new trace level");    
        return 0;
    }
    if(strlen(trace_level) != 1 || !strchr(numbers, trace_level[0]) || atoi(trace_level) > MAX_TRACE_LEVEL)
    {
        shark__perr("<big>Illegal Ooma Monitor trace level.<BR> Select a value between 0 and 7. <br><br>"
                    "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=logging\" target=\"_self\">Return to Logging Configuration</a></big>\n");    
        return 0;
    }
    strncpy(new_level, trace_level, 2);
    
    return 1;
}

void update_logging()
{
    /* extract the diags info */
    char new_mdm_level[2];
    char new_vpn_level[2];
    char new_prov_level[2];
    char new_opm_level[2];
    char new_netmgr_level[2];
    char new_gtppmyx_level[2] = "3";
    dictionary          *ooma_dict = 0;

    if(!get_new_trace_level("sharkg_mdm_trace_level", new_mdm_level) ||
    	!get_new_trace_level("sharkg_vpn_trace_level", new_vpn_level) ||
    	!get_new_trace_level("sharkg_prov_trace_level", new_prov_level) ||
    	!get_new_trace_level("sharkg_opm_trace_level", new_opm_level) ||
    	!get_new_trace_level("sharkg_netmgr_trace_level", new_netmgr_level))
    {
        return;
    }

    /* need to read the gtppmyx log level, it is not exposed on the web page */
    ooma_dict = iniparser_new(OOMA_TRACE_CFG_FILE);
    if(ooma_dict)
    {
        char * value;
        value = iniparser_getstr(ooma_dict, "default:gtppmyx");
        if(value)
        {
            new_gtppmyx_level[0] = value[0];
        }
        iniparser_free(ooma_dict);
    }

    ooma_dict = iniparser_new("/dev/null");
    if (ooma_dict) 
    {
        FILE * ini_file;
#ifdef DO_SYSLOG
     //   syslog(LOG_DEBUG, "http_cgi: writing new trace file");
#endif
        
        iniparser_setstr(ooma_dict, "default", NULL);
        iniparser_setstr(ooma_dict, "default:mdm", new_mdm_level);
        iniparser_setstr(ooma_dict, "default:openvpn", new_vpn_level);
        iniparser_setstr(ooma_dict, "default:provisioning", new_prov_level);
        iniparser_setstr(ooma_dict, "default:opm", new_opm_level);
        iniparser_setstr(ooma_dict, "default:netmgr", new_netmgr_level);
        iniparser_setstr(ooma_dict, "default:gtppmyx", new_gtppmyx_level);
        ini_file = fopen(OOMA_TRACE_CFG_FILE, "w");
        iniparser_dump_ini(ooma_dict, ini_file);
        fclose(ini_file);
        iniparser_free(ooma_dict);
    }
    
    ooma_trace_set_level(OPM_SLOT_MDM, atoi(new_mdm_level));   
    ooma_trace_set_level(OPM_SLOT_OPENVPN, atoi(new_vpn_level));   
    ooma_trace_set_level(OPM_SLOT_PROV, atoi(new_prov_level));   
    ooma_trace_set_level(OPM_SLOT_ME, atoi(new_opm_level));   
    ooma_trace_set_level(OPM_SLOT_NETMGR, atoi(new_netmgr_level));   
    
    printf("Content-Type: text/html\r\n\r\n"
           "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
           "<HTML><HEAD>\n"
           "<TITLE>Logging Parameters Updated</TITLE>\n"
           "</HEAD><BODY>\n"
           "<H1>Logging Parameters Updated OK!</H1>\n"
           "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=logging\" target=\"_self\">Return to Logging Configuration</a>\n"
           "<HR>\n"
           "</BODY></HTML>\n");
    fflush(stdout);
}


void do_get_apps(Template * mytemplate, char ** apps, char ** template_vars)
{
    char path[32], sbuf[512];
    FILE * cmd_line;
    int read, i;
    DIR *dir;
    struct dirent *entry;

    dir = opendir("/proc");
    if (!dir)
        return;
    
    while ((entry = readdir(dir)) != NULL) 
    {
        /* all processes have a directory named with the PID */
        if (!isdigit(*entry->d_name))
			continue;            
        
        sprintf(path, "/proc/%s/cmdline", entry->d_name);

        cmd_line = fopen(path, "r");
        if(cmd_line)
        {
            memset(sbuf, 0, sizeof(sbuf));
            read = fread(sbuf, 1, sizeof(sbuf), cmd_line); 
            fclose(cmd_line);
            for(i = 0; apps[i][0]; i++)
            {
                if(!template_vars[i] || read < strlen(apps[i]))
                    continue;
                if(strstr(sbuf, apps[i]))
                {
                    char data[50];
                    sprintf(data, "%s - Running", entry->d_name);
                    templateSetVar(mytemplate, template_vars[i], data);
                    template_vars[i] = 0;
                    break;
                }
            }
        }
    }
    closedir(dir);
    /* go through the unfound processes and mark them so */
    for(i = 0; apps[i][0]; i++)
    {
        if(template_vars[i])
            templateSetVar(mytemplate, template_vars[i], "Status unavailable !");
    }
}

void do_get_net(Template * mytemplate, const char * iname, char * template_var, char show_addr)
{
    struct in_addr ip_addr;
    int rc;
    char out[50];
    
    memset(&ip_addr, 0, sizeof(ip_addr));
    
    rc = util_get_if_status(iname, &ip_addr);
    switch(rc) {
        case -1:
        case 1:
	        templateSetVar(mytemplate, template_var, "Disconnected");
            break;
        case 0:
            if(!show_addr)
            {
                templateSetVar(mytemplate, template_var, "Connected");
            }
            else
            {
	            sprintf(out, "Connected : [%s]", util_in_addr_to_str(ip_addr.s_addr));
		        templateSetVar(mytemplate, template_var, out);
            }
            break;
    }
}

void do_get_mem(Template * mytemplate, char * template_var)
{
    char ext_data[1000] = "Status unavailable";
    FILE * ext_app;
    int read;
    
    ext_app = popen("cat /proc/meminfo | grep MemFree | sed 's/MemFree: *\\| kB//g'", "r");
	if(ext_app)
    {
        read = fread(ext_data, sizeof(char), sizeof(ext_data), ext_app);
        ext_data[read] = 0;
        templateSetVar(mytemplate, template_var, ext_data);
        pclose(ext_app);
    }
    else
    {
        templateSetVar(mytemplate, template_var, "Status unavailable (2)");
    }
}

void get_version_info(Template * mytemplate)
{
    char ext_data[1000] = " - Rev: ";
    FILE * ext_app;
    int read;
    
    ext_app = popen("cat /proc/version | sed 's/.*)\\ #//g' | sed 's/\\ .*$//'", "r");
	if(ext_app)
    {
        int len = strlen(ext_data);
        read = fread(&ext_data[len], sizeof(char), sizeof(ext_data) - len - 1, ext_app);
        /* overwrite newline character */
        ext_data[read + len - 1] = '.';
        ext_data[read + len] = 0;
        pclose(ext_app);
    }
    else
    {
        int len = strlen(ext_data);
        strcpy(&ext_data[len], "0.");
    }
    ext_app = popen("cat /version | sed 's/Revision: //g'", "r");
	if(ext_app)
    {
        int len = strlen(ext_data);
        read = fread(&ext_data[len], sizeof(char), sizeof(ext_data) - len - 1, ext_app);
        /* overwrite newline character */
        ext_data[read + len - 1] = ' ';
        ext_data[read + len] = 0;
        pclose(ext_app);
    }
    else
    {
        int len = strlen(ext_data);
        strcpy(&ext_data[len], "0 ");
    }
    
	templateSetVar(mytemplate, "versions", ext_data);
}

void generate_status()
{
    Template *mytemplate = NULL;
    char * apps[] = { "mdm" ,"dnsmasq", "openvpn", "thttpd", "" };
    char * vars[] = { "telephony", "dnsmasq", "open_vpn", "thttpd", "" };
    
    mytemplate = templateSetFile(&mytemplate, TEMPLATE_STATUS);
    
    if(!mytemplate)
    {
        shark__perr("Error loading status template");
        return;
    }
    
    get_version_info(mytemplate);
    
    /* obtain the data to show on the web page */
	do_get_net(mytemplate, OOMACGI_WAN_ETH, "internet", 1);
	do_get_net(mytemplate, OOMACGI_LAN_ETH, "internal", 1);
	do_get_net(mytemplate, OOMACGI_TUN_IF, "ooma", 0);
    
    do_get_apps(mytemplate, &apps[0], vars);

    do_get_mem(mytemplate, "freemem");

    templatePrint(mytemplate);
    
    fflush(stdout);
    
    templateFreeMem(mytemplate);
}

void generate_ifconfig()
{
    Template *mytemplate = NULL;
    char ifconfig_raw[10000];
    char ifconfig[10000] = "Interface Information Unavailable";
    FILE * if_file;
	int size = 0;

    mytemplate = templateSetFile(&mytemplate, TEMPLATE_IFCONFIG);
    
    if(!mytemplate)
    {
        shark__perr("Error loading ifconfig template");
        return;
    }

    /* obtain the data to show on the web page */
    if_file = popen("ifconfig eth0", "r");
    if(if_file)
    {
        memset(ifconfig_raw, 0, sizeof(ifconfig_raw));
        fread(ifconfig_raw, sizeof(ifconfig_raw), sizeof(char), if_file);
        /* change eth0 to Home */
        if(!strncmp(ifconfig_raw, "eth0", 4))
        {
            ifconfig_raw[0] = 'H';ifconfig_raw[1] = 'O';ifconfig_raw[2] = 'M';ifconfig_raw[3] = 'E';
        }
        /* convert to html */
        convert_tabs_to_table(ifconfig_raw, ifconfig, sizeof(ifconfig));
        pclose(if_file);
		size = strlen(ifconfig);
    }
    /* modem will be ppp1000 or eth1 depending on whether pppoe is being used */ 
    if_file = popen("ifconfig ppp100", "r");
    if(if_file)
    {
        memset(ifconfig_raw, 0, sizeof(ifconfig_raw));
        fread(ifconfig_raw, sizeof(ifconfig_raw), sizeof(char), if_file);
        /* change ppp100 to Modm */
        if(!strncmp(ifconfig_raw, "ppp100", 6))
        {   
            ifconfig_raw[0] = 'M';ifconfig_raw[1] = 'O';ifconfig_raw[2] = 'D';ifconfig_raw[3] = 'E'; ifconfig_raw[4] = 'M'; ifconfig_raw[5] = ' ';
        }
        else /* no ppp100 interface */
        {
            pclose(if_file);
            if_file = popen("ifconfig eth1", "r");
            if(if_file)
            {
                memset(ifconfig_raw, 0, sizeof(ifconfig_raw));
                fread(ifconfig_raw, sizeof(ifconfig_raw), sizeof(char), if_file);
                /* change eth1 to Modm */
                if(!strncmp(ifconfig_raw, "eth1", 4))
                { 
                    ifconfig_raw[0] = 'M';ifconfig_raw[1] = 'O';ifconfig_raw[2] = 'D';ifconfig_raw[3] = 'E'; ifconfig_raw[4] = 'M';
                }
            }
        }
        if(if_file)
        {
            /* convert to html */
            convert_tabs_to_table(ifconfig_raw, ifconfig + size, sizeof(ifconfig) - size);
            pclose(if_file);
        }
    }

    templateSetVar(mytemplate, "if_config", ifconfig);

    templatePrint(mytemplate);
    
    fflush(stdout);
    
    templateFreeMem(mytemplate);
}

void generate_syslog()
{
    Template *mytemplate = NULL;
    char log_raw[30000];
    char log_out[34000] = "System Log Unavailable";
    FILE * log_file;
    
    mytemplate = templateSetFile(&mytemplate, TEMPLATE_SYSLOG);
    
    if(!mytemplate)
    {
        shark__perr("Error loading logread template");
        return;
    }

    /* obtain the data to show on the web page */
    log_file = popen("logread", "r");
	if(log_file)
    {
        fread(log_raw, sizeof(log_raw), sizeof(char), log_file);
        /* convert to html */
        convert_crs_to_html(log_raw, log_out, sizeof(log_out));
        pclose(log_file);
    }

    templateSetVar(mytemplate, "logread", log_out);
    
    templatePrint(mytemplate);
    
    fflush(stdout);
    
    templateFreeMem(mytemplate);
}

void generate_home()
{
    Template *mytemplate = NULL;
    char * value;
    dictionary          *ooma_dict = 0;
    
    mytemplate = templateSetFile(&mytemplate, TEMPLATE_HOME);
    
    if(!mytemplate)
    {
        shark__perr("Error loading home template");
        return;
    }
    
    /* template variables for home
    connected
    internet
    central
    phone
    refresh_rate
    provision
    tle
    bam
        */
  	ooma_dict = iniparser_new(OOMA_MDM_CFG_FILE);
    if (ooma_dict) 
    {
	    value = iniparser_getstr(ooma_dict, "default:PROVISIONED");
        if(value && !strcmp(value, "1"))
	        templateSetVar(mytemplate, "provision", "Your phone line is configured for the ooma network");
        else
	        templateSetVar(mytemplate, "provision", "We are waiting for your phone line to be configured for the ooma network");
	    value = iniparser_getstr(ooma_dict, "default:TLE_ENABLED");
        if(value && !strcmp(value, "1"))
	        templateSetVar(mytemplate, "tle", "Enabled");
        else
	        templateSetVar(mytemplate, "tle", "Disabled, visit www.ooma.com to enable.");
	    value = iniparser_getstr(ooma_dict, "default:BAM_ENABLED");
        if(value && !strcmp(value, "1"))
	        templateSetVar(mytemplate, "bam", "Enabled");
        else
	        templateSetVar(mytemplate, "bam", "Disabled, visit www.ooma.com to enable.");
        
        iniparser_free(ooma_dict);
        ooma_dict = 0;
    }
    
  	ooma_dict = iniparser_new(OOMA_MDM_STATUS_FILE);
    if (ooma_dict) 
    {
	    value = iniparser_getstr(ooma_dict, "default:refresh_rate");
        if(value)
	        templateSetVar(mytemplate, "refresh_rate", value);
        else
	        templateSetVar(mytemplate, "refresh_rate", "3");
	    value = iniparser_getstr(ooma_dict, "default:connected");
        if(value)
	        templateSetVar(mytemplate, "connected", value);
        else
	        templateSetVar(mytemplate, "connected", "Detecting...");
	    value = iniparser_getstr(ooma_dict, "default:internet");
        if(value)
	        templateSetVar(mytemplate, "internet", value);
        else
	        templateSetVar(mytemplate, "internet", "Detecting...");
	    value = iniparser_getstr(ooma_dict, "default:central");
        if(value)
	        templateSetVar(mytemplate, "central", value);
        else
	        templateSetVar(mytemplate, "central", "Detecting...");
	    value = iniparser_getstr(ooma_dict, "default:phone");
        if(value)
	        templateSetVar(mytemplate, "phone", value);
        else
	        templateSetVar(mytemplate, "phone", "Detecting...");
        iniparser_free(ooma_dict);
    }
    else
    {
        templateSetVar(mytemplate, "refresh_rate", "3");
        templateSetVar(mytemplate, "connected", "Initializing, please wait...");
        templateSetVar(mytemplate, "internet", "Detecting...");
        templateSetVar(mytemplate, "phone", "Detecting...");
        templateSetVar(mytemplate, "central", "Detecting...");
    }
    
    templatePrint(mytemplate);
    
    fflush(stdout);
    
    templateFreeMem(mytemplate);
}
int gen_mac_address(char * class_a, char * class_b, char * class_c, char * class_d, char * class_e, char * class_f, const char * ip_in)
{
    in_addr_t addr;
    int rc;
    ooma_eth_addr_t eth_addr;
    class_a[0] = class_b[0] = class_c[0] = class_d[0] = class_e[0] = class_f[0] = 0;

    rc = util_parse_eth_addr(ip_in, &eth_addr);
    if(rc)
    {
        sprintf(class_a, "%02X", eth_addr.data[0]); 
        sprintf(class_b, "%02X", eth_addr.data[1]); 
        sprintf(class_c, "%02X", eth_addr.data[2]); 
        sprintf(class_d, "%02X", eth_addr.data[3]); 
        sprintf(class_e, "%02X", eth_addr.data[4]); 
        sprintf(class_f, "%02X", eth_addr.data[5]); 
    }
    return rc;
}

int gen_ip_address(char * class_a, char * class_b, char * class_c, char * class_d, const char * ip_in)
{
    in_addr_t addr;
    int rc = TRUE;
    class_a[0] = class_b[0] = class_c[0] = class_d[0] = 0;
	
    if(inet_aton(ip_in, &addr))
    {
        sprintf(class_a, "%d", (addr >> 24)); 
        sprintf(class_b, "%d", (addr >> 16) & 0xFF); 
        sprintf(class_c, "%d", (addr >> 8) & 0xFF); 
        sprintf(class_d, "%d", (addr) & 0xFF); 
    }    
    
    return rc;
}

int get_default_wan_mac_addr(char * mac)
{
    int rc = FALSE;
    char host_name[255];
    if(gethostname(host_name, 255) == 0)
    {
        /* the mac should be the characters 5-16 in the host name + 1*/
        int i;
        ooma_eth_addr_t eth_addr;

        strncpy(mac, &host_name[4], 2);
        mac[2] = 0;
        for(i = 6; i < 16; i+=2)
        {
            strcat(mac, ":");
            strncat(mac, &host_name[i], 2);
        }
        mac[16]++;
        /* verify that the mac is valid */
        rc = util_parse_eth_addr(mac, &eth_addr);
    }
    return rc;
}

int get_if_mac_address(const char * if_name, char * mac)
{
    int rc = FALSE;
    char host_name[255];

    /* the mac should be the characters 5-16 in the host name + 1*/
    int i;
    ooma_eth_addr_t eth_addr;
          
    struct ifreq ifr;
    int s;

    s = socket(AF_INET, SOCK_DGRAM, 0);

    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, if_name,sizeof(ifr.ifr_name));
    if(ioctl(s, SIOCGIFHWADDR, &ifr) >= 0)
    {
        sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
                (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[0],
                (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[1],
                (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[2],
                (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[3],
                (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[4],
                (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[5]);
        /* verify that the mac is valid */
        rc = util_parse_eth_addr(mac, &eth_addr);
    }
	close(s);
    return rc;
}

void generate_network()
{
    Template *mytemplate = NULL;
    char a[5], b[5], c[5], d[5], e[5], f[5];
    char default_mac[25], home_mac[25];
    char * value;
    dictionary          *ooma_dict = 0;
    
    mytemplate = templateSetFile(&mytemplate, TEMPLATE_NETWORK);
    
    if(!mytemplate)
    {
        shark__perr("Error loading network template");
        return;
    }
    
    get_default_wan_mac_addr(default_mac);
    get_if_mac_address(OOMACGI_LAN_ETH, home_mac);
#ifdef DO_SYSLOG
    //syslog(LOG_DEBUG, "default mac address %s", default_mac);
#endif
    
  	ooma_dict = iniparser_new(OOMA_NET_CFG_FILE);
    if (ooma_dict) 
    {
        /* read in all the configuration options from the isp.cfg file */
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_PPPOE_USER);
        if(value)
	        templateSetVar(mytemplate, "pppoe_username", value);
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_PPPOE_SERVICE);
        if(value)
	        templateSetVar(mytemplate, "pppoe_servicename", value);
        templateSetVar(mytemplate, "pppoe_password", UNCHANGED_PPPOE_PASSWORD);
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_IP_ADDR);
        if(value && gen_ip_address(a, b, c, d, value))
        {
            templateSetVar(mytemplate, "ip_address_a", a);
            templateSetVar(mytemplate, "ip_address_b", b);
            templateSetVar(mytemplate, "ip_address_c", c);
            templateSetVar(mytemplate, "ip_address_d", d);
        }
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_DNS1);
        if(value && gen_ip_address(a, b, c, d, value))
        {
            templateSetVar(mytemplate, "dns1_address_a", a);
            templateSetVar(mytemplate, "dns1_address_b", b);
            templateSetVar(mytemplate, "dns1_address_c", c);
            templateSetVar(mytemplate, "dns1_address_d", d);
        }
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_NETMASK);
        if(value && gen_ip_address(a, b, c, d, value))
        {
            templateSetVar(mytemplate, "netmask_a", a);
            templateSetVar(mytemplate, "netmask_b", b);
            templateSetVar(mytemplate, "netmask_c", c);
            templateSetVar(mytemplate, "netmask_d", d);
        }
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_DNS2);
        if(value && gen_ip_address(a, b, c, d, value))
        {
            templateSetVar(mytemplate, "dns2_address_a", a);
            templateSetVar(mytemplate, "dns2_address_b", b);
            templateSetVar(mytemplate, "dns2_address_c", c);
            templateSetVar(mytemplate, "dns2_address_d", d);
        }
        value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_ROUTER);
        if(value && gen_ip_address(a, b, c, d, value))
        {
            templateSetVar(mytemplate, "router_address_a", a);
            templateSetVar(mytemplate, "router_address_b", b);
            templateSetVar(mytemplate, "router_address_c", c);
            templateSetVar(mytemplate, "router_address_d", d);
        }
        templateSetVar(mytemplate, "home_built_in", home_mac);        
        templateSetVar(mytemplate, "built_in", default_mac);        
        value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_WAN_ETH_ADDR);
        if(!value || !gen_mac_address(a, b, c, d, e, f, value) || !strlen(value))
        {
            char current_value[25];
            get_if_mac_address(OOMACGI_WAN_ETH, current_value);
            templateSetVar(mytemplate, "automatic_mac", "2\" CHECKED align=\"undefined");        
            templateSetVar(mytemplate, "default_mac", "1\" align=\"undefined");        
            templateSetVar(mytemplate, "override_mac", "0\" align=\"undefined");        
            templateSetVar(mytemplate, "automatic_value", current_value);        
        }
        else if (!strcmp(value, default_mac))
        {
            templateSetVar(mytemplate, "automatic_mac", "2\" align=\"undefined");        
            templateSetVar(mytemplate, "default_mac", "1\" CHECKED align=\"undefined");        
            templateSetVar(mytemplate, "override_mac", "0\" align=\"undefined");        
            templateSetVar(mytemplate, "automatic_value", "");        
        }
        else
        {
            templateSetVar(mytemplate, "automatic_mac", "2\" align=\"undefined");        
            templateSetVar(mytemplate, "default_mac", "1\" align=\"undefined");        
            templateSetVar(mytemplate, "override_mac", "0\" CHECKED align=\"undefined");        
            templateSetVar(mytemplate, "automatic_value", "");        
            templateSetVar(mytemplate, "mac_a", a);
            templateSetVar(mytemplate, "mac_b", b);
            templateSetVar(mytemplate, "mac_c", c);
            templateSetVar(mytemplate, "mac_d", d);
            templateSetVar(mytemplate, "mac_e", e);
            templateSetVar(mytemplate, "mac_f", f);
        }
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_PROTO);
        if(value && !strcmp(value, NETMGR_PROTO_STATIC_STR))
        {
            templateSetVar(mytemplate, "static", NETMGR_PROTO_STATIC_STR "\" selected=\"true");        
            templateSetVar(mytemplate, "dhcp", NETMGR_PROTO_DHCP_STR);        
            templateSetVar(mytemplate, "pppoe", NETMGR_PROTO_PPPOE_STR);        
            templateSetVar(mytemplate, "auto", NETMGR_PROTO_AUTO_STR);        
        }
        else if(value && !strcmp(value, NETMGR_PROTO_DHCP_STR))
        {
            templateSetVar(mytemplate, "static", NETMGR_PROTO_STATIC_STR);        
            templateSetVar(mytemplate, "dhcp", NETMGR_PROTO_DHCP_STR "\" selected=\"true");        
            templateSetVar(mytemplate, "pppoe", NETMGR_PROTO_PPPOE_STR);        
            templateSetVar(mytemplate, "auto", NETMGR_PROTO_AUTO_STR);        
        }
        else if(value && !strcmp(value, NETMGR_PROTO_PPPOE_STR))
        {
            templateSetVar(mytemplate, "static", NETMGR_PROTO_STATIC_STR);        
            templateSetVar(mytemplate, "dhcp", NETMGR_PROTO_DHCP_STR);        
            templateSetVar(mytemplate, "pppoe", NETMGR_PROTO_PPPOE_STR "\" selected=\"true");        
            templateSetVar(mytemplate, "auto", NETMGR_PROTO_AUTO_STR);        
        }
        else
        {
            templateSetVar(mytemplate, "static", NETMGR_PROTO_STATIC_STR);        
            templateSetVar(mytemplate, "dhcp", NETMGR_PROTO_DHCP_STR);        
            templateSetVar(mytemplate, "pppoe", NETMGR_PROTO_PPPOE_STR);        
            templateSetVar(mytemplate, "auto", NETMGR_PROTO_AUTO_STR "\" selected=\"true");        
        }
        iniparser_free(ooma_dict);
    }
    
    templatePrint(mytemplate);
    
    fflush(stdout);
    
    templateFreeMem(mytemplate);
}

void generate_phone()
{
    Template *mytemplate = NULL;
    char ext_data[1000] = "Unavailable";
    char cmd[256];
    FILE * ext_app;
    int read;
    
    mytemplate = templateSetFile(&mytemplate, TEMPLATE_PHONE);
    
    if(!mytemplate)
    {
        shark__perr("Error loading phone template");
        return;
    }

    sprintf(cmd, "cat %s | grep MY_PHONE | sed 's/MY_PHONE=//'", OOMA_MDM_CFG_FILE);
    ext_app = popen(cmd, "r");
	if(ext_app)
    {
        read = fread(ext_data, sizeof(char), sizeof(ext_data), ext_app);
        ext_data[read] = 0;
        templateSetVar(mytemplate, "phone_number", ext_data);
        pclose(ext_app);
    }
    else
    {
        templateSetVar(mytemplate, "phone_number", "Unavailable (2)");
    }
    
    templatePrint(mytemplate);
    
    fflush(stdout);
    
    templateFreeMem(mytemplate);
}


void get_log_level(dictionary * ooma_dict, char * param, char * template, Template * mytemplate)
{
    char * value;
    
    value = iniparser_getstr(ooma_dict, param);
    if(value)
    {
        templateSetVar(mytemplate, template, value);
    }
    else
    {
        /* set default trace level */
        templateSetVar(mytemplate, template, DEFAULT_TRACE_LEVEL);
    }
}


void generate_logging()
{
    Template *mytemplate = NULL;
    dictionary          *ooma_dict = 0;
    
    mytemplate = templateSetFile(&mytemplate, TEMPLATE_LOGGING);
    
    if(!mytemplate)
    {
        shark__perr("Error loading diags template");
        return;
    }
    
    ooma_dict = iniparser_new(OOMA_TRACE_CFG_FILE);

    if (ooma_dict) 
    {
        /* read in all the configuration options from the isp.cfg file */
	    get_log_level(ooma_dict, "default:mdm", "mdm_trace_level", mytemplate);
    	get_log_level(ooma_dict, "default:openvpn", "vpn_trace_level", mytemplate);
    	get_log_level(ooma_dict, "default:provisioning", "prov_trace_level", mytemplate);
    	get_log_level(ooma_dict, "default:opm", "opm_trace_level", mytemplate);
    	get_log_level(ooma_dict, "default:netmgr", "netmgr_trace_level", mytemplate);
        iniparser_free(ooma_dict);
    }
    templatePrint(mytemplate);
    
    fflush(stdout);
    
    templateFreeMem(mytemplate);
}

int add_fwd_list_item (char *value, int index, char * output)
{
	/* parse the forward line */
	char * end, * port_nat;
	int port_nat_val = 0;
	char * start = value;
    char a[5], b[5], c[5], d[5], * port, * tmp;
	int i = index + 1;
	char row[300];
	char type[20];

#define PF_ROW_TEMPLATE "%d</td><td>%s</td><td>%s</td><td>%s.%s.%s.%s</td><td><input name=\"select_rule\" type=\"checkbox\" value=\"%d\" />"
#define PF_ROW_TEMPLATE_WITH_PORT_NAT "%d</td><td>%s</td><td>%s</td><td>%s.%s.%s.%s:%d</td><td><input name=\"select_rule\" type=\"checkbox\" value=\"%d\" />"
	
	/* filter string has format address:port:protocol
		e.g. 172.27.35.22:80:tcp */
	
	/* get the address */
	end = strchr(start, NETMGR_PARAM_SEPARATOR_CHAR);
	if(!end)
	{
		return FALSE;
	}
	*end = 0;
	/* see if there is a port NAT as well */
	if((port_nat = strchr(start, ',')) != NULL)
	{
		*port_nat = 0;
		port_nat++;
		port_nat_val = atoi(port_nat);
	}
	if(!gen_ip_address(a, b, c, d, start))
	{
		return FALSE;
	}
	start = end + 1;
	
	/* get the port */
	end = strchr(start, NETMGR_PARAM_SEPARATOR_CHAR);
	if(!end)
	{
		return FALSE;
	}
	*end = 0;
	port = start;	
	/* if it is a range replace the comma with a - */
	if((tmp = strchr(port, ',')) != NULL)
	{
		*tmp = '-';
	}
	
	start = end + 1;
		
	/* get the protocol */
	if(!strcasecmp(start, "tcp"))
	{
		strcpy(type, "TCP");
	}
	else if(!strcasecmp(start, "udp"))
	{
		strcpy(type, "UDP");
	}
	else if(!strcasecmp(start, "both"))
	{
		strcpy(type, "TCP & UDP");
	}
	else
	{	
		return FALSE;
	}

	if(port_nat_val)
	{
		sprintf(row, PF_ROW_TEMPLATE_WITH_PORT_NAT, i, port, type, a, b, c, d, port_nat_val, i);
	}
	else
	{
		sprintf(row, PF_ROW_TEMPLATE, i, port, type, a, b, c, d, i);
	}
	strcat(output, row);
	
	return TRUE;
}


void generate_lan()
{
    Template *mytemplate = NULL;
    char a[5], b[5], c[5], d[5], e[5], f[5], g[5], h[5];
    char * value;
    dictionary          *ooma_dict = 0;
	int i;
    
    mytemplate = templateSetFile(&mytemplate, TEMPLATE_LAN);
    
    if(!mytemplate)
    {
        shark__perr("Error loading lan template");
        return;
    }
    
	ooma_dict = iniparser_new(OOMA_NET_CFG_FILE);
    if (ooma_dict) 
    {
        /* read in all the configuration options from the netmgr.cfg file */
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_LAN_IP_ADDR);
        if(!value || !gen_ip_address(a, b, c, d, value))
        {
			/* set defaults */
			gen_ip_address(a, b, c, d, util_in_addr_to_str(NETMGR_DEFAULT_LAN_ADDR));
		}	
		templateSetVar(mytemplate, "ip_address_a", a);
		templateSetVar(mytemplate, "ip_address_b", b);
		templateSetVar(mytemplate, "ip_address_c", c);
		templateSetVar(mytemplate, "ip_address_d", d);

		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_LAN_NETMASK);
        if(!value || !gen_ip_address(a, b, c, d, value))
        {
			/* set defaults */
			gen_ip_address(a, b, c, d, util_in_addr_to_str(NETMGR_DEFAULT_LAN_NETMASK));
		}	
		templateSetVar(mytemplate, "netmask_a", a);
		templateSetVar(mytemplate, "netmask_b", b);
		templateSetVar(mytemplate, "netmask_c", c);
		templateSetVar(mytemplate, "netmask_d", d);
		
		/* extract the dhcp range from the config value */
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_DHCP_ADDR_RANGE);
		if(value)
		{
			char start[50];
			char * end;

		    end = strchr(value, NETMGR_SEPARATOR_CHAR);
			if(end)
			{
                                memset(start, 0, sizeof(start));

				strncpy(start, value, end - value);
				end++;
//				syslog(LOG_DEBUG, "dhcp start %s", start);

				if(!gen_ip_address(a, b, c, d, start) || !gen_ip_address(e, f, g, h, end))
				{
					value = 0;
				}
			}
			else
			{
				value = 0;
			}
		}
        if(!value)
        {
			/* set defaults */
			gen_ip_address(a, b, c, d, util_in_addr_to_str(NETMGR_DEFAULT_DHCP_START));
			gen_ip_address(e, f, g, h, util_in_addr_to_str(NETMGR_DEFAULT_DHCP_STOP));
		}	
		templateSetVar(mytemplate, "dhcp_start_addr_a", a);
		templateSetVar(mytemplate, "dhcp_start_addr_b", b);
		templateSetVar(mytemplate, "dhcp_start_addr_c", c);
		templateSetVar(mytemplate, "dhcp_start_addr_d", d);
		templateSetVar(mytemplate, "dhcp_end_addr_a", e);
		templateSetVar(mytemplate, "dhcp_end_addr_b", f);
		templateSetVar(mytemplate, "dhcp_end_addr_c", g);
		templateSetVar(mytemplate, "dhcp_end_addr_d", h);
		
		/* set the DMZ if present in the configuration */
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_DMZ);
        if(value && gen_ip_address(a, b, c, d, value))
        {
            templateSetVar(mytemplate, "dmz_addr_a", a);
            templateSetVar(mytemplate, "dmz_addr_b", b);
            templateSetVar(mytemplate, "dmz_addr_c", c);
            templateSetVar(mytemplate, "dmz_addr_d", d);
        }
		
		i = 0;
		/* set the port forward settings (if any) */
		value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_PORT_FWRD_LIST);
        if(value && strlen(value))
		{
			char filter[150];
			char * start = (char *) value;
			char * end;
			char pf_table[NUM_PORT_FORWARD_RULES * 60] = "";
				
			do
			{
				memset(filter, 0, sizeof(filter));
				end = strchr(start, NETMGR_SEPARATOR_CHAR);
				if(end)
				{
					strncpy(filter, start, end - start);
				}	
				else
				{
					strncpy(filter, start, sizeof(filter));
				}
				if(!add_fwd_list_item(filter, i, pf_table))
				{
					break;
				}
				if(end)
				{
					strcat(pf_table, "</td></tr>\n<tr><td>");
				}
				i++;
				start = end + 1;
			}
			while(end);

			templateSetVar(mytemplate, "port_forward_routes", pf_table);
		}
		else
		{
			templateSetVar(mytemplate, "port_forward_routes", "None</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;");
		}
		
        iniparser_free(ooma_dict);
	}

	ooma_dict = iniparser_new(OOMA_QOS_CFG_FILE);
    if (ooma_dict) 
    {
		char * value;
		
		value = iniparser_getstr(ooma_dict, NETMGR_QOS_EGRESS_BW);
        if(value)
		{
	        templateSetVar(mytemplate, "up_speed", value);
		}
		else
		{
			char temp_val[10];

			sprintf(temp_val, "%d", NETMGR_QOS_EGRESS_BW_DEFAULT);
	        templateSetVar(mytemplate, "up_speed", temp_val);
		}
		value = iniparser_getstr(ooma_dict, NETMGR_QOS_INGRESS_BW);
        if(value)
		{
	        templateSetVar(mytemplate, "down_speed", value);
		}
		else
		{
			char temp_val[10];

			sprintf(temp_val, "%d", NETMGR_QOS_INGRESS_BW_DEFAULT);
	        templateSetVar(mytemplate, "down_speed", "0");
		}
        iniparser_free(ooma_dict);
	}
	
    templatePrint(mytemplate);
    
    fflush(stdout);
    
    templateFreeMem(mytemplate);
}

#define INVALID_DHCP_START_ADDR  1
#define INVALID_DHCP_END_ADDR    2
#define INVALID_DMZ_ADDRESS      3
#define INVALID_DHCP_END_ADDR_LOWER 4
#define INVALID_IP_IN_DHCP_RANGE    5
char *str_addr[] = {"Unknown", "DHCP start address", "DHCP end address", "DMZ address"};
void update_lan_add_port_forward_button()
{
	/* display the add rule page */
    Template *mytemplate = NULL;
    mytemplate = templateSetFile(&mytemplate, TEMPLATE_ADD_PORT_FORWARD);

    if(!mytemplate)
    {
        shark__perr("Error loading status template");
        return;
    }

    templatePrint(mytemplate);

    fflush(stdout);

    templateFreeMem(mytemplate);
}

void update_add_port_forward_rule()
{
    FILE * ini_file;
    dictionary          *ooma_dict = 0;
	char port_forward[200] = "";

	char port[25];
	char addr[25];
	char * port_num;
	char * type;
	int start_port_val, end_port_val, translate_port;
	int ip_val, lIpAddr = 0, lNetmask = 0;
	
	/* get the home ip address and subnet for validation */					
    ooma_dict = iniparser_new(OOMA_NET_CFG_FILE);
    if (ooma_dict)
    {
		char * value;
		int count = 1;
        iniparser_setstr(ooma_dict, "default", NULL);

		iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_PORT_FWRD_LIST);
        if(value && strlen(value))
		{
			/* check to see if we have the max rules already */
			while((value = strchr(value, NETMGR_SEPARATOR_CHAR)) != NULL)
			{
				count++;
			}
		}

		if(count >= NUM_PORT_FORWARD_RULES)
		{
       	 	char err_str[512];
       		sprintf(err_str, "<big> Maximum number of rules, %d, reached, delete some before adding any more.<BR><BR>"
        	        "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n", NUM_PORT_FORWARD_RULES);
    	    shark__perr(err_str);
			iniparser_free(ooma_dict);
	        return;
		}

        value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_LAN_IP_ADDR);
		if(value)
		{
			lIpAddr = inet_addr(value);
		}
        value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_LAN_NETMASK);
		if(value)
		{
			lNetmask = inet_addr(value);
		}

        iniparser_free(ooma_dict);
    }

	type = getenv("sharkg_protocol_type");
	if(strcmp(type, "tcp") && strcmp(type, "udp") && strcmp(type, "both"))
	{
		char err_str[512];
		sprintf(err_str, "<big> Bad protocol %s.<BR> Choose a valid protocol.<br><br>"
				"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n", type);
		shark__perr(err_str);
		return;
	}
	
	if(!get_ip_address("Add Port Forward", "ip_address_a", "ip_address_b", "ip_address_c", "ip_address_d", addr, "lan"))
		return;
	
    /* get the translate port value and validate */
	port_num = getenv("sharkg_translate_port");
	translate_port = atoi(port_num);
	if(!is_number_only(port_num, 65534))
	{
		char err_str[512];
		sprintf(err_str, "<big> Forward Port value is invalid.<BR> Enter a port that contains digits 0-9 only and is between 1 and 65534.<br><br>"
					"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");    
		shark__perr(err_str);
		return;
	}
	
	/* get the start port value and validate */
	port_num = getenv("sharkg_start_port");
	start_port_val = atoi(port_num);
	if(!is_number_only(port_num, 65534) || (start_port_val < 1))
	{
		char err_str[512];
		sprintf(err_str, "<big> Start Port value is invalid.<BR> Enter a port that contains digits 0-9 only and is between 1 and 65534.<br><br>"
					"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");    
		shark__perr(err_str);
		return;
	}

	port_num = getenv("sharkg_end_port");
	end_port_val = atoi(port_num);
	if(!is_number_only(port_num, 65534))
	{
		char err_str[512];
		sprintf(err_str, "<big> End Port value is invalid.<BR> Enter a port that contains digits 0-9 only and is between 1 and 65534.<br><br>"
					"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");    
		shark__perr(err_str);
		return;
	}

	/* check the forward ip address is in the home subnet */
	if (addr[0] != 0) {
	    inet_pton(AF_INET, addr, &ip_val);
	    if ((lIpAddr&lNetmask) != (ip_val&lNetmask)) {
		char err_str[512];
		sprintf(err_str, "<big> The Forwarding Address must be on the Home subnet.<br><br>"
	                "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");
                       shark__perr(err_str);
                       return;
	    }
	}

	if(end_port_val && (end_port_val < start_port_val))
	{
		char err_str[512];
		sprintf(err_str, "<big> End Port must be blank or higher then the Start Port value..<br><br>"
					"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");    
		shark__perr(err_str);
		return;
	}

	if((start_port_val == 1194) || (start_port_val >= 49000 && start_port_val < 50000))
	{
		char err_str[512];
		sprintf(err_str, "<big> Start Port value is using a reserved port.<BR> Ooma uses ports 1194 and 49000-49999 for your telephone.<br><br>"
			"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");    
		shark__perr(err_str);
		return;
	}

	if(end_port_val == start_port_val)
	{
		end_port_val = 0;
	}

	if(end_port_val)
	{
		if(((start_port_val < 1194) && (end_port_val >= 1194)) || 
           ((start_port_val < 49000 && end_port_val >= 49000)))
		{
			char err_str[512];
			sprintf(err_str, "<big> The port range is using reserved ports.<BR> Ooma uses ports 1194 and 49000-49999 for your telephone.<br><br>"
				"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");    
			shark__perr(err_str);
			return;
		}
	}

	/* create the rule */
	if(end_port_val && translate_port)
	{
		sprintf(port_forward, "%s,%d%c%d,%d%c%s", addr, translate_port, NETMGR_PARAM_SEPARATOR_CHAR, start_port_val, end_port_val, NETMGR_PARAM_SEPARATOR_CHAR, type);
	}
	else if(end_port_val)
	{
		sprintf(port_forward, "%s%c%d,%d%c%s", addr, NETMGR_PARAM_SEPARATOR_CHAR, start_port_val, end_port_val, NETMGR_PARAM_SEPARATOR_CHAR, type);
	}
	else if(translate_port)
	{
		sprintf(port_forward, "%s,%d%c%d%c%s", addr, translate_port, NETMGR_PARAM_SEPARATOR_CHAR, start_port_val, NETMGR_PARAM_SEPARATOR_CHAR, type);
	}
	else
	{
		sprintf(port_forward, "%s%c%d%c%s", addr, NETMGR_PARAM_SEPARATOR_CHAR, start_port_val, NETMGR_PARAM_SEPARATOR_CHAR, type);
	}

    ooma_dict = iniparser_new(OOMA_NET_CFG_FILE);
    if (ooma_dict)
    {
		char new_port_forward[NUM_PORT_FORWARD_RULES * 40] = "";
		char * value;

        iniparser_setstr(ooma_dict, "default", NULL);

        value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_PORT_FWRD_LIST);
        if(value && strlen(value))
		{
			sprintf(new_port_forward, "%s%c", value, NETMGR_SEPARATOR_CHAR);
		}
		
		strcat(new_port_forward, port_forward);

        iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_PORT_FWRD_LIST, new_port_forward);

        ini_file = fopen(OOMA_NET_CFG_FILE, "w");
        iniparser_dump_ini(ooma_dict, ini_file);
        fclose(ini_file);
        iniparser_free(ooma_dict);
    }

    send_netmgr_reconfig();

    printf("Content-Type: text/html\r\n\r\n"
           "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
           "<HTML><HEAD>\n"
           "<TITLE>Lan Parameters Updated</TITLE>\n"
           "</HEAD><BODY>\n"
           "<H1>Routes Added OK!</H1> <BR>"
           "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Configuration</a>\n"
           "<HR>\n"
           "</BODY></HTML>\n");
    fflush(stdout);
}

void update_lan_delete_selected_button()
{
	int deleted_rules[NUM_PORT_FORWARD_RULES];
	char rule_name[25], new_port_forward[NUM_PORT_FORWARD_RULES * 40];
	int i, j, num_rules;
    FILE * ini_file;
    dictionary          *ooma_dict = 0;

	if(!getenv("sharkg_select_rule"))
	{
        shark__perr("<big> No rules selected for deletion!.<br><br>"
            "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");
        return;
	}
	memset(deleted_rules, 0, sizeof(deleted_rules));

	deleted_rules[0] = atoi(getenv("sharkg_select_rule"));

	num_rules = 1;
	do
	{	
		sprintf(rule_name, "sharkg_select_rule%d", num_rules + 1);
		if(!getenv(rule_name))
		{
			break;
		}
		deleted_rules[num_rules] = atoi(getenv(rule_name));
		num_rules++;
	}
	while(num_rules < NUM_PORT_FORWARD_RULES);

    ooma_dict = iniparser_new(OOMA_NET_CFG_FILE);
    if (ooma_dict)
    {
		char * value;
        /* set all the configuration options from the isp.cfg file */
        iniparser_setstr(ooma_dict, "default", NULL);

		/* go through the list deleting the selected rules */
		memset(new_port_forward, 0, sizeof(new_port_forward));
		
        value = iniparser_getstr(ooma_dict, NETMGR_CFG_KEY_PORT_FWRD_LIST);
        if(value && strlen(value))
        {
            char * start = (char *) value;
            char * end;
			int count = 1;
			int skip;
			int i = 0;

            do
            {
                end = strchr(start, NETMGR_SEPARATOR_CHAR);
				/* see if this is one of the rules being deleted */
				skip  = 0;
				for(i = 0; i < num_rules; i++)
				{
					if(deleted_rules[i] == count)
					{
						skip = 1;
						break;
					}
				}
				if(!skip)
				{
                	if(end)
         	       {
            	    	if(strlen(new_port_forward))
                		{
                    		new_port_forward[strlen(new_port_forward)] = NETMGR_SEPARATOR_CHAR;
	                	}
    	                strncat(new_port_forward, start, end - start);
        	        }
            	    else
                	{
                		if(strlen(new_port_forward))
	                	{
                    		new_port_forward[strlen(new_port_forward)] = NETMGR_SEPARATOR_CHAR;
        	        	}
            	        strcat(new_port_forward, start);
                	}
				}
                count++;
                start = end + 1;
            }
            while(end);
        }

        if(strlen(new_port_forward))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_PORT_FWRD_LIST, new_port_forward);
        else iniparser_unset(ooma_dict, NETMGR_CFG_KEY_PORT_FWRD_LIST);

        ini_file = fopen(OOMA_NET_CFG_FILE, "w");
        iniparser_dump_ini(ooma_dict, ini_file);
        fclose(ini_file);
        iniparser_free(ooma_dict);
    }

	
    send_netmgr_reconfig();
    
    printf("Content-Type: text/html\r\n\r\n"
           "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
           "<HTML><HEAD>\n"
           "<TITLE>Lan Parameters Updated</TITLE>\n"
           "</HEAD><BODY>\n"
           "<H1>Routes Deleted OK!</H1> <BR>"
           "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Configuration</a>\n"
           "<HR>\n"
           "</BODY></HTML>\n");
    fflush(stdout);

}

void update_lan_update_button()
{
	char ip_addr[25] = "";
    char netmask[25] = "";
    char dhcp_start[25] = "";
    char dhcp_end[25] = "";
    char dmz[25] = "";
	char up_speed[25] = "";
	char down_speed[25] = "";
	int i;
    char flag = 0;
    long lIpAddr=0, lNetmask=0, lDhcpStart=0, lDhcpEnd=0, lDmz=0;
	
    FILE * ini_file;
    dictionary          *ooma_dict = 0;
	
    if(!get_ip_address("IP Address", "ip_address_a", "ip_address_b", "ip_address_c", "ip_address_d", ip_addr, "lan") ||
 	   !get_ip_address("Netmask", "netmask_a", "netmask_b", "netmask_c", "netmask_d", netmask, "lan") ||
 	   !get_ip_address("DHCP Start Address", "dhcp_start_addr_a", "dhcp_start_addr_b", "dhcp_start_addr_c", "dhcp_start_addr_d", dhcp_start, "lan") ||
	   !get_ip_address("DHCP End Address", "dhcp_end_addr_a", "dhcp_end_addr_b", "dhcp_end_addr_c", "dhcp_end_addr_d", dhcp_end, "lan") ||
       !get_ip_address("DMZ Address", "dmz_addr_a", "dmz_addr_b", "dmz_addr_c", "dmz_addr_d", dmz, "lan"))
    {
        return;
    } 
   
    if (ip_addr[0] != 0) inet_pton(AF_INET, ip_addr, &lIpAddr);
    if (netmask[0] != 0) inet_pton(AF_INET, netmask, &lNetmask);
    if (dhcp_start[0] != 0) inet_pton(AF_INET, dhcp_start, &lDhcpStart);
    if (dhcp_end[0] != 0) inet_pton(AF_INET, dhcp_end, &lDhcpEnd);
    if (dmz[0] != 0) inet_pton(AF_INET, dmz, &lDmz);

    if (!is_valid_mask(lNetmask)) {
        shark__perr("<big> The Netmask is Invalid.<br><br>"
	   	    "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");
	return;
    }

    /* check all ip address setting at the same subnet */
    if (lDhcpStart > lDhcpEnd) flag = INVALID_DHCP_END_ADDR_LOWER;
    else if (lIpAddr>=lDhcpStart && lIpAddr<=lDhcpEnd) flag = INVALID_IP_IN_DHCP_RANGE;
    else if ((lIpAddr&lNetmask) != (lDhcpStart&lNetmask)) flag = INVALID_DHCP_START_ADDR;
    else if ((lIpAddr&lNetmask) != (lDhcpEnd&lNetmask)) flag = INVALID_DHCP_END_ADDR;
    else if (dmz[0] != 0 && (lIpAddr&lNetmask) != (lDmz&lNetmask)) flag = INVALID_DMZ_ADDRESS;

    if (flag) {
	char err_str[512];
	if (flag == INVALID_DHCP_END_ADDR_LOWER) {
            sprintf(err_str, "<big>DHCP Start Address is higher than End Address.<br><br>"
		"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");
	} else if (flag == INVALID_IP_IN_DHCP_RANGE) {
            sprintf(err_str, "<big>Home IP Address is in DHCP address range.<br><br>"
		"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");
	} else {
            sprintf(err_str, "<big>Home IP Address and DHCP range are not in the same subnet.<br><br>"
		"<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");
	}
        shark__perr(err_str);
	return;
    }
	
	/* get the speed parameters */
	
    /* end of add */
	
    ooma_dict = iniparser_new(OOMA_NET_CFG_FILE);
    if (ooma_dict) 
    {
        /* set all the configuration options from the isp.cfg file */
        iniparser_setstr(ooma_dict, "default", NULL);

        if(strlen(ip_addr))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_LAN_IP_ADDR, ip_addr);
        if(strlen(netmask))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_LAN_NETMASK, netmask);
        if(strlen(dhcp_start) && strlen(dhcp_end))
        {
            char dhcp[50];
            sprintf(dhcp, "%s%c%s", dhcp_start, NETMGR_SEPARATOR_CHAR, dhcp_end);
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_DHCP_ADDR_RANGE, dhcp);
        }
        if(strlen(dmz))
            iniparser_setstr(ooma_dict, NETMGR_CFG_KEY_DMZ, dmz);
	    else iniparser_unset(ooma_dict, NETMGR_CFG_KEY_DMZ);
		
        ini_file = fopen(OOMA_NET_CFG_FILE, "w");
        iniparser_dump_ini(ooma_dict, ini_file);
        fclose(ini_file);
        iniparser_free(ooma_dict);
    }

	ooma_dict = iniparser_new(OOMA_QOS_CFG_FILE);
    if (ooma_dict) 
    {
		/* stip non-numeric chars */
		if(getenv("sharkg_up_speed"))
			sprintf(up_speed, "%d", atoi(getenv("sharkg_up_speed")));
		if(getenv("sharkg_down_speed"))
			sprintf(down_speed, "%d", atoi(getenv("sharkg_down_speed")));
		
        /* get all the configuration options from the existing file */
        iniparser_setstr(ooma_dict, "default", NULL);
		
		iniparser_setstr(ooma_dict, NETMGR_QOS_EGRESS_BW, up_speed);
		iniparser_setstr(ooma_dict, NETMGR_QOS_INGRESS_BW, down_speed);

        ini_file = fopen(OOMA_QOS_CFG_FILE, "w");
        iniparser_dump_ini(ooma_dict, ini_file);
        fclose(ini_file);
        iniparser_free(ooma_dict);
    }
    
    send_netmgr_reconfig();

	printf("Content-Type: text/html\r\n\r\n"
           "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
           "<HTML><HEAD>\n"
           "<TITLE>Lan Parameters Updated</TITLE>\n"
           "</HEAD><BODY>\n"
           "<H1>Home Network Parameters Updated OK!</H1> <BR> If you changed your Home IP Address you may need to restart your computer or router to get your internet connection back. <BR><BR>"
           "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Configuration</a>\n"
           "<HR>\n"
           "</BODY></HTML>\n");
    fflush(stdout);
	
}

void update_lan()
{
	if(getenv("sharkg_add"))
	{
		update_lan_add_port_forward_button();
	}
	else if(getenv("sharkg_delete"))
	{
		update_lan_delete_selected_button();
	}
	else if(getenv("sharkg_update"))
	{
		update_lan_update_button();
	}
	else
	{
        shark__perr("<big> Internal error, bad submit ID.<br><br>"
            "<a href=\"/cgi-bin/ooma_cgi.cgi?makepage=lan\" target=\"_self\">Return to Home Network Settings</a></big>\n");
	}
}

