Exemple #1
0
int
main(int argc, char *argv[])
{
    int         sts;
    int         ctx;
    int         c;
    char	*infile;
    int		nfilelist;
    int		filenum;
    char	*archive = NULL;
    int		j;
    char	*buf;
    fields_t	*f;
    char	*s;
    int		gzipped;
    FILE	*fp;
    metric_t	*m;
    handler_t	*h;
    int		unhandled_metric_cnt = 0;

    while ((c = pmGetOptions(argc, argv, &opts)) != EOF) {
        switch (c) {
	case 'F':
	    Fflag = 1;
	    break;
	case 'v':
	    vflag++;
	    break;
        }
    }

    nfilelist = argc - opts.optind - 1;
    if (nfilelist < 1)
    	opts.errors++;
    else
	archive = argv[argc - 1];

    if (opts.errors) {
	pmUsageMessage(&opts);
	exit(1);
    }

    if ((buf = malloc(BUFSIZE)) == NULL) {
    	perror("Error: out of memory:");
	exit(1);
    }

    if (Fflag) {
    	snprintf(buf, BUFSIZE, "%s.meta", archive); unlink(buf);
    	snprintf(buf, BUFSIZE, "%s.index", archive); unlink(buf);
	for (j=0;; j++) {
	    snprintf(buf, BUFSIZE, "%s.%d", archive, j);
	    if (unlink(buf) < 0)
	    	break;
	}
    }

    ctx = pmiStart(archive, 0);
    if ((sts = pmiUseContext(ctx)) < 0) {
	fprintf(stderr, "Error: pmiUseContext failed: %s\n", pmiErrStr(sts));
	exit(1);
    }

    /*
     * Define the metrics name space, see metrics.c (generated by pmdesc)
     */
    for (m = metrics; m->name; m++) {
	pmDesc *d = &m->desc;

	sts = pmiAddMetric(m->name, d->pmid, d->type, d->indom, d->sem, d->units);
	if (sts < 0) {
	    fprintf(stderr, "Error: failed to add metric %s: %s\n", m->name, pmiErrStr(sts));
	    exit(1);
	}
    }

    /*
     * Populate special case instance domains
     */
    pmiAddInstance(pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM), "1 minute", 1);
    pmiAddInstance(pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM), "5 minute", 5);
    pmiAddInstance(pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM), "15 minute", 15);
    indom_cnt[LOADAVG_INDOM] = 3;

    for (filenum=0; filenum < nfilelist; filenum++) {
	infile = argv[opts.optind + filenum];
	gzipped = strstr(infile, ".gz") != NULL;
	if (gzipped) {
	    snprintf(buf, BUFSIZE, "gzip -c -d %s", infile);
	    if ((fp = popen(buf, "r")) == NULL)
		perror(buf);
	}
	else
	if ((fp = fopen(infile, "r")) == NULL)
	    perror(infile);

	if (fp == NULL) {
	    pmUsageMessage(&opts);
	    exit(1);
	}

	/*
	 * parse the header
	 */
	sts = header_handler(fp, infile, buf, BUFSIZE);

	/*
	 * Parse remaining data stream for this input file
	 */
	while(fgets(buf, BUFSIZE, fp)) {
	    if ((s = strrchr(buf, '\n')) != NULL)
		*s = '\0';
	    if (!buf[0])
	    	continue;
	    f = fields_new(buf, strlen(buf)+1);
	    if (f->nfields > 0) {
		if ((h = find_handler(f->fields[0])) == NULL) {
		    unhandled_metric_cnt++;
		    if (vflag > 1)
			printf("Unhandled tag: \"%s\"\n", f->fields[0]);
		}
		else {
		    sts = h->handler(h, f);
		    if (sts < 0 && h->handler == timestamp_handler) {
			fprintf(stderr, "Error: %s\n", pmiErrStr(sts));
			exit(1);
		    }
		}
	    }
	    fields_free(f);
	}

	/* final flush for this file */
	if ((sts = timestamp_flush()) < 0) {
	    fprintf(stderr, "Error: failed to write final timestamp: %s\n", pmiErrStr(sts));
	    exit(1);
	}

	if (gzipped)
	    pclose(fp);
	else
	    fclose(fp);
    }

    sts = pmiEnd();
    if (unhandled_metric_cnt && vflag)
    	fprintf(stderr, "Warning: %d unhandled metric/values\n", unhandled_metric_cnt);

    exit(0);
}
int main(int argc, char* argv[])
{
    std::string server;
    std::string port;
    std::string user;
    std::string folder;
    std::string password;
    std::vector<fs::path> from;
    std::vector<fs::path> entity;
    fs::path to;
    
    //[Gmail]/Sent Mail
    po::options_description general_options("General");
    general_options.add_options()
        ("help", "list options");
    po::options_description file_options("Load");
    file_options.add_options()
        ("save-raw", po::value<fs::path>(&to), "path to save the data (after download phase)");
    po::options_description download_options("Download");
    download_options.add_options()
        ("server", po::value<std::string>(&server), "imap server dns/ip")
        ("port", po::value<std::string>(&port)->default_value("993"), "imap port")
        ("folder", po::value<std::string>(&folder)->default_value("Sent"), "imap folder")
        ("user", po::value<std::string>(&user), "imap username")
        ("password", po::value<std::string>(&password), "imap password (will ask if not specified)");
    po::options_description run_options("Run");
    
    po::options_description all_options("Email Topology Options");
    all_options
        .add(general_options)
        .add(file_options)
        .add(download_options);

    if(argc < 2) {
        std::cout << all_options << std::endl;
        return 1;
    }

    po::variables_map vm;
    try {
        int options_style = po::command_line_style::default_style;
        po::store(po::parse_command_line(argc, argv, all_options, options_style), vm);
        po::notify(vm);
    } catch(std::exception& e) {
        std::cout << all_options << std::endl;
        std::cout << "Command line parsing failed: " << e.what() << std::endl;
        return 1;
    }
    
    if(vm.count("help")) {
        std::cout << all_options << std::endl;
        return 1;
    }

    email_id_bimap email_id;
    connectedness_graph cg;
    entity_map em;
    initial_group_partition_map igpm;

    if(!vm.count("save-raw")) {
        std::cout << "you must specify --save-raw with a file name" << std::endl;
        return 1;
    }
    if(!vm.count("password")) {
        password = getpass("Password: "******"missing server for download" << std::endl;
        return 1;
    }
    if(user.empty()) {
        std::cout << "missing user for download" << std::endl;
        return 1;
    }
    if(password.empty()) {
        std::cout << "missing user for download" << std::endl;
        return 1;
    }
    //this is our network block, downloads all messages headers
    try
    {
        std::cout << "downloading " << folder << " from " << server << std::endl;
        //use to dedupe if there are dupes
        message_id_set message_id;        

        typedef boost::function<void (const std::string&, const std::list<std::string>& args)> untagged_handler;
        std::string pending_tag = "* ";
        std::list<std::string> pending_command;
        pending_command.push_back("WAIT_FOR_ACK");
        untagged_handler pending_handler;
        unsigned int command_id = 0;

        //The sequence of imap commands we want to run
        std::list<std::list<std::string> > commands;
        std::list<untagged_handler> handlers;

        handlers.push_back(log_handler());
        commands.push_back(std::list<std::string>());
        std::ostringstream login_os;
        login_os << "LOGIN \"" << user << "\" {" << password.size() << "}";
        commands.back().push_back(login_os.str()); 
        commands.back().push_back(password); 

        handlers.push_back(log_handler());
        commands.push_back(std::list<std::string>());
        commands.back().push_back("LIST \"\" *"); 

        handlers.push_back(log_handler());
        commands.push_back(std::list<std::string>());
        commands.back().push_back("SELECT \"" + folder + "\""); 

        handlers.push_back(header_handler(email_id, cg, em, message_id, igpm));
        commands.push_back(std::list<std::string>());
        commands.back().push_back("FETCH 1:* (BODY.PEEK[HEADER.FIELDS (MESSAGE-ID FROM TO CC)])");
        commands.push_back(std::list<std::string>());

        handlers.push_back(log_handler());
        commands.back().push_back("LOGOUT");
    
        //open ssl connection to the server, no cert checking
        asio::io_service io_service;
        asio::ip::tcp::resolver resolver(io_service);
        asio::ip::tcp::resolver::query query(server, port);
        asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
        asio::ssl::context context(io_service, asio::ssl::context::sslv23);
        context.set_verify_mode(asio::ssl::context::verify_none);
        asio::ssl::stream<asio::ip::tcp::socket> socket(io_service, context);
        socket.lowest_layer().connect(*iterator);
        socket.handshake(asio::ssl::stream_base::client);
        asio::streambuf buf;

        while(true) {
            //read the next line of data
            std::size_t line_length = asio::read_until(socket, buf, re_crlf);
            std::string line(
                asio::buffers_begin(buf.data()),
                asio::buffers_begin(buf.data()) + line_length);
            buf.consume(line_length);
            boost::match_results<std::string::iterator> what;
            std::size_t initial = 0;
            std::list<std::string> args;
            //the line may be split into segments with chunks of data embedded, this is the case
            //for bodies or message header blocks that are returned, we only handle this case if it
            //comes in untagged response (*) not a continuation (+), i think that is normal
            while(regex_search(line.begin() + initial, line.end(), what, re_byte_buffer, boost::match_default)) {
                unsigned int bytes = boost::lexical_cast<unsigned int>(what[1].str());
                if(buf.size() < bytes)
                    asio::read(socket, buf, asio::transfer_at_least(bytes - buf.size()));
                args.push_back(
                    std::string(
                        asio::buffers_begin(buf.data()),
                        asio::buffers_begin(buf.data()) + bytes));
                buf.consume(bytes);
                line.resize(what[1].second - line.begin());
                initial = line.size();
                //read the next line of data
                line_length = asio::read_until(socket, buf, re_crlf);
                line += std::string(
                    asio::buffers_begin(buf.data()),
                    asio::buffers_begin(buf.data()) + line_length);
                buf.consume(line_length);
            }
            if(boost::algorithm::starts_with(line, pending_tag)) {
                //if the command is being completed, then we will go here, bail out if the response wasn't ok
                if(!boost::algorithm::starts_with(line, pending_tag + "OK")) {
                    std::cout << line;
                    throw std::runtime_error("command failed");
                }
                //pull the next command off the list
                pending_tag = "A" + boost::lexical_cast<std::string>(command_id++) + " ";
                if(commands.size() == 0)
                    break;
                pending_handler = handlers.front();
                pending_command = commands.front();
                commands.pop_front();
                handlers.pop_front();

                //send the command along with any data arguments
                std::cout << pending_tag << pending_command.front() << std::endl;
                asio::write(socket, asio::buffer(pending_tag.data(), pending_tag.size()));
                for(std::list<std::string>::iterator i = pending_command.begin(); i != pending_command.end(); ++i) {
                    if(i != pending_command.begin()) {
                        //print the continuation response
                        std::size_t line_length = asio::read_until(socket, buf, re_crlf);
                        std::string line(
                            asio::buffers_begin(buf.data()),
                            asio::buffers_begin(buf.data()) + line_length);
                        buf.consume(line_length);
                        std::cout << line << std::flush;
                        if(!boost::algorithm::starts_with(line, "+ ")) {
                            throw std::runtime_error("bad response when writing extra data");
                        }
                    } else {
                        //print it out as well (but not the args)
                        std::cout << *i << std::endl;
                    }
                    asio::write(socket, asio::buffer(i->data(), i->size()));
                    asio::write(socket, asio::buffer("\r\n", 2));
                }
            } else if(boost::algorithm::starts_with(line, "* ")) {
                //if there is a registered handler, dispatch to it
                if(pending_handler)
                    pending_handler(line, args);
            } else {
                throw std::runtime_error("unrecognized response");
            }
        }
    }
    catch (std::exception& e) {
        std::cout << "Exception: " << e.what() << std::endl;
        return 1;
    }
    std::cout << std::endl;
    
    if(to.empty()) {
        std::cout << "Missing output file for save" << std::endl;
        return 1;
    }
    if(fs::exists(to))
        fs::remove(to);
    fs::ofstream out(to);
    std::cout << "saving data to " << to.file_string();        
    for(connectedness_graph::vertex_iterator i = gr::vertices(cg).first; i != gr::vertices(cg).second; ++i) {
        out << (unsigned long long)cg[*i].weight;
        for(members_t::iterator j = cg[*i].members.begin(); j != cg[*i].members.end(); ++j) {
            out << "\t" << email_id.by<bit>().equal_range(*j).first->second;
        }
        out << std::endl;
    }
    out << "-" << std::endl;
    for(entity_map::iterator i = em.begin(); i != em.end(); ++i) {
        out << i->first;
        for(std::set<std::string>::iterator k = i->second.begin(); k != i->second.end(); ++k) {
            out << "\t" << *k; 
        }
        out << std::endl;
    }
    return 0;
}