~vcs-imports/cyphesis/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// Cyphesis Online RPG Server and AI Engine
// Copyright (C) 2001-2005 Alistair Riddoch
//
// This program 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 of the License, or
// (at your option) any later version.
// 
// This program 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 this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

// $Id: cyaddrules.cpp,v 1.18 2008-11-07 04:04:55 alriddoch Exp $

/// \page cyaddrules_index
///
/// \section Introduction
///
/// cyaddrules is a non-interactive commandline tool to upload rules files
/// into a running server. For information on the usage, please see the unix
/// manual page. The manual page is generated from docbook sources, so can
/// also be converted into other formats.
///
/// The code to interact with the server is encapsulated in the AdminClient
/// class, which is shared with other tools.

#include "AdminClient.h"

#include "common/Database.h"
#include "common/globals.h"
#include "common/log.h"

#include <Atlas/Objects/Decoder.h>
#include <Atlas/Codecs/XML.h>

#include <varconf/config.h>

#include <string>
#include <fstream>

#include <dirent.h>

using Atlas::Message::MapType;

/// \brief Class that handles reading in a rules file, and loading the
/// contents to the server via the AdminClient.
class ServerRulesFileLoader : public Atlas::Message::DecoderBase
{
    /// \brief iostream for accessing the rules file.
    std::fstream m_file;

    /// \brief Name of the ruleset to be loaded.
    std::string m_ruleset;

    /// \brief Client object to handle the connection to the server.
    AdminClient & m_client;

    /// \brief Atlas codec used to decode the contents of the rules file.
    Atlas::Codecs::XML m_codec;

    /// \brief Count of classes uploaded to the server.
    int m_count;

    /// \brief Count of classes read from the file.
    int m_total;

    /// \brief Method called from the base class when a complete message
    /// is read from the file.
    virtual void messageArrived(const MapType & omap) {
        MapType::const_iterator I = omap.find("id");
        if (I == omap.end()) {
            std::cerr << "Found rule with no id" << std::endl << std::flush;
            return;
        }
        if (!I->second.isString()) {
            std::cerr << "Found rule with non string id" << std::endl << std::flush;
            return;
        }
        m_total++;
        // m_rules[I->second.asString()] = obj.asMap();
        int ret = m_client.uploadRule(I->second.asString(), m_ruleset, omap);
        if (ret > 0) {
            m_count += ret;
        }
    }
  public:
    /// \brief ServerRulesFileLoader constructor
    ///
    /// @param filename name of the rules file to be loaded
    /// @param ruleset name of the ruleset the file represents
    /// @param client client object that uploads rules to the server
    ServerRulesFileLoader(const std::string & filename,
                          const std::string & ruleset,
                          AdminClient & client) :
                          m_file(filename.c_str(), std::ios::in),
                          m_ruleset(ruleset), m_client(client),
                          m_codec(m_file, *this), m_count(0), m_total(0)
    {
    }

    /// \brief Read the contents of the file to the end
    void read() {
        while (!m_file.eof()) {
            m_codec.poll();
        }
    }

    /// \brief Send a report of rules laoded and uploaded to standard out
    void report() {
        std::cout << m_count << " new classes uploaded out of "
                  << m_total << " loaded from file."
                  << std::endl << std::flush;
    }

    /// \brief Indicate whether the file has been opened successfully
    bool isOpen() {
        return m_file.is_open();
    }
};

static void usage(char * prgname)
{
    std::cerr << "usage: " << prgname << " [<rulesetname> <atlas-xml-file>]" << std::endl << std::flush;
}

int main(int argc, char ** argv)
{
    int config_status = loadConfig(argc, argv, USAGE_CYCMD);
    if (config_status < 0) {
        if (config_status == CONFIG_VERSION) {
            reportVersion(argv[0]);
            return 0;
        } else if (config_status == CONFIG_HELP) {
            showUsage(argv[0], USAGE_CYCMD, "[<rulesetname> <atlas-xml-file>]");
            return 0;
        } else if (config_status != CONFIG_ERROR) {
            log(ERROR, "Unknown error reading configuration.");
        }
        // Fatal error loading config file
        return 1;
    }

    int optind = config_status;

    AdminClient bridge;

    std::string server;
    readConfigItem("client", "serverhost", server);

    int useslave = 0;
    readConfigItem("client", "useslave", useslave);

    std::string username("admin");
    readConfigItem("client", "account", username);
    bridge.setUsername(username);

    std::string passwd;
    if (readConfigItem("client", "password", passwd) == 0) {
        bridge.setPassword(passwd);
    }
    passwd.clear();

    if (server.empty()) {
        std::string localSocket;
        if (useslave != 0) {
            localSocket = slave_socket_name;
        } else {
            localSocket = client_socket_name;
        }

        if (bridge.connect_unix(localSocket) != 0) {
            std::cerr << "Failed to connect to local server"
                      << std::endl << std::flush;
            return 1;
        }
    } else {
        if (bridge.connect(server) != 0) {
            std::cerr << "Failed to connect to remote server"
                      << std::endl << std::flush;
            return 1;
        }
    }

    if (bridge.login() != 0) {
        std::cerr << "Login failed." << std::endl << std::flush;
        bridge.getLogin();

        if (!bridge.login()) {
            std::cerr << "Login failed." << std::endl << std::flush;
            return 1;
        }
    }

    if (optind == (argc - 2)) {
        ServerRulesFileLoader f(argv[optind + 1], argv[optind], bridge);
        if (!f.isOpen()) {
            std::cerr << "ERROR: Unable to open file " << argv[optind + 1]
                      << std::endl << std::flush;
            return 1;
        }
        f.read();
        f.report();
    } else if (optind == argc) {
        std::cout << "Reading rules from " << ruleset << std::endl << std::flush;
        std::string filename;

        std::string dirname = etc_directory + "/cyphesis/" + ruleset + ".d";
        DIR * rules_dir = ::opendir(dirname.c_str());
        if (rules_dir == 0) {
            filename = etc_directory + "/cyphesis/" + ruleset + ".xml";
            ServerRulesFileLoader f(filename, ruleset, bridge);
            if (f.isOpen()) {
                std::cerr << "WARNING: Reading legacy rule data from \""
                          << filename << "\""
                          << std::endl << std::flush;
                f.read();
                f.report();
            }
        } else {
            while (struct dirent * rules_entry = ::readdir(rules_dir)) {
                if (rules_entry->d_name[0] == '.') {
                    continue;
                }
                filename = dirname + "/" + rules_entry->d_name;
    
                ServerRulesFileLoader f(filename, ruleset, bridge);
                if (!f.isOpen()) {
                    std::cerr << "ERROR: Unable to open file " << filename
                              << std::endl << std::flush;
                } else {
                    f.read();
                    f.report();
                }
            }
        }
    } else {
        usage(argv[0]);
        return 1;
    }

    bridge.report();

    return 0;
}