250 lines
6.7 KiB
C++
250 lines
6.7 KiB
C++
/*
|
|
* Copyright (C) 2019 Adrien Destugues <pulkomandy@pulkomandy.tk>
|
|
*
|
|
* Distributed under terms of the MIT license.
|
|
*/
|
|
|
|
#include "GlooxHandler.h"
|
|
|
|
#include "bob.h"
|
|
#include "BobStore.h"
|
|
#include "Extensions.h"
|
|
#include "media.h"
|
|
|
|
#include "support/LogHandler.h"
|
|
|
|
#include <GridView.h>
|
|
#include <LayoutBuilder.h>
|
|
#include <String.h>
|
|
#include <StringView.h>
|
|
#include <TextView.h>
|
|
|
|
#include <gloox/dataformitem.h>
|
|
|
|
|
|
GlooxHandler::GlooxHandler(gloox::Client* client)
|
|
: BHandler("gloox connection")
|
|
, fClient(client)
|
|
{
|
|
// Configure logging through BeDC
|
|
fClient->logInstance().registerLogHandler(gloox::LogLevelDebug,
|
|
gloox::LogAreaAll, new LogHandler());
|
|
|
|
fRegistration = new gloox::Registration(fClient);
|
|
fRegistration->registerRegistrationHandler(this);
|
|
fClient->registerConnectionListener(this);
|
|
|
|
// BOB handling was in a former gloox 1.1 branch but was deleted?
|
|
// So we have our own version, but we must register it here.
|
|
gloox::BOB* bob = new gloox::BOB();
|
|
bob->RegisterBobHandler(BobStore::Instance());
|
|
fClient->registerStanzaExtension(bob);
|
|
|
|
// And this one isn't in Gloox yet. TODO upstream it
|
|
Media* media = new Media();
|
|
media->RegisterMediaHandler(this);
|
|
fClient->registerStanzaExtension(media);
|
|
}
|
|
|
|
void GlooxHandler::Run()
|
|
{
|
|
thread_id thread = spawn_thread(GlooxThread, "gloox connection", B_LOW_PRIORITY, this);
|
|
resume_thread(thread);
|
|
}
|
|
|
|
|
|
int32 GlooxHandler::GlooxThread(void* arg)
|
|
{
|
|
GlooxHandler* object = (GlooxHandler*)arg;
|
|
|
|
object->fClient->connect();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void GlooxHandler::handleRegistrationFields(const gloox::JID&, int, std::string)
|
|
{
|
|
SendNotices(kRegistrationFields);
|
|
}
|
|
|
|
|
|
void GlooxHandler::handleAlreadyRegistered(const gloox::JID&)
|
|
{
|
|
SendNotices(kAlreadyRegistered);
|
|
}
|
|
|
|
|
|
void GlooxHandler::handleRegistrationResult(const gloox::JID& from, gloox::RegistrationResult result)
|
|
{
|
|
BMessage* message = new BMessage(kRegistrationResult);
|
|
message->AddString("gloox::JID", from.full().c_str());
|
|
message->AddInt32("gloox::RegistrationResult", result);
|
|
SendNotices(kRegistrationResult, message);
|
|
}
|
|
|
|
|
|
void GlooxHandler::handleDataForm(const gloox::JID& from, const gloox::DataForm& form)
|
|
{
|
|
BMessage message(kDataForm);
|
|
|
|
BGridView* registrationForm = new BGridView("gloox::DataForm");
|
|
|
|
int line = 0;
|
|
|
|
if (!form.title().empty()) {
|
|
BStringView* titleView = new BStringView("gloox::title", form.title().c_str());
|
|
titleView->SetFont(be_bold_font);
|
|
|
|
BLayoutBuilder::Grid<>(registrationForm).Add(titleView, 0, line++, 3, 1);
|
|
}
|
|
|
|
if (!form.instructions().empty()) {
|
|
BString instructions;
|
|
for (const auto& line: form.instructions()) {
|
|
instructions << line.c_str() << "\n";
|
|
}
|
|
|
|
BTextView* instructionsView = new BTextView("gloox::instructions");
|
|
instructionsView->MakeEditable(false);
|
|
instructionsView->MakeSelectable(false);
|
|
instructionsView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
|
|
instructionsView->SetText(instructions);
|
|
float charSize = instructionsView->StringWidth("W");
|
|
instructionsView->SetExplicitMinSize(BSize(charSize * 30, charSize * 7));
|
|
|
|
BLayoutBuilder::Grid<>(registrationForm).Add(instructionsView, 0, line++, 3, 1);
|
|
}
|
|
|
|
bool hasRequiredFields = false;
|
|
|
|
for (auto f: form.fields()) {
|
|
switch(f->type()) {
|
|
case gloox::DataFormField::TypeTextSingle:
|
|
case gloox::DataFormField::TypeTextPrivate:
|
|
case gloox::DataFormField::TypeHidden:
|
|
{
|
|
BTextControl* fieldView = new BTextControl(f->name().c_str(),
|
|
f->label().c_str(), f->value().c_str(), NULL);
|
|
if (!f->description().empty()) {
|
|
fieldView->SetToolTip(f->description().c_str());
|
|
}
|
|
BLayoutBuilder::Grid<>(registrationForm).Add(
|
|
fieldView->CreateLabelLayoutItem(), 0, line);
|
|
BLayoutBuilder::Grid<>(registrationForm).Add(
|
|
fieldView->CreateTextViewLayoutItem(), 1, line);
|
|
if (f->required() && f->type() != gloox::DataFormField::TypeHidden) {
|
|
BLayoutBuilder::Grid<>(registrationForm).Add(
|
|
new BStringView("gloox::requiredMarker", "*"), 2, line);
|
|
}
|
|
|
|
if (f->type() == gloox::DataFormField::TypeTextPrivate) {
|
|
fieldView->TextView()->HideTyping(true);
|
|
}
|
|
if (f->type() == gloox::DataFormField::TypeHidden) {
|
|
fieldView->Hide();
|
|
}
|
|
break;
|
|
}
|
|
case gloox::DataFormField::TypeFixed:
|
|
{
|
|
BStringView* fieldView = new BStringView(f->name().c_str(), f->value().c_str());
|
|
if (!f->description().empty()) {
|
|
fieldView->SetToolTip(f->description().c_str());
|
|
}
|
|
if (!f->label().empty()) {
|
|
fprintf(stderr, "Fixed field without label\n");
|
|
}
|
|
BLayoutBuilder::Grid<>(registrationForm).Add(
|
|
fieldView, 0, line, 2, 1);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
fprintf(stderr, "Unhandled form type %d for %s [%s] (%d)\n",
|
|
f->type(), f->name().c_str(), f->label().c_str(), f->required());
|
|
break;
|
|
}
|
|
}
|
|
line++;
|
|
}
|
|
|
|
if (hasRequiredFields) {
|
|
BLayoutBuilder::Grid<>(registrationForm).Add(
|
|
new BStringView("footer", "* required fields"), 0, line++);
|
|
}
|
|
#if 1
|
|
// FIXME need to handle nested items if there are some
|
|
for (const gloox::DataFormItem* i: form.items()) {
|
|
fprintf(stderr, "-------------\n");
|
|
for (auto f: i->fields()) {
|
|
fprintf(stderr, "%s [%s] (%d)\n", f->name().c_str(),
|
|
f->label().c_str(), f->required());
|
|
}
|
|
}
|
|
#endif
|
|
|
|
registrationForm->Archive(&message);
|
|
delete registrationForm;
|
|
|
|
message.AddString("gloox::JID", from.full().c_str());
|
|
SendNotices(kDataForm, &message);
|
|
}
|
|
|
|
|
|
void GlooxHandler::handleOOB(const gloox::JID&, const gloox::OOB& oob)
|
|
{
|
|
BMessage message(kOOB);
|
|
message.AddString("url", oob.url().c_str());
|
|
message.AddString("desc", oob.desc().c_str());
|
|
SendNotices(kOOB, &message);
|
|
}
|
|
|
|
|
|
void GlooxHandler::onConnect()
|
|
{
|
|
// Ok, not very clean, the listener could tell us to do that instead...
|
|
if (fRegistration)
|
|
fRegistration->fetchRegistrationFields();
|
|
SendNotices(kConnect);
|
|
}
|
|
|
|
|
|
void GlooxHandler::onDisconnect(gloox::ConnectionError error)
|
|
{
|
|
BMessage message(kDisconnect);
|
|
message.AddInt32("gloox::ConnectionError", error);
|
|
if (error == gloox::ConnStreamError)
|
|
message.AddInt32("gloox::StreamError", fClient->streamError());
|
|
SendNotices(kDisconnect, &message);
|
|
}
|
|
|
|
|
|
bool GlooxHandler::onTLSConnect(const gloox::CertInfo& info)
|
|
{
|
|
// TODO let the listener (if any?) decide what to do with invalid
|
|
// certificates. Add the relevant info to the notice, and wait for a
|
|
// reply before moving on. But what if the listener does not reply or if
|
|
// there is no listener?
|
|
|
|
// TODO add the relevant fields to the notice so the listener can make a
|
|
// decision
|
|
SendNotices(kTLSConnect);
|
|
return info.status == gloox::CertOk;
|
|
}
|
|
|
|
|
|
void GlooxHandler::handleMedia(const Media* media)
|
|
{
|
|
BMessage message(kMedia);
|
|
message.AddString("type", media->type().c_str());
|
|
message.AddString("uri", media->uri().c_str());
|
|
SendNotices(kMedia, &message);
|
|
}
|
|
|
|
|
|
void GlooxHandler::createAccount(gloox::DataForm* form)
|
|
{
|
|
fRegistration->createAccount(form);
|
|
}
|