/*
  Aaron Linville
  aaron@linville.org
 
  v1.0 - March 3rd, 2001
 
  ypfix.cpp
 
  Description: This application sorts the ypfile by userid and outputs it
  to a file. The program will also print errors to stderr if a user does
  not have a password set.

  Bugs: There are some problems with the arguments parsing. It works if you
  don't make any mistakes, but bad stuff can happen.
 
  Usage: ./ypfix -f source_file -w new_file
  The source_file can be created by doing something like
  % ypcat passwd > source_file'
*/

#include <algorithm>
#include <iostream>
#include <fstream>
#include <functional>
#include <list>
#include <string>

#include <getopt.h>

using namespace std;

class entry {
public:
  string username;
  string password;
  string uid;
  string gid;
  string realname;
  string homedir;
  string shell;
  
  bool operator< (const entry &e1) {
    string s1 = e1.uid;
    return (atoi(uid.c_str()) < atoi(s1.c_str()));
  }
};

bool fileCheck(string, ifstream &);
list<entry> parseFile(ifstream &);

int main(int argc, char *argv[]) {
  string srcFilePath, dstFilePath;
  
  int opt;
  
  if(argc < 3) {
    cerr << "usage: " << argv[0]
         << "[-vhd] -f source_file -w new_file"
         << endl;
    return 0;
  }
  
  while ((opt = getopt (argc, argv, "f:w:")) != EOF)
    switch (opt) {
      case 'f': cout << optarg << endl; srcFilePath = optarg; break;
      case 'w': cout << optarg << endl; dstFilePath = optarg; break;
      case 'v': cout << "Version 0.1b" << endl;
      case '?': case 'h' :
        cerr << "usage: " << argv[0]
        << " [-vhd] -f source_file -w new_file"
        << endl;
        return 0;
    }
  
  ifstream inFile;
  
  // Check the file
  if(!fileCheck(srcFilePath, inFile))
    return 0;
  
  list<entry> userlist = parseFile(inFile);
  inFile.close();
  
  userlist.sort();
  
  ofstream outFile;
  outFile.open(dstFilePath.c_str(), ios::out);
  
  list<entry>::iterator i;
  for(i = userlist.begin(); i != userlist.end(); i++) {
    outFile << (*i).username << ':'
            << (*i).password << ':'
            << (*i).uid << ':'
            << (*i).gid << ':'
            << (*i).realname << ':'
            << (*i).homedir << ':'
            << (*i).shell << endl;
    if((*i).password == "") {
      cerr << (*i).username << " (" << (*i).username
           << ") has a blank password!" << endl;
    }
  }
  outFile.close();
  
  return 0;
}

// Checks the file for existence
bool fileCheck(string srcFilePath, ifstream &inFile) {
  inFile.open(srcFilePath.c_str(), ios::in);
  if(!inFile.good()) {
    cerr << "Cannot open file " << srcFilePath << endl;
    return false;
  }
  return true;
}

list<entry> parseFile(ifstream &inFile) {
  list<entry> userlist;
  
  int line = 0;
  
  while(!inFile.eof() && inFile.good()) {
    entry tempUser;
    
    if(!getline(inFile, tempUser.username, ':') ||
       !getline(inFile, tempUser.password, ':') ||
       !getline(inFile, tempUser.uid, ':') ||
       !getline(inFile, tempUser.gid, ':') ||
       !getline(inFile, tempUser.realname, ':') ||
       !getline(inFile, tempUser.homedir, ':') ||
       !getline(inFile, tempUser.shell, '\n')) {
      if(!inFile.eof()) {
        cerr << "Error parsing line #" << line << endl;
      }
    } else {
      userlist.push_back(tempUser);
    }
    
    line++;
  }
  
  return userlist;
}

