00001
00002
00003
00004
00005
00006
00007 #include "uniconfdaemonconn.h"
00008 #include "uniconfdaemon.h"
00009 #include "wvtclstring.h"
00010 #include "wvstrutils.h"
00011
00012
00013
00014
00015 UniConfDaemonConn::UniConfDaemonConn(WvStream *_s, const UniConf &_root)
00016 : UniClientConn(_s), root(_root)
00017 {
00018 uses_continue_select = true;
00019 addcallback();
00020 writecmd(EVENT_HELLO,
00021 spacecat(wvtcl_escape("UniConf Server ready."),
00022 wvtcl_escape(UNICONF_PROTOCOL_VERSION)));
00023 }
00024
00025
00026 UniConfDaemonConn::~UniConfDaemonConn()
00027 {
00028 close();
00029 terminate_continue_select();
00030 delcallback();
00031 }
00032
00033
00034 void UniConfDaemonConn::close()
00035 {
00036 UniClientConn::close();
00037 }
00038
00039
00040 void UniConfDaemonConn::addcallback()
00041 {
00042 root.add_callback(this, wv::bind(&UniConfDaemonConn::deltacallback, this,
00043 _1, _2), true);
00044 }
00045
00046
00047 void UniConfDaemonConn::delcallback()
00048 {
00049 root.del_callback(this, true);
00050 }
00051
00052
00053 void UniConfDaemonConn::execute()
00054 {
00055 UniClientConn::execute();
00056
00057 WvString command_string;
00058 UniClientConn::Command command = readcmd(command_string);
00059
00060 if (command != UniClientConn::NONE)
00061 {
00062
00063 WvString arg1(readarg());
00064 WvString arg2(readarg());
00065 switch (command)
00066 {
00067 case UniClientConn::NONE:
00068 break;
00069
00070 case UniClientConn::INVALID:
00071 do_invalid(command_string);
00072 break;
00073
00074 case UniClientConn::REQ_NOOP:
00075 do_noop();
00076 break;
00077
00078 case UniClientConn::REQ_GET:
00079 if (arg1.isnull())
00080 do_malformed(command);
00081 else
00082 do_get(arg1);
00083 break;
00084
00085 case UniClientConn::REQ_SET:
00086 if (arg1.isnull() || arg2.isnull())
00087 do_malformed(command);
00088 else
00089 do_set(arg1, arg2);
00090 break;
00091
00092 case UniClientConn::REQ_REMOVE:
00093 if (arg1.isnull())
00094 do_malformed(command);
00095 else
00096 do_remove(arg1);
00097 break;
00098
00099 case UniClientConn::REQ_SUBTREE:
00100 if (arg1.isnull())
00101 do_malformed(command);
00102 else
00103 do_subtree(arg1, arg2.num() == 1);
00104 break;
00105
00106 case UniClientConn::REQ_HASCHILDREN:
00107 if (arg1.isnull())
00108 do_malformed(command);
00109 else
00110 do_haschildren(arg1);
00111 break;
00112
00113 case UniClientConn::REQ_COMMIT:
00114 do_commit();
00115 break;
00116
00117 case UniClientConn::REQ_REFRESH:
00118 do_refresh();
00119 break;
00120
00121 case UniClientConn::REQ_QUIT:
00122 do_quit();
00123 break;
00124
00125 case UniClientConn::REQ_HELP:
00126 do_help();
00127 break;
00128
00129 default:
00130 do_invalid(command_string);
00131 break;
00132 }
00133 }
00134 }
00135
00136
00137 void UniConfDaemonConn::do_invalid(WvStringParm c)
00138 {
00139 writefail(WvString("unknown command: %s", c));
00140 }
00141
00142
00143 void UniConfDaemonConn::do_malformed(UniClientConn::Command c)
00144 {
00145 writefail(WvString("malformed request: %s",
00146 UniClientConn::cmdinfos[c].name));
00147 }
00148
00149
00150 void UniConfDaemonConn::do_noop()
00151 {
00152 writeok();
00153 }
00154
00155
00156 void UniConfDaemonConn::do_reply(WvStringParm reply)
00157 {
00158 writefail("unexpected reply");
00159 }
00160
00161
00162 void UniConfDaemonConn::do_get(const UniConfKey &key)
00163 {
00164 WvString value(root[key].getme());
00165
00166 if (value.isnull())
00167 writefail();
00168 else
00169 writeonevalue(key, value);
00170 }
00171
00172
00173 void UniConfDaemonConn::do_set(const UniConfKey &key, WvStringParm value)
00174 {
00175 root[key].setme(value);
00176 }
00177
00178
00179 void UniConfDaemonConn::do_remove(const UniConfKey &_key)
00180 {
00181 int notifications_sent = 0;
00182 bool single_key = true;
00183
00184
00185 WvString strkey = _key;
00186 for (int n = strkey.len()-1; n > 0; n--)
00187 {
00188 if (strkey.edit()[n] == '/')
00189 strkey.edit()[n] = ' ';
00190 else
00191 break;
00192 }
00193
00194 trim_string(strkey.edit());
00195
00196 UniConfKey key = strkey;
00197
00198
00199 UniConf cfg(root[key]);
00200
00201 if (cfg.exists())
00202 {
00203 UniConf::RecursiveIter it(cfg);
00204 for (it.rewind(); it.next(); )
00205 {
00206 single_key = false;
00207 WvString sect_name = getdirname(it->fullkey());
00208 root[it->fullkey()].remove();
00209
00210 if (sect_name == ".")
00211 sect_name = WvString::null;
00212
00213 if (!root[sect_name].haschildren())
00214 root[sect_name].remove();
00215
00216
00217 if (++notifications_sent > CONTINUE_SELECT_AT)
00218 {
00219 notifications_sent = 0;
00220
00221 if (isok())
00222 continue_select(0);
00223 }
00224 }
00225
00226 if (single_key)
00227 root[key].remove();
00228 }
00229 }
00230
00231
00232 void UniConfDaemonConn::do_subtree(const UniConfKey &key, bool recursive)
00233 {
00234 static int niceness = 0;
00235
00236 UniConf cfg(root[key]);
00237 if (cfg.exists())
00238 {
00239 if (recursive)
00240 {
00241 UniConf::RecursiveIter it(cfg);
00242 for (it.rewind(); it.next(); )
00243 {
00244 writevalue(it->fullkey(cfg), it._value());
00245
00246
00247
00248
00249 if (!isok()) break;
00250 if (++niceness > CONTINUE_SELECT_AT)
00251 {
00252 niceness = 0;
00253 continue_select(0);
00254 }
00255 }
00256 }
00257 else
00258 {
00259 UniConf::Iter it(cfg);
00260 for (it.rewind(); it.next(); )
00261 {
00262 writevalue(it->fullkey(cfg), it._value());
00263
00264
00265
00266
00267 if (!isok()) break;
00268 continue_select(0);
00269 }
00270 }
00271 writeok();
00272 }
00273 else
00274 writefail();
00275 }
00276
00277 void UniConfDaemonConn::do_haschildren(const UniConfKey &key)
00278 {
00279 bool haschild = root[key].haschildren();
00280 writecmd(REPLY_CHILD,
00281 spacecat(wvtcl_escape(key), haschild ? "TRUE" : "FALSE"));
00282 }
00283
00284
00285 void UniConfDaemonConn::do_commit()
00286 {
00287 root.commit();
00288 writeok();
00289 }
00290
00291
00292 void UniConfDaemonConn::do_refresh()
00293 {
00294 if (root.refresh())
00295 writeok();
00296 else
00297 writefail();
00298 }
00299
00300
00301 void UniConfDaemonConn::do_quit()
00302 {
00303 writeok();
00304 close();
00305 }
00306
00307
00308 void UniConfDaemonConn::do_help()
00309 {
00310 for (int i = 0; i < UniClientConn::NUM_COMMANDS; ++i)
00311 writetext(UniClientConn::cmdinfos[i].description);
00312 writeok();
00313 }
00314
00315
00316 void UniConfDaemonConn::deltacallback(const UniConf &cfg, const UniConfKey &key)
00317 {
00318
00319
00320
00321 WvString value(cfg[key].getme());
00322 WvString msg;
00323
00324 UniConfKey fullkey(cfg.fullkey(cfg));
00325 fullkey.append(key);
00326
00327 if (value.isnull())
00328 msg = wvtcl_escape(fullkey);
00329 else
00330 msg = spacecat(wvtcl_escape(fullkey),
00331 wvtcl_escape(cfg[key].getme()));
00332
00333 writecmd(UniClientConn::EVENT_NOTICE, msg);
00334 }