/*
 * DIRB
 *
 * utils.c - Utilidades varias
 *
 */

#include "dirb.h"


/*
 * LIMPIA_URL: Corta la cadena si contiene los caracteres (\r), (\n) o ( )
 *
 */

void limpia_url(char *limpia) {
  char *ptr;

  ptr=(char *)strchr(limpia, '\r');
  if(ptr!=0) *ptr='\0';
  ptr=(char *)strchr(limpia, '\n');
  if(ptr!=0) *ptr='\0';
  ptr=(char *)strchr(limpia, ' ');
  if(ptr!=0) *ptr='\0';

}


/*
 * BARRA: Aņade una barra (/) al final de una cadena si no la tiene
 *
 */

void barra(char *barr) {

  if(barr[strlen(barr)-1]=='/') {
    if(options.debuging>5) printf("[+++++] barra() LAST = 0x2F\n");
    } else {
    strncat(barr, "\x2f", 1);
    }

}


/*
 * GUARDADIR: Guarda un directorio en la lista de directorios
 *
 */

void guardadir(char *direccion) {

  if(!options.silent_mode) printf("                                                                               \r");
  IMPRIME("==> DIRECTORY: %s\n", direccion);
  options.recursion_level++;
  if(options.debuging>4) printf("[++++] guardadir() RECURSION_LEVEL: %d\n", options.recursion_level);
  strncpy(dirlist_final->word, direccion, STRING_SIZE-1);
  dirlist_final->siguiente=(struct words *)malloc(sizeof(struct words));
  memset(dirlist_final->siguiente, 0, sizeof(struct words));
  dirlist_final=dirlist_final->siguiente;
  existant=0;

}


/*
 * ELIMINA_DUPWORDS: Elimina elementos duplicados en una lista de palabras
 *
 */

void elimina_dupwords(struct words *puntero) {
  struct words *epun;
  struct words *next;
  struct words *prev;

  epun=puntero;

  prev=epun;

  next=epun->siguiente;

  while(epun->siguiente!=0) {

    if(
    (strncmp(epun->word, next->word, STRING_SIZE-1)==0 && !options.insensitive && next->siguiente!=0)
    ||
    (strncasecmp(epun->word, next->word, STRING_SIZE-1)==0 && options.insensitive && next->siguiente!=0)
    ) {

      if(options.debuging>4) printf("[++++] elimina_dupwords() DUP_WORD: %s - %s\n", epun->word, next->word);
    contador--;
      prev->siguiente=next->siguiente;
      free(next);
      next=prev->siguiente;

      // recursion_level--; (!) En caso de necesitar eliminar directorios duplicados

      } else {
      prev=next;
      next=next->siguiente;
      }

    if(next==0) {
      if(options.debuging>5) printf("[+++++] elimina_dupwords() FIN_loop\n");
      epun=epun->siguiente;
      prev=epun;
      next=epun->siguiente;
      }

    }

}



/*
 * ABRIR_FILE: Abre un fichero de output
 *
 */

FILE *abrir_file(char *file) {
  FILE *desc;

  /*
  if(access (file, F_OK)==0) {
  printf("\n(!) FATAL: File exists, can't overwrite\n");
  exit(-1);
    }
  */

  if((desc=fopen(file, "a"))==0) {
    printf("\n(!) FATAL: Error opening output file: %s\n", file);
    exit(-1);
    }

  return desc;

}


/*
 * LOCATION_CMP: Compara 2 cabeceras Location
 *
 */

int location_cmp(char *A, char *B) {
  int result=0;
  char *ptr=0;

  if(strncmp(A, "http://", 7)==0 || strncmp(A, "https://", 8)==0) {
    ptr=(char *)strchr(A, '/');
    if(ptr!=0) A=ptr+1;
    ptr=(char *)strchr(A, '/');
    if(ptr!=0) A=ptr+1;
    ptr=(char *)strchr(A, '/');
    if(ptr!=0) A=ptr+1;
    }

  if(options.debuging>4) printf("[++++] location_cmp() A[%d]: '%s'\n", strlen(A), uri_decode(A));

  if(strncmp(B, "http://", 7)==0 || strncmp(B, "https://", 8)==0) {
    ptr=(char *)strchr(B, '/');
    if(ptr!=0) B=ptr+1;
    ptr=(char *)strchr(B, '/');
    if(ptr!=0) B=ptr+1;
    ptr=(char *)strchr(B, '/');
    if(ptr!=0) B=ptr+1;
    }

  if(options.debuging>4) printf("[++++] location_cmp() B[%d]: '%s'\n", strlen(B), uri_decode(B));

  result=strncmp(uri_decode(A), uri_decode(B), strlen(A)>strlen(B) ? strlen(A) : strlen(B));

  if(options.debuging>4) printf("[++++] location_cmp() RESULT: %d (%d)\n", result, strlen(A)>strlen(B) ? strlen(A) : strlen(B));

  return result;

}


/*
 * LOCATION_CLEAN: Limpia la cacebera location
 *
 */

void location_clean(char *cleaned, char *toelim) {
  char *ptr=0, *ptr2=0;
  char *A=cleaned;
  int remain;
  char tmpstr[STRING_SIZE];

  if(options.debuging>3) printf("[+++] location_clean() TOCLEAN: %s | TOELIM: %s\n", cleaned, toelim);

  // Jump to uri-path
  if(strncmp(A, "http://", 7)==0 || strncmp(A, "https://", 8)==0) {
    ptr=(char *)strchr(A, '/');
    if(ptr!=0) A=ptr+1;
    ptr=(char *)strchr(A, '/');
    if(ptr!=0) A=ptr+1;
    ptr=(char *)strchr(A, '/');
    if(ptr!=0) A=ptr+1;
    }

  // Remove session
  ptr=(char *)strchr(A, ';');
  if(ptr!=0) {
	ptr2=(char *)strchr(ptr, '?');
	if(ptr2==0) ptr2=cleaned+strlen(cleaned);
    remain=cleaned+strlen(cleaned)-ptr2;
	strncpy(tmpstr, ptr2, remain);
	strncpy(ptr, tmpstr, remain);
    memset(ptr+remain, 0, 1);
    }

  // Remove string
  ptr=(char *)strstr(A, toelim);
  if(ptr!=0) {
    ptr2=ptr+strlen(toelim);
	remain=cleaned+strlen(cleaned)-ptr2;
    strncpy(tmpstr, ptr2, remain);
    strncpy(ptr, tmpstr, remain);
    memset(ptr+remain, 0, 1);
    }

  if(options.debuging>3) printf("[+++] location_clean() CLEANED: %s\n", cleaned);

}


/*
 * CHECK_URL: Comprueba que la URL inicial tiene el formato correcto
 *
 */

void check_url(char *url) {

  if(options.debuging>4) printf("[++++] check_url() URL: %s\n", url);

  if(strncmp(url, "http://", 7)!=0 && strncmp(url, "https://", 8)!=0) {
    printf("\n(!) FATAL: Invalid URL format: %s\n", url);
    printf("    (Use: \"http://host/\" or \"https://host/\" for SSL)\n");
    exit(-1);
    }

}


/*
 * ISLISTABLE: Comprueba si un directorio es listable o no
 *
 */

int islistable(char *direccion) {

  listable=-1;
  get_url(direccion);

  if(listable==-1) listable=0;

  return listable;

}


/*
 * KBHIT: Comprueba si alguna tecla ha sido pulsada (no bloqueante)
 *
 */

char kbhit(void){
  struct timeval tv;
  fd_set read_fd;
  char key = 0;
  static struct termios term;

  tcgetattr(0, &term);
  term.c_lflag &= ~ICANON;
  tcsetattr(0, TCSANOW, &term);

  tv.tv_sec = 0;
  tv.tv_usec = 0;
  FD_ZERO(&read_fd);
  FD_SET(0, &read_fd);

  if(select(1, &read_fd, NULL, NULL, &tv) == -1) key = -1;

  if(FD_ISSET(0, &read_fd)) {
    read(0, &key, 1);
    } else {
  key = 0;
    }

  if(options.debuging>4) printf("[++++] kbhit() %d\n", key);

  return(key);
}


/*
 * CIERRE: Codigo de finalizacion
 *
 */

void cierre(void) {

  if(!options.silent_mode) printf("                                                                               \r");
  IMPRIME("\n-----------------\n");

  IMPRIME("DOWNLOADED: %d - FOUND: %d\n", descargadas, encontradas);

  if(options.saveoutput) fclose(outfile);

  //curl_easy_cleanup(curl); // Segfaults on last cygwin :?

}


/*
 * CODE2STRING: Convierte un codigo en su cadena equivalente
 *
 */

char *code2string(struct code *a, u_int v) {
  int i=0;

  while(a[i].codenum!=v && a[i].codenum!=0xff) {
  i++;
  }

  return a[i].desc;

}


/*
 * INIT_EXTS: Inicializa el array de extensiones
 *
 */

void init_exts(void) {

  // Si no hay extensiones, creamos una vacia

  if(exts_num==0) {

    exts_current=(struct words *)malloc(sizeof(struct words));
    memset(exts_current, 0, sizeof(struct words));
    exts_base=exts_current;

    strncpy(exts_current->word, "", 2);

    exts_current->siguiente=(struct words *)malloc(sizeof(struct words));
    memset(exts_current->siguiente, 0, sizeof(struct words));
    exts_current=exts_current->siguiente;

    exts_num=1;

  }

}


/*
 * URI_DECODE: Decodifica una cadena con caracteres uri-encoded
 *
 */

char *uri_decode(char *uri) {
  int i=0;
  int ptr=0;
  char *decoded;
  char hexa[3];
  char code;

  decoded=(char *)malloc(strlen(uri)+1);

  for(i=0;i<strlen(uri);i++) {

    switch(*(uri+i)) {
      case '%':
        memset(hexa, 0, 3);
        sprintf(hexa, "%c%c", *(uri+i+1), *(uri+i+2));
        i+=2;
        //printf("HEXA: %s\n", hexa);
        sscanf(hexa, "%x", (int *)&code);
        //printf("CODE: %c\n", code);
        *(decoded+ptr)=code;
        ptr++;
        break;
      default:
        *(decoded+ptr)=*(uri+i);
        ptr++;
        break;
      }

    }

  *(decoded+ptr)='\0';

  return decoded;

}


/*
 * COMPARE_STR: Devuelve la posicion del primer caracater diferente
 *
 */

int compare_str(char *A, char *B) {
  int i=0;

  for(i=0; i<strlen(A); i++) {
	if(A[i]!=B[i]) return i;
    }

  return 0;

}