/*
 * code source by mycroft <mycroft@minithins.net>
 *
 * r-e from http://www.passwordmeter.com/
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DEBUG

int abs(int x)
{
  if(x < 0)
    x *= -1;
  return(x);
}

int main(int argc, char **argv)
{
  char *pass;
  int points = 0, n, i, j;
  int have_low = 0, have_up = 0, have_symbol = 0, have_number = 0;
  int have_middle = 0;
  int total = 0;
  int tok = 0;

  if(argc != 2) {
    fprintf(stderr, "Please use %s <password>\n", argv[0]);
    exit(-1);
  }

  pass = argv[1];

/*
 * ADDITIONS
 */

/*
 * 1/ count total char. Need at least 8.
 * Add +(n/4)
 */
  points = strlen(pass) * 4;
#ifdef DEBUG
  fprintf(stderr, "1: Adding %d\n", strlen(pass) * 4);
#endif

/*
 * 2/ count total of Uppercase letters
 * 0: bad / 1: good / 2+: excellent
 * Add +((len - n) *2)
 */
  for(n = 0, i = 0; i < strlen(pass); i ++) {
    if(pass[i] >= 'A' && pass[i] <= 'Z')
      n ++;
  }
  if(n > 0)
    have_up = 1;
  if(!have_up)
    n = strlen(pass);
  points+= (strlen(pass) - n) * 2;
#ifdef DEBUG
  fprintf(stderr, "2: Adding %d\n", (strlen(pass) - n) * 2);
#endif

/*
 * 3/ count total of Lowercase letters
 * 0: bad / 1: good / 2+: excellent
 * Add +((len - n) *2)
 */
  for(n = 0, i = 0; i < strlen(pass); i ++) {
    if(pass[i] >= 'a' && pass[i] <= 'z')
      n ++;
  }
  if(n > 0)
    have_low = 1;
  if(!have_low)
    n = strlen(pass);
  points+= (strlen(pass) - n) * 2;
#ifdef DEBUG
  fprintf(stderr, "3: Adding %d\n", (strlen(pass) - n) * 2);
#endif

/*
 * 4/ Numbers
 * 0: bad / 1: good / 2+: excellent
 * Add +(n*4)
 */
  for(n = 0, i = 0; i < strlen(pass); i ++) {
    if(pass[i] >= '0' && pass[i] <= '9')
      n ++;
  }
  if(n > 0)
    have_number = 1;
  if(n == strlen(pass))
    n = 0;
  points+= n * 4;

#ifdef DEBUG
  fprintf(stderr, "4: Adding %d\n", n * 4);
#endif

/* 
 * 5/ Symbols
 * 0: bad / 1: good / 2+ excellent
 * Add +(n*6)
 */
  for(n = 0, i = 0; i < strlen(pass); i ++) {
    if(!(pass[i] >= 'A' && pass[i] <= 'Z')
    && !(pass[i] >= 'a' && pass[i] <= 'z')
    && !(pass[i] >= '0' && pass[i] <= '9'))
      n ++;
  }
  if(n > 0)
    have_symbol = 1;
  points+= n * 6;
#ifdef DEBUG
  fprintf(stderr, "5: Adding %d\n", n * 6);
#endif

/*
 * 6/ Middle symbols or number.
 * 0: bad / 1: good / 2+ excellent
 * Add +(n*2)
 */
  n = 0;
  if(strlen(pass) > 2) {
    for(i = 1; i < strlen(pass) - 1; i ++) {
      if(!(pass[i] >= 'A' && pass[i] <= 'Z')
      && !(pass[i] >= 'a' && pass[i] <= 'z'))
        n ++;
    }
  }

  points += n * 2;
#ifdef DEBUG
  fprintf(stderr, "6: Adding %d\n", n * 2);
#endif

/*
 * 7/ Requirements
 * len = 8+ / have different kinds of characters
 * <3: bad / 3: good / 4+ excellent
 */
  n = 0;
  if(strlen(pass) >= 8)
    n ++;
  if(have_low)
    n ++;
  if(have_up)
    n ++;
  if(have_number)
    n ++;
  if(have_symbol)
    n ++;

  if(n < 3)
    n = 0;
  points += n * 2;
#ifdef DEBUG
  fprintf(stderr, "7: Adding %d\n", n * 2);
#endif

/*
 * DEDUCTIONS
 */

/*
 * 8/ Letters Only
 * -n (= strlen(pass))
 */
  n = 0;
  if(!have_number && !have_symbol)
    n = strlen(pass);

  points -= n;
#ifdef DEBUG
  fprintf(stderr, "8: Removing %d\n", n);
#endif

/*
 * 9/ Numbers Only
 * -n (= strlen(pass))
 */
  n = 0;
  if(!have_low && !have_up && !have_symbol)
    n = strlen(pass);

  points -= n;
#ifdef DEBUG
  fprintf(stderr, "9: Removing %d\n", n);
#endif

/*
 * 10/ Repeat Characters (Case Insensitive)
 * -(n(n-1))
 */
  char *copy_pass = strdup(pass);
  if(copy_pass == NULL) {
    fprintf(stderr, "Can't copy passwd in memory: fail.\n");
    exit(-2);
  }
  for(i = 0; i < strlen(pass); i ++) {
    char c = copy_pass[i];
    if(c != ' ') {
      n = 0;
      for(j = i; j < strlen(pass); j ++) {
        if(c == copy_pass[j]) n ++;
      }
      total += n * (n - 1);
    } else
      continue;
    /* removing all occurencies of letter c in copy_pass. */
    for(j = 0; j < strlen(copy_pass); j ++)
      if(copy_pass[j] == c)
        copy_pass[j] = ' ';
  }
  free(copy_pass);

  points -= total;
#ifdef DEBUG
  fprintf(stderr, "10: Removing %d\n", total);
#endif

/*
 * 11/ Consecutive Uppercase Letters
 *
 */
  tok = total = 0;
  for(n = 0, i = 0; i < strlen(pass); i ++) {
    if(pass[i] >= 'A' && pass[i] <= 'Z') {
      tok ++;
    } else 
      if(tok) {
        total+= (tok - 1) * 2;
        tok = 0;
      }
  }

  if(tok)
    total += (tok - 1) * 2;

  points -= total;
#ifdef DEBUG
  fprintf(stderr, "11: Removing %d\n", total);
#endif

/*
 * 12/ Consecutive Lowercase Letters
 *
 */
  tok = total = 0;
  for(n = 0, i = 0; i < strlen(pass); i ++) {
    if(pass[i] >= 'a' && pass[i] <= 'z') {
      tok ++;
    } else 
      if(tok) {
        total+= (tok - 1) * 2;
        tok = 0;
      }
  }

  if(tok)
    total += (tok - 1) * 2;

  points -= total;
#ifdef DEBUG
  fprintf(stderr, "12: Removing %d\n", total);
#endif


/*
 * 13/ Consecutive Numbers
 *
 */
  tok = total = 0;
  for(n = 0, i = 0; i < strlen(pass); i ++) {
    if(pass[i] >= '0' && pass[i] <= '9') {
      tok ++;
    } else 
      if(tok) {
        total+= (tok - 1) * 2;
        tok = 0;
      }
  }

  if(tok)
    total += (tok - 1) * 2;

  points -= total;
#ifdef DEBUG
  fprintf(stderr, "13: Removing %d\n", total);
#endif

/*
 * 14/ Sequential Letters & Numbers (3+)
 *
 */
  total = tok = 0;
  for(i = 0; i < strlen(pass); i ++) {
    if((i + 1) == strlen(pass))
      break;

    if(abs(pass[i] - pass[i + 1]) == 1)
      tok ++;
    else {
      if(tok)
        total += (tok - 2) * 3;
      tok = 0;
    }
  }
  if(tok)
    total += (tok - 1) * 3;

  points -= total;
#ifdef DEBUG
  fprintf(stderr, "14: Removing %d\n", total);
#endif

  if(points < 0)
    points = 0;
  if(points > 100)
    points = 100;

  printf("=> Password is %d%% strong !\n", points);

  return 0;
}
