struct notifywatch_struct *lookup_watch_ctr(unsigned int ctr)
{
    unsigned int hashvalue=calculate_ctr_hash(ctr);
    void *index=NULL;
    struct notifywatch_struct *watch=NULL;

    watch=(struct notifywatch_struct *) get_next_element(&group_watches_ctr, &index, hashvalue);

    while(watch) {

	if (watch->ctr==ctr) break;
	watch=(struct notifywatch_struct *) get_next_element(&group_watches_ctr, &index, hashvalue);

    }

    return watch;

}
struct notifywatch_struct *lookup_watch_inode(struct inode_struct *inode)
{
    unsigned int hashvalue=calculate_inode_hash(inode);
    void *index=NULL;
    struct notifywatch_struct *watch=NULL;

    watch=(struct notifywatch_struct *) get_next_element(&group_watches_inode, &index, hashvalue);

    while(watch) {

	if (watch->inode==inode) break;
	watch=(struct notifywatch_struct *) get_next_element(&group_watches_inode, &index, hashvalue);

    }

    return watch;

}
static struct inotify_watch_struct *lookup_inotify_watch_wd(unsigned int wd)
{
    unsigned int hashvalue=calculate_wd_hash(wd);
    void *index=NULL;
    struct inotify_watch_struct *inotify_watch=NULL;

    inotify_watch=(struct inotify_watch_struct *) get_next_element(&group_watches_inotify, &index, hashvalue);

    while(inotify_watch) {

	if (inotify_watch->wd==wd) break;
	inotify_watch=(struct inotify_watch_struct *) get_next_element(&group_watches_inotify, &index, hashvalue);

    }

    return inotify_watch;

}
static struct resource_struct *get_next_ftp_noname(struct resource_struct *p, unsigned char type, void **index, unsigned char (*select_fn)(struct resource_struct *p, struct resource_struct *r, char *name, unsigned char type))
{
    struct resource_struct *r=NULL;

    if (type==FTP_TYPE_NETWORK) {

	/* there is one ftp network resource for all net workspaces/users */

	r=&ftp_network_resource;

    } else if (type==FTP_TYPE_SERVER) {
	int hashvalue=0;

	while(hashvalue<server_list.len && ! r) {

	    /* lookup in workgroup list */

	    r=get_next_element(&server_list, index, hashvalue);

	    while(r) {

		if (select_fn(p, r, NULL, type)==1) break;
		r=get_next_element(&server_list, index, hashvalue);

	    }

	    if (!r) {

		/* jump to the next hash */

		*index=NULL;
		hashvalue++;

	    } else {

		break;

	    }

	}

    }

    return r;


struct resource_struct *get_next_ftp(struct resource_struct *p, char *name, unsigned char type, void **index, unsigned char (*select_fn)(struct resource_struct *p, struct resource_struct *r, char *name, unsigned char type))
{
    struct resource_struct *r=NULL;

    if (! select_fn) select_fn=default_select_fn;

    if (! name) {

	r=get_next_ftp_noname(p, type, index, select_fn);
	goto out;

    }

    if (type==FTP_TYPE_NETWORK) {

	/* there is one smb network resource for all net workspaces/users */

	r=&ftp_network_resource;

    } else if (type==FTP_TYPE_SERVER) {
	int hashvalue;

	hashvalue=calculate_ftp_hash(name);

	/* lookup in server list */

	r=get_next_element(server_list, &index, hashvalue);

	while(r) {

	    if (select_fn(p, r, name, type)==1) break;
	    r=get_next_element(server_list, index, hashvalue);

	}

    }

    out:

    return r;

}

int ftp_groupadd(struct resource_struct *resource)
{

    if (resource->type==FTP_TYPE_SERVER) {

	/* add resource to servers */

	add_element_to_group(&server_list, (void *) resource);

    }

    return 0;

}

int smb_groupremove(struct resource_struct *resource)
{

     if (resource->type==FTP_TYPE_SERVER) {

	/* remove resource from servers */

	remove_element_from_group(&server_list, (void *) resource);

    }

    return 0;

}

static struct group_calls_struct ftp_group_calls={
	.find_role		= find_role_ftp,
	.readrecord		= NULL,
	.init			= NULL,
	.add			= NULL,
	.change			= NULL,
	.remove			= NULL,
	.close			= NULL,
	.get_next		= get_next_ftp,
	.groupadd		= ftp_groupadd,
	.groupremove		= ftp_groupremove,
	.lock			= NULL,
	.unlock			= NULL,
};

void add_group_ftp()
{
    int res=0;

    init_resource_group(&ftp_resource_group);
    add_resource_group(RESOURCE_GROUP_FTP, &ftp_resource_group, &ftp_group_calls);

    create_ftp_network_resource();

    res=initialize_group(server_list, server_hashfunction, 256);

    /* read the config */

    read_ftp_config();

    /* init ftp network role */

    snprintf(ftp_network_role.name, 128, "remote.net.ftp.network");

    ftp_network_role.directory_file=NULL;

    ftp_network_role.group=RESOURCE_GROUP_FTP;
    ftp_network_role.type=FTP_TYPE_NETWORK;

    add_role_simple(&ftp_network_role);

    /* init ftp server role */

    snprintf(ftp_server_role.name, 128, "remote.net.ftp.server");

    ftp_server_role.directory_file=NULL;

    ftp_server_role.group=RESOURCE_GROUP_FTP;
    ftp_server_role.type=FTP_TYPE_SERVER;

    add_role_simple(&ftp_server_role);

}
void handle_stlv_packet(unsigned char* packet)
{
    stlv_packet pack = packet;
    char type_buf[MAX_ELEMENT_TYPE_BUFSIZE];

    element_handle handle = get_first_element(pack);
    while (IS_VALID_STLV_HANDLE(handle))
    {
        int type_len = get_element_type(pack, handle, type_buf, sizeof(type_buf));
        log_info("Read Element: %x\n", type_buf[0]);
        switch (type_buf[0])
        {
        case ELEMENT_TYPE_ECHO:
            {
                int data_len = get_element_data_size(pack, handle, type_buf, type_len);
                unsigned char* data = get_element_data_buffer(pack, handle, type_buf, type_len);
                log_info("echo: ");
                print_stlv_string(data, data_len);
                log_info("\n");
                handle_echo(data, data_len);
            }
            break;

        case ELEMENT_TYPE_CLOCK:
            {
                int data_len = get_element_data_size(pack, handle, type_buf, type_len);
                unsigned char* data = get_element_data_buffer(pack, handle, type_buf, type_len);
                log_info("clock: %d/%d/%d %d:%d:%d\n",
                    (int)data[0], (int)data[1], (int)data[2], (int)data[3], (int)data[4], (int)data[5]);
                handle_clock(data[0], data[1], data[2], data[3], data[4], data[5]);
                if (data_len >= 8)
                    handle_phone_info(data[6], data[7]);
            }
            break;

        case ELEMENT_TYPE_MESSAGE:
            if (type_len == 2)
            {
                switch (type_buf[1])
                {
                case ELEMENT_TYPE_MESSAGE_SMS:
                    log_info("notification(SMS):\n");
                    break;
                case ELEMENT_TYPE_MESSAGE_FB:
                    log_info("notification(Facebook):\n");
                    break;
                case ELEMENT_TYPE_MESSAGE_TW:
                    log_info("notification(Twitter):\n");
                    break;
                default:
                    break;
                }
                handle_msg_element(type_buf[1], pack, handle);
            }
            break;

        case ELEMENT_TYPE_FILE:
            handle_file(pack, handle);
            break;

        case ELEMENT_TYPE_GET_FILE:
            {
                int data_len = get_element_data_size(pack, handle, type_buf, type_len);
                uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len);
                STLV_BUF_BEGIN_TEMP_STRING(data, data_len);
                handle_get_file((char*)data);
                STLV_BUF_END_TEMP_STRING(data, data_len);
            }
            break;

        case ELEMENT_TYPE_ACTIVITY_DATA:
            handle_get_activity();
            break;

        case ELEMENT_TYPE_LIST_FILES:
            {
                int data_len = get_element_data_size(pack, handle, type_buf, type_len);
                uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len);
                STLV_BUF_BEGIN_TEMP_STRING(data, data_len);
                handle_list_file((char*)data);
                STLV_BUF_END_TEMP_STRING(data, data_len);
            }
            break;

        case ELEMENT_TYPE_REMOVE_FILE:
            {
                int data_len = get_element_data_size(pack, handle, type_buf, type_len);
                uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len);
                STLV_BUF_BEGIN_TEMP_STRING(data, data_len);
                uint8_t file_name_pos = 0;
                for (uint8_t i = 0; i < data_len; ++i)
                {
                    if (data[i] == ';')
                        data[i] = '\0';

                    if (data[i] == '\0')
                    {
                        handle_remove_file((char*)(&data[file_name_pos]));
                        file_name_pos = i + 1;
                    }
                }
                STLV_BUF_END_TEMP_STRING(data, data_len);
            }
           break;

#if 0
        case ELEMENT_TYPE_SPORT_HEARTBEAT:
            {
                int data_len = get_element_data_size(pack, handle, type_buf, type_len);
                uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len);
                STLV_BUF_BEGIN_TEMP_STRING(data, data_len);
                handle_sports_heartbeat((char*)data);
                STLV_BUF_END_TEMP_STRING(data, data_len);
            }
            break;
        case ELEMENT_TYPE_SPORTS_DATA:
            handle_get_sports_data();
            break;
#endif
        case ELEMENT_TYPE_SPORTS_GRID:
            log_info("Get Sports Grid Request\n");
            handle_get_sports_grid();
            break;

        case ELEMENT_TYPE_ALARM:
            {
                int data_len = get_element_data_size(pack, handle, type_buf, type_len);
                uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len);
                if (data_len != sizeof(alarm_conf_t))
                {
                    log_info("Alarm element decode failed: length mismatch (%d/%d)", data_len, sizeof(alarm_conf_t));
                }
                else
                {
                    handle_alarm((alarm_conf_t*)data);
                }
            }
            break;

        case ELEMENT_TYPE_SN:
            handle_get_device_id();
            break;

        case ELEMENT_TYPE_ACTIVITY:
            handle_gps_data(pack, handle);
            break;

        case ELEMENT_TYPE_GESTURE_CONTROL:
            {
                int data_len = get_element_data_size(pack, handle, type_buf, type_len);
                uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len);
                if (data_len != 5)
                {
                    log_info("gesture control decode failed: length mismatch (%d/1)", data_len);
                }
                else
                {
                    handle_gesture_control(*data, data + 1);
                }
            }
            break;

        case ELEMENT_TYPE_WATCHCONFIG:
            {
                int data_len = get_element_data_size(pack, handle, type_buf, type_len);
                uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len);
                log_info("Set Watch UI Config %d/%d", data_len, (int)sizeof(ui_config));
                //if (data_len >= (int)sizeof(ui_config))
                    handle_set_watch_config((ui_config*)(data + 1));
            }
            break;

        case ELEMENT_TYPE_UNLOCK_WATCH:
            handle_unlock_watch();
            break;

        case ELEMENT_TYPE_DAILY_ACTIVITY:
            handle_daily_activity();
            break;

        }

        handle = get_next_element(pack, handle);

    }
}