Browse Source

rspamc: add action number in first line and improve code

tags/3.5
Amish 1 year ago
parent
commit
42e1c8d507
3 changed files with 127 additions and 38 deletions
  1. 9
    1
      doc/rspamc.1
  2. 2
    1
      doc/rspamc.1.md
  3. 116
    36
      src/client/rspamc.cxx

+ 9
- 1
doc/rspamc.1 View File

.RE .RE
.TP .TP
.B \-R, \-\-human .B \-R, \-\-human
Output human readable report
Output human readable report.
The first line of the output contains the message score and three
threshold scores, in this format:
.IP
.nf
\f[C]
score/greylist/addheader/reject,action=N:ACTION,spam=0|1,skipped=0|1
\f[]
.fi
.RS .RS
.RE .RE
.TP .TP

+ 2
- 1
doc/rspamc.1.md View File

: Bind to specified ip address : Bind to specified ip address


-R, \--human -R, \--human
: Output human readable report
: Output human readable report. The first line of the output contains the message score and three threshold scores, in this format:
: score/greylist/addheader/reject,action=N:ACTION,spam=0|1,skipped=0|1


-j, \--json -j, \--json
: Output formatted JSON : Output formatted JSON

+ 116
- 36
src/client/rspamc.cxx View File

} }


static void static void
print_indented_line(FILE *out, std::string line, size_t maxlen, size_t indent)
print_indented_line(FILE *out, std::string_view line, size_t maxlen, size_t indent)
{ {
if (maxlen < 1) return;
if (maxlen < 1) {
return;
}


std::string s;
for (size_t pos = 0; pos < line.length(); pos += s.length()) {
std::string_view s;
for (size_t pos = 0; pos < line.size(); pos += s.size()) {
s = line.substr(pos, pos ? (maxlen-indent) : maxlen); s = line.substr(pos, pos ? (maxlen-indent) : maxlen);
if (indent && pos) fmt::print(out, "{:>{}}", " ", indent);
if (indent && pos) {
fmt::print(out, "{:>{}}", " ", indent);
}
fmt::print(out, "{}\n", s); fmt::print(out, "{}\n", s);
} }
} }
rspamc_symbol_human_output(FILE *out, const ucl_object_t *obj) rspamc_symbol_human_output(FILE *out, const ucl_object_t *obj)
{ {
auto first = true; auto first = true;
double score = 0;
const char *key = nullptr, *desc = nullptr;
auto score = 0.0;
const char *desc = nullptr;


const auto *key = ucl_object_key(obj);
const auto *val = ucl_object_lookup(obj, "score"); const auto *val = ucl_object_lookup(obj, "score");
if (val != nullptr) score = ucl_object_todouble(val);
if (val != nullptr) {
score = ucl_object_todouble(val);
}


key = ucl_object_key(obj);
val = ucl_object_lookup(obj, "description"); val = ucl_object_lookup(obj, "description");
if (val != nullptr) desc = ucl_object_tostring(val);
if (val != nullptr) {
desc = ucl_object_tostring(val);
}


std::string line = fmt::format("{:>4.1f} {:<22} ", score, key);
if (desc != nullptr) line += desc;
auto line = fmt::format("{:>4.1f} {:<22} ", score, key);
if (desc != nullptr) {
line += desc;
}


val = ucl_object_lookup(obj, "options"); val = ucl_object_lookup(obj, "options");
if (val != nullptr && val->type == UCL_ARRAY) {
if (val != nullptr && ucl_object_type(val) == UCL_ARRAY) {
ucl_object_iter_t it = nullptr; ucl_object_iter_t it = nullptr;
const ucl_object_t *cur; const ucl_object_t *cur;


} }
line += ']'; line += ']';
} }
else if (desc == nullptr) line += '\n';
else if (desc == nullptr) {
line += '\n';
}


print_indented_line(out, line, 78, 28); print_indented_line(out, line, 78, 28);
} }
fmt::print(out, "({:.2f})", ucl_object_todouble(val)); fmt::print(out, "({:.2f})", ucl_object_todouble(val));
} }
val = ucl_object_lookup(obj, "options"); val = ucl_object_lookup(obj, "options");
if (val != nullptr && val->type == UCL_ARRAY) {
if (val != nullptr && ucl_object_type(val) == UCL_ARRAY) {
ucl_object_iter_t it = nullptr; ucl_object_iter_t it = nullptr;
const ucl_object_t *cur; const ucl_object_t *cur;


static void static void
rspamc_metric_output(FILE *out, const ucl_object_t *obj) rspamc_metric_output(FILE *out, const ucl_object_t *obj)
{ {
double score = 0, required_score = 0;
int got_scores = 0; int got_scores = 0;
bool is_spam = false, is_skipped = false;
double score = 0, required_score = 0, greylist_score =0, addheader_score = 0;


auto print_protocol_string = [&](const char *ucl_name, const char *output_message) { auto print_protocol_string = [&](const char *ucl_name, const char *output_message) {
auto *elt = ucl_object_lookup(obj, ucl_name); auto *elt = ucl_object_lookup(obj, ucl_name);
if (elt) { if (elt) {
fmt::print(out, fmt::runtime(humanreport ? ",{}={}" : "{}: {}\n"), output_message,
emphasis_argument(ucl_object_tostring(elt)));
if (humanreport) {
fmt::print(out, ",{}={}", output_message, emphasis_argument(ucl_object_tostring(elt)));
}
else {
fmt::print(out, "{}: {}\n", output_message, emphasis_argument(ucl_object_tostring(elt)));
}
} }
}; };


if (!humanreport) fmt::print(out, "[Metric: default]\n");
if (!humanreport) {
fmt::print(out, "[Metric: default]\n");
}


const auto *elt = ucl_object_lookup(obj, "required_score"); const auto *elt = ucl_object_lookup(obj, "required_score");

if (elt) { if (elt) {
required_score = ucl_object_todouble(elt); required_score = ucl_object_todouble(elt);
got_scores++; got_scores++;
} }


elt = ucl_object_lookup(obj, "score"); elt = ucl_object_lookup(obj, "score");

if (elt) { if (elt) {
score = ucl_object_todouble(elt); score = ucl_object_todouble(elt);
got_scores++; got_scores++;
} }


/* XXX: greylist_score is not yet in checkv2 */
elt = ucl_object_lookup(obj, "greylist_score");
if (elt) {
greylist_score = ucl_object_todouble(elt);
}

/* XXX: addheader_score is not yet in checkv2 */
elt = ucl_object_lookup(obj, "addheader_score");
if (elt) {
addheader_score = ucl_object_todouble(elt);
}

if (humanreport) { if (humanreport) {
fmt::print(out, fmt::print(out,
"{}/{}",
"{}/{}/{}/{}",
emphasis_argument(score, 2), emphasis_argument(score, 2),
emphasis_argument(greylist_score, 2),
emphasis_argument(addheader_score, 2),
emphasis_argument(required_score, 2)); emphasis_argument(required_score, 2));
} }




if (act.has_value()) { if (act.has_value()) {
if (!tty) { if (!tty) {
print_protocol_string("action", "Action");
if (humanreport) {
fmt::print(out, ",action={}:{}", act.value(), ucl_object_tostring(elt));
}
else {
print_protocol_string("action", "Action");
}
} }
else { else {
/* Colorize action type */ /* Colorize action type */
colorized_action = fmt::format(fmt::emphasis::bold, ucl_object_tostring(elt)); colorized_action = fmt::format(fmt::emphasis::bold, ucl_object_tostring(elt));
break; break;
} }
fmt::print(out, fmt::runtime(humanreport ? ",Action={}" : "Action: {}\n"), colorized_action);

if (humanreport) {
fmt::print(out, ",action={}:{}", act.value(), colorized_action);
}
else {
fmt::print(out, "Action: {}\n", colorized_action);
}
} }


fmt::print(out, fmt::runtime(humanreport ? ",Spam={}" : "Spam: {}\n"),
emphasis_argument(act.value() < METRIC_ACTION_GREYLIST ?
"true" : "false"));
is_spam = act.value() < METRIC_ACTION_GREYLIST ? true : false;
if (!humanreport) {
fmt::print(out, "Spam: {}\n", is_spam ? "true" : "false");
}
} }
else { else {
print_protocol_string("action", "Action");
if (humanreport) {
fmt::print(out, ",action={}:{}", METRIC_ACTION_NOACTION, ucl_object_tostring(elt));
}
else {
print_protocol_string("action", "Action");
}
} }
} }


if (!humanreport) print_protocol_string("subject", "Subject");
if (!humanreport) {
print_protocol_string("subject", "Subject");
}

if (humanreport) {
/* XXX: why checkv2 does not provide "is_spam"? */
elt = ucl_object_lookup(obj, "is_spam");
if (elt) {
is_spam = ucl_object_toboolean(elt);
}

elt = ucl_object_lookup(obj, "is_skipped");
if (elt) {
is_skipped = ucl_object_toboolean(elt);
}


if (humanreport) fmt::print(out, "\n");
fmt::print(out, ",spam={},skipped={}\n", is_spam ? 1 : 0, is_skipped ? 1 : 0);
}
else if (got_scores == 2) { else if (got_scores == 2) {
fmt::print(out, fmt::print(out,
"Score: {} / {}\n", "Score: {} / {}\n",
sort_ucl_container_with_default(symbols, "name"); sort_ucl_container_with_default(symbols, "name");


for (const auto *sym_obj : symbols) { for (const auto *sym_obj : symbols) {
if (humanreport) rspamc_symbol_human_output(out, sym_obj);
else rspamc_symbol_output(out, sym_obj);
humanreport ? rspamc_symbol_human_output(out, sym_obj) : rspamc_symbol_output(out, sym_obj);
} }
} }
if (humanreport) fmt::print(out, "\n");
if (humanreport) {
fmt::print(out, "\n");
}
} }


static void static void
emitted = (char *)ucl_object_emit(elt, UCL_EMIT_JSON); emitted = (char *)ucl_object_emit(elt, UCL_EMIT_JSON);
} }


if (emitted && strcmp(emitted, "[]")) fmt::print(out, "Urls: {}\n", emitted);
if (humanreport) {
if (emitted && strcmp(emitted, "[]")) {
print_indented_line(out, fmt::format("Domains found: {}", emitted), 78, 4);
}
}
else {
fmt::print(out, "Urls: {}\n", emitted);
}
free(emitted); free(emitted);
} }


emitted = (char *)ucl_object_emit(elt, UCL_EMIT_JSON); emitted = (char *)ucl_object_emit(elt, UCL_EMIT_JSON);
} }


if (emitted && strcmp(emitted, "[]")) fmt::print(out, "Emails: {}\n", emitted);
if (humanreport) {
if (emitted && strcmp(emitted, "[]")) {
print_indented_line(out, fmt::format("Emails found: {}", emitted), 78, 4);
}
}
else {
fmt::print(out, "Emails: {}\n", emitted);
}
free(emitted); free(emitted);
} }


print_protocol_string("error", "Scan error"); print_protocol_string("error", "Scan error");
if (humanreport) return;
if (humanreport) {
return;
}


elt = ucl_object_lookup(obj, "messages"); elt = ucl_object_lookup(obj, "messages");
if (elt && elt->type == UCL_OBJECT) { if (elt && elt->type == UCL_OBJECT) {

Loading…
Cancel
Save