/* Copyright (C) 2000,2001,2002 Manuel Amador (Rudd-O)
   This file is part of Directory administrator.

   Directory administrator is free software; you can redistribute it 
   and/or modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2.1 of
   the License, or (at your option) any later version.

   Directory administrator is distributed in the hope that it will be 
   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with Directory administrator; if not, send e-mail to amador@alomega.com
*/


#include <gnome.h>
#include "appglobals.h"
#include "appfunctions.h"
#include "appsupport.h"
#include "profile.h"
#include "usergrouplists.h"
#include "dir_entry.h"
#include "charset.h"
#include <ctype.h>

guint32 objectview_last_keypress = 0;
gchar* typeaheadcontents = NULL;

//return false if you want the keypress to be processed, true to kill it before it reaches the UI
gboolean objectview_keypress (GdkEventKey* event) {
  guint32 delta;
  gchar*tmp;

  GtkWidget * delbutton;
  unsigned char letter;
  int key;
//  GtkWidget * temp;
  GtkWidget * objectview, *scrolledwindow;
  gboolean processed = FALSE;
  GtkWindow * b = (GtkWindow*)app;

  letter=event->string[0];
  key = event->keyval;
  objectview = lookup_widget(app,"itemlist");
  scrolledwindow= lookup_widget(app,"itemlistscrolledwindow");

g_print("Processing keypress %d in main window\n",event->keyval);

if (b->focus_widget == NULL) gtk_widget_grab_focus(scrolledwindow);
g_print("Focused widget name: %s\n",gtk_widget_get_name(b->focus_widget));



// convenience functions for keypresses in filter items
if (event->keyval == 65293 || event->keyval == 65421) {
	if (GTK_WIDGET_HAS_FOCUS(lookup_widget(app,"filter"))){
		processed = TRUE;
		delbutton = lookup_widget (GTK_WIDGET (app),"filterbutton");
		if (GTK_WIDGET_SENSITIVE (delbutton)) {
			gtk_signal_emit_by_name (GTK_OBJECT (delbutton),"clicked");
			gtk_widget_grab_focus(lookup_widget(app,"filter"));
		}
	}
	if (GTK_WIDGET_HAS_FOCUS(lookup_widget(app,"filterbutton"))){
		processed = TRUE;
		delbutton = lookup_widget (GTK_WIDGET (app),"filterbutton");
		if (GTK_WIDGET_SENSITIVE (delbutton)) {
			gtk_signal_emit_by_name (GTK_OBJECT (delbutton),"clicked");
			gtk_widget_grab_focus(lookup_widget(app,"filter"));
		}
	}
	if (GTK_WIDGET_HAS_FOCUS(lookup_widget(app,"filterclear"))){
		processed = TRUE;
		delbutton = lookup_widget (GTK_WIDGET (app),"filterclear");
		if (GTK_WIDGET_SENSITIVE (delbutton)) {
			gtk_signal_emit_by_name (GTK_OBJECT (delbutton),"clicked");
			gtk_widget_grab_focus(lookup_widget(app,"filter"));
		}
	}
}


// if NOT icon list has focus... return, do not process anything further
if ( GTK_WIDGET_HAS_FOCUS(lookup_widget(app,"filtertype")) ||
GTK_WIDGET_HAS_FOCUS(lookup_widget(app,"filterdropdown")) ||
GTK_WIDGET_HAS_FOCUS(lookup_widget(app,"filter")) ||
GTK_WIDGET_HAS_FOCUS(lookup_widget(app,"filterbutton")) ||
GTK_WIDGET_HAS_FOCUS(lookup_widget(app,"filterclear")) ||
GTK_WIDGET_HAS_FOCUS(lookup_widget(app,"filteradvanced")) ) {
		g_print("A filter control is focused, no longer processing keys\n");
		return FALSE;
}


// else, key processing for object view
g_print("Processing keypress for object view\n");

/* tab key, bro */
if (event->keyval == 65289) {
		g_print("Focusing filter box\n");
		gtk_widget_grab_focus(lookup_widget(app,"filtertype"));
		processed = TRUE;
}

/* procesamiento de arrow keys */

  if (event->keyval == 65363) {
  objectview_move_right (); processed = TRUE; }
  if (event->keyval == 65361) {
  objectview_move_left ();  processed = TRUE;}
  if (event->keyval == 65362) {
  objectview_move_up ();processed = TRUE;}
  if (event->keyval == 65364) {
  objectview_move_down ();processed = TRUE;}

/* del key */
  if (event->keyval == 65535) {
processed = TRUE;
    delbutton = lookup_widget (GTK_WIDGET (app),"button_removeselection");
    if (GTK_WIDGET_SENSITIVE (delbutton)) {
       gtk_signal_emit_by_name (GTK_OBJECT(delbutton), "clicked");
    }
  }
  /* enter keys */

  if (event->keyval == 65293 || event->keyval == 65421) {
processed = TRUE;
	delbutton = lookup_widget (GTK_WIDGET (app),"button_modifyselection");
    if (GTK_WIDGET_SENSITIVE (delbutton)) {
       gtk_signal_emit_by_name (GTK_OBJECT (delbutton),"clicked");
    }
  }





/* type ahead find */

  if (isalnum(letter) || isspace(letter)) {
processed = TRUE;
    delta = event->time - objectview_last_keypress;
    //g_print("\nKeypress delta: %u", delta);

    if (delta <= 1000 || objectview_last_keypress == 0) {
      tmp = typeaheadcontents;
      if (typeaheadcontents)
        typeaheadcontents = g_strconcat(typeaheadcontents,event->string,NULL);
      else
        typeaheadcontents = g_strconcat(event->string,NULL);
      if (tmp) g_free(tmp);
//      g_print("\nType ahead begun: %s",typeaheadcontents);
      objectview_typeahead_find(typeaheadcontents);
    }
    else {
//      g_print("\nType ahead reset - time expired");
      g_free(typeaheadcontents); typeaheadcontents = g_strdup(event->string);
      objectview_typeahead_find(typeaheadcontents);
    }

    objectview_last_keypress = event->time;

  }
  else if (key == 65505 || key == 65507  || key == 65513  || key == 65407
|| key == 65509  || key == 65506
 || key ==  65508 || key ==  65406 ){

  }
  else {
    /* otra tecla, se cancela el typeahead */
    g_free(typeaheadcontents); typeaheadcontents =NULL;
  }


 return processed;

}


void objectview_select_all() {

  objectview_icon_select_all((GnomeIconList *)
      lookup_widget
      (app,"itemlist"));

}

void objectview_typeahead_find (gchar* string) {

  GList* a;
  gboolean found = FALSE;
  dir_entry*e =NULL;

  for (a=cached_dir_entries;a;a=a->next) {
    e= a->data;
    if (strncasecmp(dir_entry_get_name(e),string,strlen(string)) == 0)
      {
         g_print("\n\nFound a match while typeahead searching\n\n");
         found = TRUE;
         break;
      }
  }

  if (found) {

    objectview_icon_clear_selection((GnomeIconList *)
      lookup_widget
      (app,"itemlist"));

    objectview_icon_select_by_entry ((GnomeIconList *)
      lookup_widget
      (app,"itemlist"),e);
  }
}


void objectview_icon_select_by_entry (GnomeIconList*list,
dir_entry* e) {

int pos;

pos = gnome_icon_list_find_icon_from_data(list,e);

  if (pos>=0) {
    gnome_icon_list_select_icon(list,pos);
if (gnome_icon_list_icon_is_visible(list,pos) !=
GTK_VISIBILITY_FULL)
gnome_icon_list_moveto(list,pos,0.5);

  }
}

void objectview_icon_select_all (GnomeIconList*list) {


int pos;

for (pos = list->icons-1;pos>=0;pos--)
//	gnome_icon_list_unselect_all(list,NULL,NULL);
	//gnome_icon_list_freeze(list);
	gnome_icon_list_select_icon(list,pos);
	//gnome_icon_list_thaw(list);
}



void objectview_clear(void) {

objectview_icon_clear((GnomeIconList *) lookup_widget (app,"itemlist"));

}

void objectview_icon_clear(GnomeIconList *list) {

  gnome_icon_list_clear (list);

}


void objectview_fill (void) {

	GList* l;
	dir_entry*stuff;
	char* filter = NULL;
	char*eluno;char*elotro;
//	GtkOptionMenu*n;
//	GtkMenuItem*m;
//	GtkButton* i;
//	GtkBin*z;
//	GtkLabel*j;
//	char**whatselected;

	filter = gtk_entry_get_text(GTK_ENTRY(lookup_widget(app,"filter")));
	if (strlen(filter)<1) filter = NULL;
	/*
	n=(GtkOptionMenu*)lookup_widget(app,"filtertype");
	m=n->menu_item;
	g_assert(GTK_IS_MENU_ITEM(m));
	g_print("%s\n",gtk_type_name(GTK_WIDGET_TYPE(m)));
	z=&(m->item.bin);
	g_print("%s\n",gtk_type_name(GTK_WIDGET_TYPE(z)));
//	j=(z->child);
	g_assert(j);
	g_print("%d\n",GTK_WIDGET_TYPE(j));
	g_assert(GTK_IS_BUTTON(j));

	gtk_label_get(j,whatselected);

	g_print("This is selected on the dropdown: %s\n",whatselected);
*/
	objectview_add_begun();

	objectview_clear();

	for (l = g_list_first(cached_dir_entries); l; l = g_list_next (l)) {
		stuff = l->data;
		if (filter) { eluno = g_strdup(filter);g_strdown(eluno); } else eluno = NULL;
		elotro = g_strdup(stuff->dn);g_strdown(elotro);
		if (eluno == NULL || strstr(elotro,eluno)) {
			objectview_add (l->data);
		}
		if (filter) { g_free(eluno);} g_free(elotro);

	}

  objectview_add_finished();

}


void objectview_add_finished(void) {
  objectview_icon_add_finished((GnomeIconList *)lookup_widget
(app,
"itemlist"));
}

void objectview_icon_add_finished(GnomeIconList*list) {
//  gtk_signal_emit_by_name (GTK_OBJECT(list), "unselect_icon");
  gnome_icon_list_thaw (list);
}

void objectview_add_begun(void) {
objectview_icon_add_begun((GnomeIconList *)lookup_widget (app,
"itemlist"));
}

void objectview_icon_add_begun(GnomeIconList*list) {
	//check if icons are properly installed
	gchar*pixmapfile;
	pixmapfile = gnome_pixmap_file ("directory_administrator/user-icon.xpm");
	if (pixmapfile == NULL){
		gtk_widget_show(
		create_messagebox_with_message("Your Directory administrator installation is faulty.  Icons cannot be found.\nPlease ensure the icons were installed in the GNOME icons (pixmaps) directory."));
	}

//  gtk_signal_emit_by_name (GTK_OBJECT(list), "unselect_icon");
	gnome_icon_list_freeze (list);
}


gboolean objectview_has_selection (void) {
  return objectview_icon_has_selection((GnomeIconList *) lookup_widget (app,
"itemlist"));
}

gboolean objectview_icon_has_selection (GnomeIconList* list) {
 if (g_list_length(list->selection)>0)
    return TRUE;
 return FALSE;
}

int objectview_num_entries (void) {
  return objectview_icon_num_entries(
        (GnomeIconList *) lookup_widget (app, "itemlist"));
}

int objectview_icon_num_entries (GnomeIconList* list) {
 return list->icons;
}

void objectview_select_first (void) {

  if (objectview_num_entries() > 0)
  objectview_icon_select_first(
      (GnomeIconList *) lookup_widget (app, "itemlist"));
}

void objectview_clear_selection () {
   objectview_icon_clear_selection( (GnomeIconList *) lookup_widget (app, "itemlist"));
}

void objectview_icon_clear_selection (GnomeIconList* list) {
  GList* iter=NULL;
  GList* copy=NULL;






  for (iter=list->selection;iter;iter=iter->next) {
      copy = g_list_append(copy,GINT_TO_POINTER(iter->data));
  }
  for (iter=copy;iter;iter=iter->next) {
//      g_print("\n            Unselecting icon %d",GPOINTER_TO_INT(iter->data));
      gnome_icon_list_unselect_icon(list,GPOINTER_TO_INT(iter->data));
  }
  g_list_free(copy);

  list->selection = NULL;


  objectview_icon_dump_selections(list);





}

void objectview_icon_dump_selections (GnomeIconList* list) {
  GList* iter=NULL;
  dir_entry* entry = NULL;
  int pos;



  /*g_print("\n\nDebugging information for icon selections:");
  g_print("\nNumber of icons in list: %d     list length: %d",
       list->icons,g_list_length(list->selection)
  );*/

  for (iter=list->selection;iter;iter=iter->next)
  {
    pos = GPOINTER_TO_INT (iter->data);
    entry = gnome_icon_list_get_icon_data (list, pos);
//    g_print("\n   Selected position: %d",pos);
//    g_print("\n   Selected DN: %s",dir_entry_get_dn(entry));
  }



}

void objectview_icon_select_first (GnomeIconList* list) {
  objectview_icon_clear_selection(list);

  gnome_icon_list_select_icon(list,0);
if (gnome_icon_list_icon_is_visible(list,0) != GTK_VISIBILITY_FULL)
gnome_icon_list_moveto(list,0,0);


  objectview_icon_dump_selections(list);
}



/* there are two views

objectview_icon
objectview_list_detailed

objectview_icon_add (GnomeIconList* , dir_entry *) adds an entry to the
icon view
                                                    (dupes the icon_entry for itself and frees it
                                                     on item removal)
objectview_list_detailed_add (GtkCList* , icon_entry *) adds an entry to the detail list view
                                                    (dupes the icon_entry for itself and frees it
                                                     on item removal)

objectview_icon_remove_bydn(GnomeIconList*,gchar*) finds the entry with the corr. DN and removes it
objectview_list_detailed_remove_bydn(GnomeIconList*,gchar*) does the same thing for the list view

those two functions are marshaled by the master functions

objectview_add (dir_entry *)
objectview_remove_bydn (gchar *)

*/

void
objectview_add (dir_entry * entry)
{
  objectview_icon_add ((GnomeIconList *) lookup_widget (app, "itemlist"),
		       entry);
}





void
objectview_move_left (void) {

  if (objectview_has_selection()) {
//  g_print("\nMoving left");
  objectview_icon_move_left (
     (GnomeIconList *) lookup_widget (app, "itemlist"));
  }
  else objectview_select_first();

}
void objectview_icon_move_left( GnomeIconList * list ){
int currpos ;
int pos;
currpos = GPOINTER_TO_INT(list->selection->data);

pos = currpos - 1;
if  (pos >=0 && pos < list->icons) {
    objectview_icon_clear_selection(list);
gnome_icon_list_select_icon(list,pos);
if (gnome_icon_list_icon_is_visible(list,pos) != GTK_VISIBILITY_FULL)
gnome_icon_list_moveto(list,pos,0);
}

}



void
objectview_move_up (void) {
  if (objectview_has_selection()) {
//  g_print("\nMoving up");
  objectview_icon_move_up (
     (GnomeIconList *) lookup_widget (app, "itemlist"));}
  else objectview_select_first();

}
void objectview_icon_move_up( GnomeIconList * list ){
int currpos ;
int itemsxline ;
int pos;
itemsxline = gnome_icon_list_get_items_per_line (list);
currpos = GPOINTER_TO_INT(list->selection->data);

pos = currpos - itemsxline;
if  (pos >= 0 && pos < list->icons){
      objectview_icon_clear_selection(list);
gnome_icon_list_select_icon(list,pos);
if (gnome_icon_list_icon_is_visible(list,pos) != GTK_VISIBILITY_FULL)
gnome_icon_list_moveto(list,pos,0);
}

}




void
objectview_move_down (void) {
  if (objectview_has_selection()) {
//  g_print("\nMoving down");
  objectview_icon_move_down (
     (GnomeIconList *) lookup_widget (app, "itemlist"));
}
  else objectview_select_first();

}
void objectview_icon_move_down( GnomeIconList * list ){
int currpos ;
int itemsxline ;
int pos;

itemsxline = gnome_icon_list_get_items_per_line (list);
currpos = GPOINTER_TO_INT(list->selection->data);

pos = currpos + itemsxline;
if  (pos >= 0 && pos < list->icons){
        objectview_icon_clear_selection(list);
gnome_icon_list_select_icon(list,pos);
if (gnome_icon_list_icon_is_visible(list,pos) != GTK_VISIBILITY_FULL)
    gnome_icon_list_moveto(list,pos,1);
}

/*(estoy en la ultima linea?)
si la posicion del icono actual esta entre los ultimos N iconos
donde N es el numero de items x linea
*/


/*if (pos >= list->icons && !())
gnome_icon_list_select_icon(list,list->icons -1);
*/
}




void
objectview_move_right (void) {
  if (objectview_has_selection()) {
//  g_print("\nMoving right");
  objectview_icon_move_right (
     (GnomeIconList *) lookup_widget (app, "itemlist"));
}
  else objectview_select_first();
}

void objectview_icon_move_right( GnomeIconList * list ){
int currpos ;
int pos;
currpos = GPOINTER_TO_INT(list->selection->data);

pos = currpos +1;
if  (pos >= 0 && pos < list->icons){
          objectview_icon_clear_selection(list);
gnome_icon_list_select_icon(list,pos);
if (gnome_icon_list_icon_is_visible(list,pos) != GTK_VISIBILITY_FULL)
     gnome_icon_list_moveto(list,pos,1);
}

}









void
objectview_icon_add (GnomeIconList * list, dir_entry * entry)
{

//  SACA UN DUPLICADO DEL ENTRY
  int pos;
  gchar *pixmapfile = NULL;


  g_assert(entry);
  if (entry->type == DENTRY_USER)
    pixmapfile = gnome_pixmap_file ("directory_administrator/user-icon.xpm");
  if (entry->type == DENTRY_GROUP)
    pixmapfile = gnome_pixmap_file ("directory_administrator/group-icon.xpm");
  if (pixmapfile) {
  pos = gnome_icon_list_append (list, pixmapfile, dir_entry_get_name(entry));
  gnome_icon_list_set_icon_data (list, pos, entry);
  g_free (pixmapfile);}
}

/*void
objectview_remove_bydn (gchar * dn)
{
  objectview_icon_remove_bydn ((GnomeIconList *)
			       lookup_widget (app, "itemlist"), dn);
}

void
objectview_icon_remove_bydn (GnomeIconList * list, gchar * dn)
{
  icon_entry *curr_entry;
  int pos;
  for (pos = 0; pos < list->icons; pos++)
    {
      curr_entry = gnome_icon_list_get_icon_data (list, pos);
      if (g_strcasecmp (dn, dir_entry_get_dn(curr_entry) == 0)
	{
          g_print("\nRemoving %s from icon view",curr_entry->dn);
	  gnome_icon_list_remove (list, pos);
	  pos = list->icons + 1;
	}
    }
}
*/

GList *
refresh_directory_data (connection_profile * usethisone)
{
  //needs a connection profile already connected.  thanks.  REMEMBER DAT!!!

  LDAP *conn = NULL;
  gchar *root = NULL;
  gchar *filter = NULL;
  LDAPMessage *results = NULL;
  LDAPMessage *entry = NULL;
  gchar *attributetoreturn[8];
  char **value_collection;
  char **oc_collection;
  int oc_iterator;
  int ldap_errors;
  GList *direntries;
  gchar *uid_holder;
  gchar *cn_holder;
  gchar *gecos_holder;
  gchar *dn_holder;
  gchar *ou_holder;
  gint uidnumber_holder, gidnumber_holder;
  dir_entry *d_entry;
  float progress;
  gint totalentries, currententrynumber;

  g_print ("\ncalled: refresh_directory_data\n");
  direntries = NULL;

  //check 4 connection
  if (connection_profile_is_connected (usethisone) == FALSE)
    {
      g_print ("\ndisconnected: list emptied\n");
      return NULL;
    }

  conn = connection_profile_get_ldap_handler (usethisone);
  root = connection_profile_get_treeroot (usethisone);

  attributetoreturn[0] = "objectClass";
  attributetoreturn[1] = "uid";
  attributetoreturn[2] = "cn";
  attributetoreturn[3] = "gecos";
  attributetoreturn[4] = "gidnumber";
  attributetoreturn[5] = "uidnumber";
  attributetoreturn[6] = "ou";
  attributetoreturn[7] = NULL;

  filter = 
"(|(objectclass=posixAccount)(objectclass=posixGroup)(objectclass=organizationalUnit))";

  //look data up
  ldap_errors =
    ldap_search_s (conn, root, LDAP_SCOPE_SUBTREE, filter,
		   attributetoreturn, 0, &results);
  if (ldap_errors)
    {
      g_print ("LDAP error while filling icon list: %s\n",
	       ldap_err2string (ldap_errors));
      return NULL;
    }
  g_assert (results);

  totalentries = ldap_count_entries (conn,results);
  currententrynumber = 0;

  oc_iterator = 0;
  for (entry=ldap_first_entry(conn,results);entry;entry=ldap_next_entry 
(conn, entry))
    {
      currententrynumber++;
      progress = (float) currententrynumber/totalentries;
      app_set_progress(progress);
      //quiero ver que chucha hay en la lista de objectClass
      dn_holder = ldap_get_dn(conn,entry);
      oc_collection = ldap_get_values (conn, entry, "objectClass");
      g_assert (oc_collection);

      oc_iterator = 0;
      d_entry=NULL;

      while (oc_collection[oc_iterator] || d_entry==NULL)
	{
	  //si es un posix account, aniadir como usuario

	  if (g_strcasecmp (oc_collection[oc_iterator], "posixAccount") == 0)
	    {
              cn_holder = NULL;
              uid_holder = NULL;
              gecos_holder = NULL;
              uidnumber_holder = 0;
              gidnumber_holder = 0;

	      value_collection = ldap_get_values (conn, entry, "cn");
	      if (value_collection) {
              cn_holder = convert_from_utf8(value_collection[0]);              
	      ldap_value_free (value_collection); }

	      value_collection = ldap_get_values (conn, entry, "gecos");
	      if (value_collection) {
              gecos_holder = convert_from_utf8(value_collection[0]);              
	      ldap_value_free (value_collection); }

	      value_collection = ldap_get_values (conn, entry, "uid");
	      if (value_collection) {
              uid_holder = convert_from_utf8(value_collection[0]);              
	      ldap_value_free (value_collection); }

	      value_collection = ldap_get_values (conn, entry, "uidnumber");
	      if (value_collection) {
              uidnumber_holder = atoi(value_collection[0]);
	      ldap_value_free (value_collection); }

	      value_collection = ldap_get_values (conn, entry, "gidnumber");
	      if (value_collection) {
              gidnumber_holder = atoi(value_collection[0]);
	      ldap_value_free (value_collection); }

              //si no hay common name, al menos use gecos
              if (cn_holder == NULL) cn_holder = gecos_holder;
	      d_entry =
		dir_entry_user_new (dn_holder, uid_holder, cn_holder,
                    uidnumber_holder, gidnumber_holder);
	      g_free(uid_holder); g_free (cn_holder); g_free(gecos_holder);
	    }
	  //si es un posix group, aadir como grupo
	  else if (g_strcasecmp (oc_collection[oc_iterator], "posixGroup") == 0)
	    {
              cn_holder = NULL;
              gidnumber_holder =0;

	      value_collection = ldap_get_values (conn, entry, "cn");
	      if (value_collection) {
              cn_holder = convert_from_utf8(value_collection[0]);              
	      ldap_value_free (value_collection); }

	      value_collection = ldap_get_values (conn, entry, "gidnumber");
	      g_assert (value_collection);
              gidnumber_holder = atoi(value_collection[0]);
	      ldap_value_free (value_collection);

	      d_entry =
		dir_entry_group_new (dn_holder, cn_holder,
                     gidnumber_holder);
              g_free (cn_holder);

	    }
	  else if (g_strcasecmp (oc_collection[oc_iterator], "organizationalUnit") == 0)
	    {
              ou_holder = NULL;

	      value_collection = ldap_get_values (conn, entry, "ou");
	      if (value_collection) {
              ou_holder = convert_from_utf8(value_collection[0]);              
	      ldap_value_free (value_collection); }

	      d_entry =
		dir_entry_orgunit_new (dn_holder, ou_holder);
              g_free (ou_holder);

	    }
/*	  else 
	    {
	      d_entry =
		dir_entry_undef_new (dn_holder);

	    }*/
	  oc_iterator++;
	}
      if (d_entry)
      direntries = g_list_append(direntries,d_entry);
      ldap_value_free (oc_collection);
      g_free (dn_holder); 
    }
  ldap_msgfree (results);

  return g_list_first(direntries);

}



syntax highlighted by Code2HTML, v. 0.9.1