[neon/backports-jammy/signon-ui/Neon/unstable] debian: make it work

Carlos De Maine null at kde.org
Wed Oct 4 04:26:48 BST 2023


Git commit 5f74e6db9e2842180d7eaa57edd7974f6625294a by Carlos De Maine.
Committed on 04/10/2023 at 05:26.
Pushed by carlosdem into branch 'Neon/unstable'.

make it work

M  +1    -1    debian/changelog
M  +1    -1    debian/control
A  +3553 -0    debian/patches/git.diff
M  +1    -1    debian/watch

https://invent.kde.org/neon/backports-jammy/signon-ui/-/commit/5f74e6db9e2842180d7eaa57edd7974f6625294a

diff --git a/debian/changelog b/debian/changelog
index 55826af..c75fc07 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-signon-ui (0.17+22.04.20171027+really20160406-0neon1) jammy; urgency=medium
+signon-ui (0.17+18.04.20171027+0neon) jammy; urgency=medium
 
   * Rebuild of 0.17+18.04.20160406-0ubuntu1 source with upstream patches 
     from gitlab that gets rid of webkit and uses webengine instead.
diff --git a/debian/control b/debian/control
index 4f250a2..505b8dc 100644
--- a/debian/control
+++ b/debian/control
@@ -19,7 +19,7 @@ Build-Depends: dbus-test-runner,
                libxext-dev,
                libxslt1-dev,
                pkg-config,
-               qtbase5-dev (>= 5.0.2+dfsg1-3ubuntu1),
+               qtbase5-dev,
                qtdeclarative5-dev,
                qtlocation5-dev,
                libqt5sensors5-dev,
diff --git a/debian/patches/git.diff b/debian/patches/git.diff
new file mode 100644
index 0000000..8a9e978
--- /dev/null
+++ b/debian/patches/git.diff
@@ -0,0 +1,3553 @@
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/HEAD" /tmp/src/signon-ui/.git/HEAD
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/HEAD"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/HEAD	2023-10-04 11:35:19.901523255 +1000
+@@ -0,0 +1 @@
++ref: refs/heads/master
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/config" /tmp/src/signon-ui/.git/config
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/config"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/config	2023-10-04 11:35:19.901523255 +1000
+@@ -0,0 +1,11 @@
++[core]
++	repositoryformatversion = 0
++	filemode = true
++	bare = false
++	logallrefupdates = true
++[remote "origin"]
++	url = https://gitlab.com/accounts-sso/signon-ui.git
++	fetch = +refs/heads/*:refs/remotes/origin/*
++[branch "master"]
++	remote = origin
++	merge = refs/heads/master
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/description" /tmp/src/signon-ui/.git/description
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/description"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/description	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1 @@
++Unnamed repository; edit this file 'description' to name the repository.
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/applypatch-msg.sample" /tmp/src/signon-ui/.git/hooks/applypatch-msg.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/applypatch-msg.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/applypatch-msg.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,15 @@
++#!/bin/sh
++#
++# An example hook script to check the commit log message taken by
++# applypatch from an e-mail message.
++#
++# The hook should exit with non-zero status after issuing an
++# appropriate message if it wants to stop the commit.  The hook is
++# allowed to edit the commit message file.
++#
++# To enable this hook, rename this file to "applypatch-msg".
++
++. git-sh-setup
++commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
++test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
++:
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/commit-msg.sample" /tmp/src/signon-ui/.git/hooks/commit-msg.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/commit-msg.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/commit-msg.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,24 @@
++#!/bin/sh
++#
++# An example hook script to check the commit log message.
++# Called by "git commit" with one argument, the name of the file
++# that has the commit message.  The hook should exit with non-zero
++# status after issuing an appropriate message if it wants to stop the
++# commit.  The hook is allowed to edit the commit message file.
++#
++# To enable this hook, rename this file to "commit-msg".
++
++# Uncomment the below to add a Signed-off-by line to the message.
++# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
++# hook is more suited to it.
++#
++# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
++# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
++
++# This example catches duplicate Signed-off-by lines.
++
++test "" = "$(grep '^Signed-off-by: ' "$1" |
++	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
++	echo >&2 Duplicate Signed-off-by lines.
++	exit 1
++}
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/fsmonitor-watchman.sample" /tmp/src/signon-ui/.git/hooks/fsmonitor-watchman.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/fsmonitor-watchman.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/fsmonitor-watchman.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,173 @@
++#!/usr/bin/perl
++
++use strict;
++use warnings;
++use IPC::Open2;
++
++# An example hook script to integrate Watchman
++# (https://facebook.github.io/watchman/) with git to speed up detecting
++# new and modified files.
++#
++# The hook is passed a version (currently 2) and last update token
++# formatted as a string and outputs to stdout a new update token and
++# all files that have been modified since the update token. Paths must
++# be relative to the root of the working tree and separated by a single NUL.
++#
++# To enable this hook, rename this file to "query-watchman" and set
++# 'git config core.fsmonitor .git/hooks/query-watchman'
++#
++my ($version, $last_update_token) = @ARGV;
++
++# Uncomment for debugging
++# print STDERR "$0 $version $last_update_token\n";
++
++# Check the hook interface version
++if ($version ne 2) {
++	die "Unsupported query-fsmonitor hook version '$version'.\n" .
++	    "Falling back to scanning...\n";
++}
++
++my $git_work_tree = get_working_dir();
++
++my $retry = 1;
++
++my $json_pkg;
++eval {
++	require JSON::XS;
++	$json_pkg = "JSON::XS";
++	1;
++} or do {
++	require JSON::PP;
++	$json_pkg = "JSON::PP";
++};
++
++launch_watchman();
++
++sub launch_watchman {
++	my $o = watchman_query();
++	if (is_work_tree_watched($o)) {
++		output_result($o->{clock}, @{$o->{files}});
++	}
++}
++
++sub output_result {
++	my ($clockid, @files) = @_;
++
++	# Uncomment for debugging watchman output
++	# open (my $fh, ">", ".git/watchman-output.out");
++	# binmode $fh, ":utf8";
++	# print $fh "$clockid\n at files\n";
++	# close $fh;
++
++	binmode STDOUT, ":utf8";
++	print $clockid;
++	print "\0";
++	local $, = "\0";
++	print @files;
++}
++
++sub watchman_clock {
++	my $response = qx/watchman clock "$git_work_tree"/;
++	die "Failed to get clock id on '$git_work_tree'.\n" .
++		"Falling back to scanning...\n" if $? != 0;
++
++	return $json_pkg->new->utf8->decode($response);
++}
++
++sub watchman_query {
++	my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
++	or die "open2() failed: $!\n" .
++	"Falling back to scanning...\n";
++
++	# In the query expression below we're asking for names of files that
++	# changed since $last_update_token but not from the .git folder.
++	#
++	# To accomplish this, we're using the "since" generator to use the
++	# recency index to select candidate nodes and "fields" to limit the
++	# output to file names only. Then we're using the "expression" term to
++	# further constrain the results.
++	if (substr($last_update_token, 0, 1) eq "c") {
++		$last_update_token = "\"$last_update_token\"";
++	}
++	my $query = <<"	END";
++		["query", "$git_work_tree", {
++			"since": $last_update_token,
++			"fields": ["name"],
++			"expression": ["not", ["dirname", ".git"]]
++		}]
++	END
++
++	# Uncomment for debugging the watchman query
++	# open (my $fh, ">", ".git/watchman-query.json");
++	# print $fh $query;
++	# close $fh;
++
++	print CHLD_IN $query;
++	close CHLD_IN;
++	my $response = do {local $/; <CHLD_OUT>};
++
++	# Uncomment for debugging the watch response
++	# open ($fh, ">", ".git/watchman-response.json");
++	# print $fh $response;
++	# close $fh;
++
++	die "Watchman: command returned no output.\n" .
++	"Falling back to scanning...\n" if $response eq "";
++	die "Watchman: command returned invalid output: $response\n" .
++	"Falling back to scanning...\n" unless $response =~ /^\{/;
++
++	return $json_pkg->new->utf8->decode($response);
++}
++
++sub is_work_tree_watched {
++	my ($output) = @_;
++	my $error = $output->{error};
++	if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
++		$retry--;
++		my $response = qx/watchman watch "$git_work_tree"/;
++		die "Failed to make watchman watch '$git_work_tree'.\n" .
++		    "Falling back to scanning...\n" if $? != 0;
++		$output = $json_pkg->new->utf8->decode($response);
++		$error = $output->{error};
++		die "Watchman: $error.\n" .
++		"Falling back to scanning...\n" if $error;
++
++		# Uncomment for debugging watchman output
++		# open (my $fh, ">", ".git/watchman-output.out");
++		# close $fh;
++
++		# Watchman will always return all files on the first query so
++		# return the fast "everything is dirty" flag to git and do the
++		# Watchman query just to get it over with now so we won't pay
++		# the cost in git to look up each individual file.
++		my $o = watchman_clock();
++		$error = $output->{error};
++
++		die "Watchman: $error.\n" .
++		"Falling back to scanning...\n" if $error;
++
++		output_result($o->{clock}, ("/"));
++		$last_update_token = $o->{clock};
++
++		eval { launch_watchman() };
++		return 0;
++	}
++
++	die "Watchman: $error.\n" .
++	"Falling back to scanning...\n" if $error;
++
++	return 1;
++}
++
++sub get_working_dir {
++	my $working_dir;
++	if ($^O =~ 'msys' || $^O =~ 'cygwin') {
++		$working_dir = Win32::GetCwd();
++		$working_dir =~ tr/\\/\//;
++	} else {
++		require Cwd;
++		$working_dir = Cwd::cwd();
++	}
++
++	return $working_dir;
++}
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/post-update.sample" /tmp/src/signon-ui/.git/hooks/post-update.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/post-update.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/post-update.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,8 @@
++#!/bin/sh
++#
++# An example hook script to prepare a packed repository for use over
++# dumb transports.
++#
++# To enable this hook, rename this file to "post-update".
++
++exec git update-server-info
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-applypatch.sample" /tmp/src/signon-ui/.git/hooks/pre-applypatch.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-applypatch.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/pre-applypatch.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,14 @@
++#!/bin/sh
++#
++# An example hook script to verify what is about to be committed
++# by applypatch from an e-mail message.
++#
++# The hook should exit with non-zero status after issuing an
++# appropriate message if it wants to stop the commit.
++#
++# To enable this hook, rename this file to "pre-applypatch".
++
++. git-sh-setup
++precommit="$(git rev-parse --git-path hooks/pre-commit)"
++test -x "$precommit" && exec "$precommit" ${1+"$@"}
++:
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-commit.sample" /tmp/src/signon-ui/.git/hooks/pre-commit.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-commit.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/pre-commit.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,49 @@
++#!/bin/sh
++#
++# An example hook script to verify what is about to be committed.
++# Called by "git commit" with no arguments.  The hook should
++# exit with non-zero status after issuing an appropriate message if
++# it wants to stop the commit.
++#
++# To enable this hook, rename this file to "pre-commit".
++
++if git rev-parse --verify HEAD >/dev/null 2>&1
++then
++	against=HEAD
++else
++	# Initial commit: diff against an empty tree object
++	against=$(git hash-object -t tree /dev/null)
++fi
++
++# If you want to allow non-ASCII filenames set this variable to true.
++allownonascii=$(git config --type=bool hooks.allownonascii)
++
++# Redirect output to stderr.
++exec 1>&2
++
++# Cross platform projects tend to avoid non-ASCII filenames; prevent
++# them from being added to the repository. We exploit the fact that the
++# printable range starts at the space character and ends with tilde.
++if [ "$allownonascii" != "true" ] &&
++	# Note that the use of brackets around a tr range is ok here, (it's
++	# even required, for portability to Solaris 10's /usr/bin/tr), since
++	# the square bracket bytes happen to fall in the designated range.
++	test $(git diff --cached --name-only --diff-filter=A -z $against |
++	  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
++then
++	cat <<\EOF
++Error: Attempt to add a non-ASCII file name.
++
++This can cause problems if you want to work with people on other platforms.
++
++To be portable it is advisable to rename the file.
++
++If you know what you are doing you can disable this check using:
++
++  git config hooks.allownonascii true
++EOF
++	exit 1
++fi
++
++# If there are whitespace errors, print the offending file names and fail.
++exec git diff-index --check --cached $against --
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-merge-commit.sample" /tmp/src/signon-ui/.git/hooks/pre-merge-commit.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-merge-commit.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/pre-merge-commit.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,13 @@
++#!/bin/sh
++#
++# An example hook script to verify what is about to be committed.
++# Called by "git merge" with no arguments.  The hook should
++# exit with non-zero status after issuing an appropriate message to
++# stderr if it wants to stop the merge commit.
++#
++# To enable this hook, rename this file to "pre-merge-commit".
++
++. git-sh-setup
++test -x "$GIT_DIR/hooks/pre-commit" &&
++        exec "$GIT_DIR/hooks/pre-commit"
++:
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-push.sample" /tmp/src/signon-ui/.git/hooks/pre-push.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-push.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/pre-push.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,53 @@
++#!/bin/sh
++
++# An example hook script to verify what is about to be pushed.  Called by "git
++# push" after it has checked the remote status, but before anything has been
++# pushed.  If this script exits with a non-zero status nothing will be pushed.
++#
++# This hook is called with the following parameters:
++#
++# $1 -- Name of the remote to which the push is being done
++# $2 -- URL to which the push is being done
++#
++# If pushing without using a named remote those arguments will be equal.
++#
++# Information about the commits which are being pushed is supplied as lines to
++# the standard input in the form:
++#
++#   <local ref> <local oid> <remote ref> <remote oid>
++#
++# This sample shows how to prevent push of commits where the log message starts
++# with "WIP" (work in progress).
++
++remote="$1"
++url="$2"
++
++zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
++
++while read local_ref local_oid remote_ref remote_oid
++do
++	if test "$local_oid" = "$zero"
++	then
++		# Handle delete
++		:
++	else
++		if test "$remote_oid" = "$zero"
++		then
++			# New branch, examine all commits
++			range="$local_oid"
++		else
++			# Update to existing branch, examine new commits
++			range="$remote_oid..$local_oid"
++		fi
++
++		# Check for WIP commit
++		commit=$(git rev-list -n 1 --grep '^WIP' "$range")
++		if test -n "$commit"
++		then
++			echo >&2 "Found WIP commit in $local_ref, not pushing"
++			exit 1
++		fi
++	fi
++done
++
++exit 0
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-rebase.sample" /tmp/src/signon-ui/.git/hooks/pre-rebase.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-rebase.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/pre-rebase.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,169 @@
++#!/bin/sh
++#
++# Copyright (c) 2006, 2008 Junio C Hamano
++#
++# The "pre-rebase" hook is run just before "git rebase" starts doing
++# its job, and can prevent the command from running by exiting with
++# non-zero status.
++#
++# The hook is called with the following parameters:
++#
++# $1 -- the upstream the series was forked from.
++# $2 -- the branch being rebased (or empty when rebasing the current branch).
++#
++# This sample shows how to prevent topic branches that are already
++# merged to 'next' branch from getting rebased, because allowing it
++# would result in rebasing already published history.
++
++publish=next
++basebranch="$1"
++if test "$#" = 2
++then
++	topic="refs/heads/$2"
++else
++	topic=`git symbolic-ref HEAD` ||
++	exit 0 ;# we do not interrupt rebasing detached HEAD
++fi
++
++case "$topic" in
++refs/heads/??/*)
++	;;
++*)
++	exit 0 ;# we do not interrupt others.
++	;;
++esac
++
++# Now we are dealing with a topic branch being rebased
++# on top of master.  Is it OK to rebase it?
++
++# Does the topic really exist?
++git show-ref -q "$topic" || {
++	echo >&2 "No such branch $topic"
++	exit 1
++}
++
++# Is topic fully merged to master?
++not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
++if test -z "$not_in_master"
++then
++	echo >&2 "$topic is fully merged to master; better remove it."
++	exit 1 ;# we could allow it, but there is no point.
++fi
++
++# Is topic ever merged to next?  If so you should not be rebasing it.
++only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
++only_next_2=`git rev-list ^master           ${publish} | sort`
++if test "$only_next_1" = "$only_next_2"
++then
++	not_in_topic=`git rev-list "^$topic" master`
++	if test -z "$not_in_topic"
++	then
++		echo >&2 "$topic is already up to date with master"
++		exit 1 ;# we could allow it, but there is no point.
++	else
++		exit 0
++	fi
++else
++	not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
++	/usr/bin/perl -e '
++		my $topic = $ARGV[0];
++		my $msg = "* $topic has commits already merged to public branch:\n";
++		my (%not_in_next) = map {
++			/^([0-9a-f]+) /;
++			($1 => 1);
++		} split(/\n/, $ARGV[1]);
++		for my $elem (map {
++				/^([0-9a-f]+) (.*)$/;
++				[$1 => $2];
++			} split(/\n/, $ARGV[2])) {
++			if (!exists $not_in_next{$elem->[0]}) {
++				if ($msg) {
++					print STDERR $msg;
++					undef $msg;
++				}
++				print STDERR " $elem->[1]\n";
++			}
++		}
++	' "$topic" "$not_in_next" "$not_in_master"
++	exit 1
++fi
++
++<<\DOC_END
++
++This sample hook safeguards topic branches that have been
++published from being rewound.
++
++The workflow assumed here is:
++
++ * Once a topic branch forks from "master", "master" is never
++   merged into it again (either directly or indirectly).
++
++ * Once a topic branch is fully cooked and merged into "master",
++   it is deleted.  If you need to build on top of it to correct
++   earlier mistakes, a new topic branch is created by forking at
++   the tip of the "master".  This is not strictly necessary, but
++   it makes it easier to keep your history simple.
++
++ * Whenever you need to test or publish your changes to topic
++   branches, merge them into "next" branch.
++
++The script, being an example, hardcodes the publish branch name
++to be "next", but it is trivial to make it configurable via
++$GIT_DIR/config mechanism.
++
++With this workflow, you would want to know:
++
++(1) ... if a topic branch has ever been merged to "next".  Young
++    topic branches can have stupid mistakes you would rather
++    clean up before publishing, and things that have not been
++    merged into other branches can be easily rebased without
++    affecting other people.  But once it is published, you would
++    not want to rewind it.
++
++(2) ... if a topic branch has been fully merged to "master".
++    Then you can delete it.  More importantly, you should not
++    build on top of it -- other people may already want to
++    change things related to the topic as patches against your
++    "master", so if you need further changes, it is better to
++    fork the topic (perhaps with the same name) afresh from the
++    tip of "master".
++
++Let's look at this example:
++
++		   o---o---o---o---o---o---o---o---o---o "next"
++		  /       /           /           /
++		 /   a---a---b A     /           /
++		/   /               /           /
++	       /   /   c---c---c---c B         /
++	      /   /   /             \         /
++	     /   /   /   b---b C     \       /
++	    /   /   /   /             \     /
++    ---o---o---o---o---o---o---o---o---o---o---o "master"
++
++
++A, B and C are topic branches.
++
++ * A has one fix since it was merged up to "next".
++
++ * B has finished.  It has been fully merged up to "master" and "next",
++   and is ready to be deleted.
++
++ * C has not merged to "next" at all.
++
++We would want to allow C to be rebased, refuse A, and encourage
++B to be deleted.
++
++To compute (1):
++
++	git rev-list ^master ^topic next
++	git rev-list ^master        next
++
++	if these match, topic has not merged in next at all.
++
++To compute (2):
++
++	git rev-list master..topic
++
++	if this is empty, it is fully merged to "master".
++
++DOC_END
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-receive.sample" /tmp/src/signon-ui/.git/hooks/pre-receive.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/pre-receive.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/pre-receive.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,24 @@
++#!/bin/sh
++#
++# An example hook script to make use of push options.
++# The example simply echoes all push options that start with 'echoback='
++# and rejects all pushes when the "reject" push option is used.
++#
++# To enable this hook, rename this file to "pre-receive".
++
++if test -n "$GIT_PUSH_OPTION_COUNT"
++then
++	i=0
++	while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
++	do
++		eval "value=\$GIT_PUSH_OPTION_$i"
++		case "$value" in
++		echoback=*)
++			echo "echo from the pre-receive-hook: ${value#*=}" >&2
++			;;
++		reject)
++			exit 1
++		esac
++		i=$((i + 1))
++	done
++fi
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/prepare-commit-msg.sample" /tmp/src/signon-ui/.git/hooks/prepare-commit-msg.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/prepare-commit-msg.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/prepare-commit-msg.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,42 @@
++#!/bin/sh
++#
++# An example hook script to prepare the commit log message.
++# Called by "git commit" with the name of the file that has the
++# commit message, followed by the description of the commit
++# message's source.  The hook's purpose is to edit the commit
++# message file.  If the hook fails with a non-zero status,
++# the commit is aborted.
++#
++# To enable this hook, rename this file to "prepare-commit-msg".
++
++# This hook includes three examples. The first one removes the
++# "# Please enter the commit message..." help message.
++#
++# The second includes the output of "git diff --name-status -r"
++# into the message, just before the "git status" output.  It is
++# commented because it doesn't cope with --amend or with squashed
++# commits.
++#
++# The third example adds a Signed-off-by line to the message, that can
++# still be edited.  This is rarely a good idea.
++
++COMMIT_MSG_FILE=$1
++COMMIT_SOURCE=$2
++SHA1=$3
++
++/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
++
++# case "$COMMIT_SOURCE,$SHA1" in
++#  ,|template,)
++#    /usr/bin/perl -i.bak -pe '
++#       print "\n" . `git diff --cached --name-status -r`
++# 	 if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
++#  *) ;;
++# esac
++
++# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
++# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
++# if test -z "$COMMIT_SOURCE"
++# then
++#   /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
++# fi
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/push-to-checkout.sample" /tmp/src/signon-ui/.git/hooks/push-to-checkout.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/push-to-checkout.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/push-to-checkout.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,78 @@
++#!/bin/sh
++
++# An example hook script to update a checked-out tree on a git push.
++#
++# This hook is invoked by git-receive-pack(1) when it reacts to git
++# push and updates reference(s) in its repository, and when the push
++# tries to update the branch that is currently checked out and the
++# receive.denyCurrentBranch configuration variable is set to
++# updateInstead.
++#
++# By default, such a push is refused if the working tree and the index
++# of the remote repository has any difference from the currently
++# checked out commit; when both the working tree and the index match
++# the current commit, they are updated to match the newly pushed tip
++# of the branch. This hook is to be used to override the default
++# behaviour; however the code below reimplements the default behaviour
++# as a starting point for convenient modification.
++#
++# The hook receives the commit with which the tip of the current
++# branch is going to be updated:
++commit=$1
++
++# It can exit with a non-zero status to refuse the push (when it does
++# so, it must not modify the index or the working tree).
++die () {
++	echo >&2 "$*"
++	exit 1
++}
++
++# Or it can make any necessary changes to the working tree and to the
++# index to bring them to the desired state when the tip of the current
++# branch is updated to the new commit, and exit with a zero status.
++#
++# For example, the hook can simply run git read-tree -u -m HEAD "$1"
++# in order to emulate git fetch that is run in the reverse direction
++# with git push, as the two-tree form of git read-tree -u -m is
++# essentially the same as git switch or git checkout that switches
++# branches while keeping the local changes in the working tree that do
++# not interfere with the difference between the branches.
++
++# The below is a more-or-less exact translation to shell of the C code
++# for the default behaviour for git's push-to-checkout hook defined in
++# the push_to_deploy() function in builtin/receive-pack.c.
++#
++# Note that the hook will be executed from the repository directory,
++# not from the working tree, so if you want to perform operations on
++# the working tree, you will have to adapt your code accordingly, e.g.
++# by adding "cd .." or using relative paths.
++
++if ! git update-index -q --ignore-submodules --refresh
++then
++	die "Up-to-date check failed"
++fi
++
++if ! git diff-files --quiet --ignore-submodules --
++then
++	die "Working directory has unstaged changes"
++fi
++
++# This is a rough translation of:
++#
++#   head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
++if git cat-file -e HEAD 2>/dev/null
++then
++	head=HEAD
++else
++	head=$(git hash-object -t tree --stdin </dev/null)
++fi
++
++if ! git diff-index --quiet --cached --ignore-submodules $head --
++then
++	die "Working directory has staged changes"
++fi
++
++if ! git read-tree -u -m "$commit"
++then
++	die "Could not update working tree to new HEAD"
++fi
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/update.sample" /tmp/src/signon-ui/.git/hooks/update.sample
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/hooks/update.sample"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/hooks/update.sample	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,128 @@
++#!/bin/sh
++#
++# An example hook script to block unannotated tags from entering.
++# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
++#
++# To enable this hook, rename this file to "update".
++#
++# Config
++# ------
++# hooks.allowunannotated
++#   This boolean sets whether unannotated tags will be allowed into the
++#   repository.  By default they won't be.
++# hooks.allowdeletetag
++#   This boolean sets whether deleting tags will be allowed in the
++#   repository.  By default they won't be.
++# hooks.allowmodifytag
++#   This boolean sets whether a tag may be modified after creation. By default
++#   it won't be.
++# hooks.allowdeletebranch
++#   This boolean sets whether deleting branches will be allowed in the
++#   repository.  By default they won't be.
++# hooks.denycreatebranch
++#   This boolean sets whether remotely creating branches will be denied
++#   in the repository.  By default this is allowed.
++#
++
++# --- Command line
++refname="$1"
++oldrev="$2"
++newrev="$3"
++
++# --- Safety check
++if [ -z "$GIT_DIR" ]; then
++	echo "Don't run this script from the command line." >&2
++	echo " (if you want, you could supply GIT_DIR then run" >&2
++	echo "  $0 <ref> <oldrev> <newrev>)" >&2
++	exit 1
++fi
++
++if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
++	echo "usage: $0 <ref> <oldrev> <newrev>" >&2
++	exit 1
++fi
++
++# --- Config
++allowunannotated=$(git config --type=bool hooks.allowunannotated)
++allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
++denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
++allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
++allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
++
++# check for no description
++projectdesc=$(sed -e '1q' "$GIT_DIR/description")
++case "$projectdesc" in
++"Unnamed repository"* | "")
++	echo "*** Project description file hasn't been set" >&2
++	exit 1
++	;;
++esac
++
++# --- Check types
++# if $newrev is 0000...0000, it's a commit to delete a ref.
++zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
++if [ "$newrev" = "$zero" ]; then
++	newrev_type=delete
++else
++	newrev_type=$(git cat-file -t $newrev)
++fi
++
++case "$refname","$newrev_type" in
++	refs/tags/*,commit)
++		# un-annotated tag
++		short_refname=${refname##refs/tags/}
++		if [ "$allowunannotated" != "true" ]; then
++			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
++			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
++			exit 1
++		fi
++		;;
++	refs/tags/*,delete)
++		# delete tag
++		if [ "$allowdeletetag" != "true" ]; then
++			echo "*** Deleting a tag is not allowed in this repository" >&2
++			exit 1
++		fi
++		;;
++	refs/tags/*,tag)
++		# annotated tag
++		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
++		then
++			echo "*** Tag '$refname' already exists." >&2
++			echo "*** Modifying a tag is not allowed in this repository." >&2
++			exit 1
++		fi
++		;;
++	refs/heads/*,commit)
++		# branch
++		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
++			echo "*** Creating a branch is not allowed in this repository" >&2
++			exit 1
++		fi
++		;;
++	refs/heads/*,delete)
++		# delete branch
++		if [ "$allowdeletebranch" != "true" ]; then
++			echo "*** Deleting a branch is not allowed in this repository" >&2
++			exit 1
++		fi
++		;;
++	refs/remotes/*,commit)
++		# tracking branch
++		;;
++	refs/remotes/*,delete)
++		# delete tracking branch
++		if [ "$allowdeletebranch" != "true" ]; then
++			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
++			exit 1
++		fi
++		;;
++	*)
++		# Anything else (is there anything else?)
++		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
++		exit 1
++		;;
++esac
++
++# --- Finished
++exit 0
+Binary files /tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/index and /tmp/src/signon-ui/.git/index differ
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/info/exclude" /tmp/src/signon-ui/.git/info/exclude
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/info/exclude"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/info/exclude	2023-10-04 11:35:18.833512597 +1000
+@@ -0,0 +1,6 @@
++# git ls-files --others --exclude-from=.git/info/exclude
++# Lines that start with '#' are comments.
++# For a project mostly in C, the following would be a good set of
++# exclude patterns (uncomment them if you want to use them):
++# *.[oa]
++# *~
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/logs/HEAD" /tmp/src/signon-ui/.git/logs/HEAD
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/logs/HEAD"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/logs/HEAD	2023-10-04 11:35:19.901523255 +1000
+@@ -0,0 +1 @@
++0000000000000000000000000000000000000000 4368bb77d9d1abc2978af514225ba4a42c29a646 Carlos De Maine <carlosdemaine at gmail.com> 1696383319 +1000	clone: from https://gitlab.com/accounts-sso/signon-ui.git
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/logs/refs/heads/master" /tmp/src/signon-ui/.git/logs/refs/heads/master
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/logs/refs/heads/master"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/logs/refs/heads/master	2023-10-04 11:35:19.901523255 +1000
+@@ -0,0 +1 @@
++0000000000000000000000000000000000000000 4368bb77d9d1abc2978af514225ba4a42c29a646 Carlos De Maine <carlosdemaine at gmail.com> 1696383319 +1000	clone: from https://gitlab.com/accounts-sso/signon-ui.git
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/logs/refs/remotes/origin/HEAD" /tmp/src/signon-ui/.git/logs/refs/remotes/origin/HEAD
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/logs/refs/remotes/origin/HEAD"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/logs/refs/remotes/origin/HEAD	2023-10-04 11:35:19.901523255 +1000
+@@ -0,0 +1 @@
++0000000000000000000000000000000000000000 4368bb77d9d1abc2978af514225ba4a42c29a646 Carlos De Maine <carlosdemaine at gmail.com> 1696383319 +1000	clone: from https://gitlab.com/accounts-sso/signon-ui.git
+Binary files /tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/objects/pack/pack-2230065f0d095e2ba5ceecea1865e2f05a5c5a6d.idx and /tmp/src/signon-ui/.git/objects/pack/pack-2230065f0d095e2ba5ceecea1865e2f05a5c5a6d.idx differ
+Binary files /tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/objects/pack/pack-2230065f0d095e2ba5ceecea1865e2f05a5c5a6d.pack and /tmp/src/signon-ui/.git/objects/pack/pack-2230065f0d095e2ba5ceecea1865e2f05a5c5a6d.pack differ
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/packed-refs" /tmp/src/signon-ui/.git/packed-refs
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/packed-refs"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/packed-refs	2023-10-04 11:35:19.901523255 +1000
+@@ -0,0 +1,38 @@
++# pack-refs with: peeled fully-peeled sorted
++0d3014e69e5b64f08241bc1053894e8d8cac300b refs/remotes/origin/launchpad-trunk
++4368bb77d9d1abc2978af514225ba4a42c29a646 refs/remotes/origin/master
++e4fe1ba67cb2441b6f170de3463a2c377adaefbb refs/tags/0.1
++bac2bd71a8ee180a2bf84fe1015fb46ec32dbd5a refs/tags/0.10
++bac2bd71a8ee180a2bf84fe1015fb46ec32dbd5a refs/tags/0.10+bzr63
++0a905c64258ebe00e69d9a87f0f91baef6bd9298 refs/tags/0.11
++0a905c64258ebe00e69d9a87f0f91baef6bd9298 refs/tags/0.11+bzr66
++a374ba8b6a09a721d9dc3ea7a6fed87dd45fadee refs/tags/0.12
++a374ba8b6a09a721d9dc3ea7a6fed87dd45fadee refs/tags/0.12+bzr70
++1e3f846a89f5adbbdeb7be22573345eb5d5f798a refs/tags/0.14
++fbe810a5a55c949f6f3e81deb859e2ecd8acc863 refs/tags/0.16
++b4b6622fee0973a45cfcaf3103b322c0e46d6b76 refs/tags/0.16+14.04.20140304-0ubuntu1
++cd423fe33d5c7cee6b5e65df72f12cd7917a4c03 refs/tags/0.16+14.04.20140304.is.0.15+14.04.20140313-0ubuntu1
++bc09f1079d07b3e1195b1d820829bfc635b04842 refs/tags/0.16+14.04.20140304.is.0.15+14.04.20140313-0ubuntu2
++c94f7e955461aba183b16e1b57461ee7c195fe39 refs/tags/0.16+14.10.20140530-0ubuntu1
++b0780febdcb9c2a6e8e6211c504bf7835e5ee682 refs/tags/0.17+14.10.20140612-0ubuntu1
++48ef13a9de8910803c309da317c6bb8530268cdc refs/tags/0.17+14.10.20140814-0ubuntu1
++4f73eec491f6a3bc527647f9ea215dd4509dc843 refs/tags/0.17+14.10.20140916-0ubuntu1
++24892bdcca2dd253cd352b8e89892a41158a3318 refs/tags/0.17+15.04.20150410-0ubuntu1
++c08dd916857c4cde270da7ea63477eee865c1668 refs/tags/0.17+15.10.20150810-0ubuntu1
++20d2030151922a06a9a7365f61691ccd0a82ab8d refs/tags/0.2
++828d26008b9bfdb00644556b04dd866fc01318ce refs/tags/0.2-bzr25
++b01bf1355b647f2af231045e62093845cc9626d5 refs/tags/0.2-bzr33
++a91e7e2b5ca9abfaa877ab7b0dbbd052cf15afe2 refs/tags/0.3
++a91e7e2b5ca9abfaa877ab7b0dbbd052cf15afe2 refs/tags/0.3+bzr40
++3f2013cb09529150bcd6bee8e4edb795c55de18e refs/tags/0.3+bzr43
++d15f10e621044597e352e57dfca5cd56e5415014 refs/tags/0.4
++d15f10e621044597e352e57dfca5cd56e5415014 refs/tags/0.4+bzr46
++239c6b90499bcb27f6d699ef4a4c0249835e01a1 refs/tags/0.5
++d49da9fdfb025c06a4a20e2401ea601363ff3dcd refs/tags/0.6
++d49da9fdfb025c06a4a20e2401ea601363ff3dcd refs/tags/0.6+bzr52
++12d2c4434e8d70658bb6511b7084b4d8ebf74056 refs/tags/0.7
++12d2c4434e8d70658bb6511b7084b4d8ebf74056 refs/tags/0.7+bzr54
++10c63136cd6f025eda4cccaa120e01d2508ebce9 refs/tags/0.8
++10c63136cd6f025eda4cccaa120e01d2508ebce9 refs/tags/0.8+bzr56
++3fd7b67c2581c4d76cfa6e23995b1ed493620d82 refs/tags/0.9
++3fd7b67c2581c4d76cfa6e23995b1ed493620d82 refs/tags/0.9+bzr59
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/refs/heads/master" /tmp/src/signon-ui/.git/refs/heads/master
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/refs/heads/master"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/refs/heads/master	2023-10-04 11:35:19.901523255 +1000
+@@ -0,0 +1 @@
++4368bb77d9d1abc2978af514225ba4a42c29a646
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/refs/remotes/origin/HEAD" /tmp/src/signon-ui/.git/refs/remotes/origin/HEAD
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.git/refs/remotes/origin/HEAD"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.git/refs/remotes/origin/HEAD	2023-10-04 11:35:19.901523255 +1000
+@@ -0,0 +1 @@
++ref: refs/remotes/origin/master
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.gitignore" /tmp/src/signon-ui/.gitignore
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/.gitignore"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/.gitignore	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,7 @@
++*.moc
++*.o
++*.swp
++.*
++Makefile*
++moc_*
++qrc_*
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/.gitignore" /tmp/src/signon-ui/src/.gitignore
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/.gitignore"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/.gitignore	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,6 @@
++com.canonical.indicators.webcredentials.service
++com.nokia.singlesignonui.service
++signon-ui
++signon-ui.desktop
++webcredentials_adaptor.cpp
++webcredentials_adaptor.h
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/browser-request.cpp" /tmp/src/signon-ui/src/browser-request.cpp
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/browser-request.cpp"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/browser-request.cpp	2023-10-04 11:35:19.905523296 +1000
+@@ -1,7 +1,8 @@
+ /*
+  * This file is part of signon-ui
+  *
+- * Copyright (C) 2011 Canonical Ltd.
++ * Copyright (C) 2013 Canonical Ltd.
++ * Copyright (C) 2017 Alberto Mardegan
+  *
+  * Contact: Alberto Mardegan <alberto.mardegan at canonical.com>
+  *
+@@ -20,302 +21,73 @@
+
+ #include "browser-request.h"
+
+-#include "animation-label.h"
+-#include "cookie-jar-manager.h"
+ #include "debug.h"
+-#include "dialog.h"
+-#include "http-warning.h"
++#include "qquick-dialog.h"
++#include "errors.h"
+ #include "i18n.h"
+
+-#include <QDBusArgument>
+-#include <QDesktopServices>
+-#include <QIcon>
+-#include <QLabel>
+-#include <QNetworkCookie>
+-#include <QNetworkReply>
+-#include <QNetworkRequest>
+-#include <QPixmap>
+-#include <QPointer>
+-#include <QProgressBar>
+-#include <QPushButton>
+-#include <QRegExp>
+-#include <QSettings>
+-#include <QSslError>
+-#include <QStackedLayout>
+-#include <QStatusBar>
++#include <QDir>
++#include <QQmlContext>
++#include <QStandardPaths>
+ #include <QTimer>
+-#include <QVBoxLayout>
+-#include <QWebElement>
+-#include <QWebFrame>
+-#include <QWebView>
+ #include <SignOn/uisessiondata_priv.h>
+
+ using namespace SignOnUi;
++using namespace SignOnUi::QQuick;
+
+ namespace SignOnUi {
+
+-static const QString keyPreferredWidth = QString("PreferredWidth");
+-static const QString keyHorizontalScrollBar = QString("HorizontalScrollBar");
+-static const QString keyVerticalScrollBar = QString("VerticalScrollBar");
+-static const QString keyTextSizeMultiplier = QString("TextSizeMultiplier");
+-static const QString keyUserAgent = QString("UserAgent");
+-static const QString keyViewportWidth = QString("ViewportWidth");
+-static const QString keyViewportHeight = QString("ViewportHeight");
+-static const QString keyZoomFactor = QString("ZoomFactor");
+-static const QString keyUsernameField = QString("UsernameField");
+-static const QString keyPasswordField = QString("PasswordField");
+-static const QString keyLoginButton = QString("LoginButton");
+-static const QString keyInternalLinksPattern = QString("InternalLinksPattern");
+-static const QString keyExternalLinksPattern = QString("ExternalLinksPattern");
+-static const QString keyAllowedUrls = QString("AllowedUrls");
+-static const QString valueAlwaysOn = QString("alwaysOn");
+-static const QString valueAlwaysOff = QString("alwaysOff");
+-
+-/* Additional session-data keys we support. */
+-static const QString keyCookies = QString("Cookies");
+-static const QString keyAllowedSchemes = QString("AllowedSchemes");
+-static const QString keyIgnoreSslErrors = QString("IgnoreSslErrors");
+-
+-static bool pathsAreEqual(const QString &p1, const QString &p2)
+-{
+-    static QRegExp regExp("/*$");
+-    QString p1copy(p1);
+-    QString p2copy(p2);
+-    return p1copy.remove(regExp) == p2copy.remove(regExp);
+-}
+-
+-class WebPage: public QWebPage
+-{
+-    Q_OBJECT
+-
+-public:
+-    WebPage(QObject *parent = 0): QWebPage(parent) {}
+-    ~WebPage() {}
+-
+-    void setUserAgent(const QString &userAgent) { m_userAgent = userAgent; }
+-
+-    void setExternalLinksPattern(const QString &pattern) {
+-        m_externalLinksPattern =
+-            QRegExp(pattern, Qt::CaseInsensitive, QRegExp::RegExp2);
+-    }
+-
+-    void setInternalLinksPattern(const QString &pattern) {
+-        m_internalLinksPattern =
+-            QRegExp(pattern, Qt::CaseInsensitive, QRegExp::RegExp2);
+-    }
+-
+-    void setAllowedSchemes(const QStringList &schemes) {
+-        m_allowedSchemes = schemes;
+-    }
+-
+-    void setAllowedUrls(const QString &pattern) {
+-        m_allowedUrls =
+-            QRegExp(pattern, Qt::CaseInsensitive, QRegExp::RegExp2);
+-    }
+-
+-    void setFinalUrl(const QUrl &url) { m_finalUrl = url; }
+-
+-protected:
+-    // reimplemented virtual methods
+-    QString userAgentForUrl(const QUrl &url) const
+-    {
+-        return m_userAgent.isEmpty() ?
+-            QWebPage::userAgentForUrl(url) : m_userAgent;
+-    }
+-
+-    bool acceptNavigationRequest(QWebFrame *frame,
+-                                 const QNetworkRequest &request,
+-                                 NavigationType type)
+-    {
+-        Q_UNUSED(type);
+-
+-        QUrl url = request.url();
+-        TRACE() << url;
+-
+-        /* We generally don't need to load the final URL, so skip loading it.
+-         * If this behaviour is not desired for some requests, then just avoid
+-         * calling setFinalUrl() */
+-        if (url.host() == m_finalUrl.host() &&
+-            pathsAreEqual(url.path(), m_finalUrl.path())) {
+-            Q_EMIT finalUrlReached(url);
+-            return false;
+-        }
+-
+-        /* open all new window requests (identified by "frame == 0") in the
+-         * external browser, as well as other links according to the
+-         * ExternalLinksPattern and InternalLinksPattern rules. */
+-        if (frame == 0 || urlIsBlocked(url)) {
+-            QDesktopServices::openUrl(url);
+-            return false;
+-        }
+-        /* Handle all other requests internally. */
+-        return true;
+-    }
+-
+-Q_SIGNALS:
+-    void finalUrlReached(const QUrl &url);
+-
+-private:
+-    bool urlIsBlocked(QUrl url) const;
+-
+-private:
+-    QString m_userAgent;
+-    QRegExp m_externalLinksPattern;
+-    QRegExp m_internalLinksPattern;
+-    QStringList m_allowedSchemes;
+-    QRegExp m_allowedUrls;
+-    QUrl m_finalUrl;
+-};
+-
+-bool WebPage::urlIsBlocked(QUrl url) const {
+-    if (url == QUrl("about:blank")) return false;
+-
+-    if (!m_allowedSchemes.contains(url.scheme())) {
+-        TRACE() << "Scheme not allowed:" << url.scheme();
+-        return true;
+-    }
+-
+-    if (!m_allowedUrls.isEmpty() &&
+-        !m_allowedUrls.exactMatch(url.toString())) {
+-        TRACE() << "URL not allowed:" << url;
+-        return true;
+-    }
+-
+-    QString urlText = url.toString(QUrl::RemoveScheme |
+-                                   QUrl::RemoveUserInfo |
+-                                   QUrl::RemoveFragment |
+-                                   QUrl::StripTrailingSlash);
+-    if (urlText.startsWith("//")) {
+-        urlText = urlText.mid(2);
+-    }
+-
+-    if (!m_internalLinksPattern.isEmpty()) {
+-        return !m_internalLinksPattern.exactMatch(urlText);
+-    }
+-
+-    if (!m_externalLinksPattern.isEmpty()) {
+-        return m_externalLinksPattern.exactMatch(urlText);
+-    }
+-
+-    return false;
+-}
+-
+-class WebView: public QWebView
+-{
+-    Q_OBJECT
+-
+-public:
+-    WebView(QWidget *parent = 0):
+-        QWebView(parent)
+-    {
+-        setSizePolicy(QSizePolicy::MinimumExpanding,
+-                      QSizePolicy::MinimumExpanding);
+-        setAttribute(Qt::WA_OpaquePaintEvent, true);
+-    }
+-    ~WebView() {};
+-
+-    void setPreferredSize(const QSize &size) {
+-        m_preferredSize = size;
+-        updateGeometry();
+-    }
+-
+-protected:
+-    QSize sizeHint() const {
+-        if (m_preferredSize.isValid()) {
+-            return m_preferredSize;
+-        } else {
+-            return QSize(400, 300);
+-        }
+-    }
+-
+-    void paintEvent(QPaintEvent *event) {
+-        QPainter painter(this);
+-        painter.fillRect(rect(), palette().window());
+-        QWebView::paintEvent(event);
+-    }
+-
+-private:
+-    QSize m_preferredSize;
+-};
+-
+ class BrowserRequestPrivate: public QObject
+ {
+     Q_OBJECT
+     Q_DECLARE_PUBLIC(BrowserRequest)
++    Q_PROPERTY(QUrl pageComponentUrl READ pageComponentUrl CONSTANT)
++    Q_PROPERTY(QUrl currentUrl READ currentUrl WRITE setCurrentUrl)
++    Q_PROPERTY(QUrl startUrl READ startUrl CONSTANT)
++    Q_PROPERTY(QUrl finalUrl READ finalUrl CONSTANT)
+
+ public:
+     BrowserRequestPrivate(BrowserRequest *request);
+     ~BrowserRequestPrivate();
+
+-    QWidget *buildWebViewPage(const QVariantMap &params);
+-    QWidget *buildSuccessPage();
+-    QWidget *buildLoadFailurePage();
+-    void buildDialog(const QVariantMap &params);
+     void start();
+
+-private Q_SLOTS:
+-    void onSslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
+-    void onUrlChanged(const QUrl &url);
+-    void onLoadProgress();
++    void setCurrentUrl(const QUrl &url);
++    QUrl pageComponentUrl() const;
++    QUrl currentUrl() const { return m_currentUrl; }
++    QUrl startUrl() const { return m_startUrl; }
++    QUrl finalUrl() const { return m_finalUrl; }
++    QUrl responseUrl() const { return m_responseUrl; }
++
++public Q_SLOTS:
++    void cancel();
++    void onLoadStarted();
+     void onLoadFinished(bool ok);
++
++private Q_SLOTS:
+     void onFailTimer();
+     void onFinished();
+-    void startProgress();
+-    void stopProgress();
+-    void onContentsChanged();
+
+ private:
+-    void showDialog();
+-    void setupViewForUrl(const QUrl &url);
+-    void notifyAuthCompleted();
+-    void notifyLoadFailed();
+-    QWebElement initializeField(const QString &settingsKey,
+-                                const QString &paramKey = QString());
+-    void initializeFields();
+-    bool tryAutoLogin();
+-    void addBrowserCookies(CookieJar *cookieJar);
++    void buildDialog(const QVariantMap &params);
+
+ private:
+-    mutable BrowserRequest *q_ptr;
+-    /* The dialog can be deleted by the Request class, if it's set as children
+-     * of an embedded widget which is then deleted. Therefore, in order to
+-     * avoid a double deletion, guard the pointer with a QPointer. */
+-    QPointer<Dialog> m_dialog;
+-    QStackedLayout *m_dialogLayout;
+-    QWidget *m_webViewPage;
+-    QWidget *m_successPage;
+-    QWidget *m_loadFailurePage;
+-    QStackedLayout *m_webViewLayout;
+-    WebView *m_webView;
+-    AnimationLabel *m_animationLabel;
+-    HttpWarning *m_httpWarning;
+-    QUrl finalUrl;
+-    QUrl responseUrl;
+-    QString m_host;
+-    QSettings *m_settings;
+-    QWebElement m_usernameField;
+-    QWebElement m_passwordField;
+-    QWebElement m_loginButton;
+-    QString m_username;
+-    QString m_password;
+-    int m_loginCount;
+-    bool m_ignoreSslErrors;
++    Dialog *m_dialog;
++    QUrl m_currentUrl;
++    QUrl m_startUrl;
++    QUrl m_finalUrl;
++    QUrl m_responseUrl;
+     QTimer m_failTimer;
++    mutable BrowserRequest *q_ptr;
+ };
+
+ } // namespace
+
+-BrowserRequestPrivate::BrowserRequestPrivate(BrowserRequest *request):
++BrowserRequestPrivate::BrowserRequestPrivate(
++    BrowserRequest *request):
+     QObject(request),
+-    q_ptr(request),
+     m_dialog(0),
+-    m_webViewLayout(0),
+-    m_webView(0),
+-    m_animationLabel(0),
+-    m_httpWarning(0),
+-    m_settings(0),
+-    m_loginCount(0),
+-    m_ignoreSslErrors(false)
++    q_ptr(request)
+ {
+     m_failTimer.setSingleShot(true);
+     m_failTimer.setInterval(3000);
+@@ -328,45 +100,99 @@
+     delete m_dialog;
+ }
+
+-void BrowserRequestPrivate::onSslErrors(QNetworkReply *reply,
+-                                        const QList<QSslError> &errors)
++void BrowserRequestPrivate::start()
+ {
+-    TRACE() << errors;
+-    if (m_ignoreSslErrors) {
+-        reply->ignoreSslErrors();
++    Q_Q(BrowserRequest);
++
++    const QVariantMap &params = q->parameters();
++    TRACE() << params;
++
++    QString cachePath =
++        QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
++    QDir rootDir = cachePath + QString("/id-%1").arg(q->identity());
++    if (!rootDir.exists()) {
++        rootDir.mkpath(".");
+     }
++
++    m_finalUrl = params.value(SSOUI_KEY_FINALURL).toString();
++    m_startUrl = params.value(SSOUI_KEY_OPENURL).toString();
++    buildDialog(params);
++
++    QObject::connect(m_dialog, SIGNAL(finished(int)),
++                     this, SLOT(onFinished()));
++
++    QUrl webview("qrc:/MainWindow.qml");
++    QDir qmlDir("/usr/share/signon-ui/qml");
++    if (qmlDir.exists())
++    {
++        QFileInfo qmlFile(qmlDir.absolutePath() + "/MainWindow.qml");
++        if (qmlFile.exists())
++            webview.setUrl(qmlFile.absoluteFilePath());
++    }
++
++    m_dialog->rootContext()->setContextProperty("request", this);
++    m_dialog->rootContext()->setContextProperty("rootDir",
++                                                QUrl::fromLocalFile(rootDir.absolutePath()));
++    m_dialog->setSource(webview);
+ }
+
+-void BrowserRequestPrivate::onUrlChanged(const QUrl &url)
++QUrl BrowserRequestPrivate::pageComponentUrl() const
+ {
+-    Q_Q(BrowserRequest);
++    Q_Q(const BrowserRequest);
++    /* We define the X-PageComponent key to let the clients override the QML
++     * component to be used to build the authentication page.
++     * To prevent a malicious client to show it's own UI, we require that the
++     * file path begins with "/usr/share/signon-ui/" (where Ubuntu click
++     * packages cannot install files).
++     */
++    QUrl providedUrl = q->clientData().value("X-PageComponent").toString();
++    if (providedUrl.isValid() && providedUrl.isLocalFile() &&
++        providedUrl.path().startsWith("/usr/share/signon-ui/")) {
++        return providedUrl;
++    } else {
++        return QStringLiteral("DefaultPage.qml");
++    }
++}
+
++void BrowserRequestPrivate::setCurrentUrl(const QUrl &url)
++{
+     TRACE() << "Url changed:" << url;
+     m_failTimer.stop();
+
+-    if (url.host() == finalUrl.host() &&
+-        pathsAreEqual(url.path(), finalUrl.path())) {
+-        responseUrl = url;
+-        if (q->embeddedUi() || !m_dialog->isVisible()) {
++    if (url.host() == m_finalUrl.host() &&
++        url.path() == m_finalUrl.path()) {
++        m_responseUrl = url;
++        if (!m_dialog->isVisible()) {
+             /* Do not show the notification page. */
+             m_dialog->accept();
+         } else {
+             /* Replace the web page with an information screen */
+-            notifyAuthCompleted();
++            /* TODO */
++            m_dialog->accept();
+         }
+     }
++}
+
+-    setupViewForUrl(url);
+-    m_httpWarning->setVisible(url.scheme() == "http");
++void BrowserRequestPrivate::cancel()
++{
++    Q_Q(BrowserRequest);
++
++    TRACE() << "Client requested to cancel";
++    q->setCanceled();
++    if (m_dialog) {
++        m_dialog->close();
++    }
+ }
+
+-void BrowserRequestPrivate::onLoadProgress()
++void BrowserRequestPrivate::onLoadStarted()
+ {
+     m_failTimer.stop();
+ }
+
+ void BrowserRequestPrivate::onLoadFinished(bool ok)
+ {
++    Q_Q(BrowserRequest);
++
+     TRACE() << "Load finished" << ok;
+
+     if (!ok) {
+@@ -374,17 +200,9 @@
+         return;
+     }
+
+-    if (loggingLevel() > 2) {
+-        /* Dump the HTML */
+-        TRACE() << m_webView->page()->mainFrame()->toHtml();
+-    }
+-
+-    initializeFields();
+-
+     if (!m_dialog->isVisible()) {
+-        if (responseUrl.isEmpty()) {
+-            if (!tryAutoLogin())
+-                showDialog();
++        if (m_responseUrl.isEmpty()) {
++            q->setWindow(m_dialog);
+         } else {
+             onFinished();
+         }
+@@ -393,166 +211,30 @@
+
+ void BrowserRequestPrivate::onFailTimer()
+ {
+-    notifyLoadFailed();
+-}
+-
+-void BrowserRequestPrivate::addBrowserCookies(CookieJar *cookieJar)
+-{
+     Q_Q(BrowserRequest);
+
+-    const QVariantMap &clientData = q->clientData();
+-    if (!clientData.contains(keyCookies)) return;
+-
+-    RawCookies rawCookies;
+-    QDBusArgument arg = clientData[keyCookies].value<QDBusArgument>();
+-    if (arg.currentSignature() == "a{sv}") {
+-        /* The signature of the argument should be "a{ss}", not "a{sv}";
+-         * however, ruby-dbus is rather primitive and there seems to be no way
+-         * to speficy a different signature than "a{sv}" when marshalling Hash
+-         * into a variant.
+-         * Therefore, just for our functional tests, also support "a{sv}".
+-         */
+-        QVariantMap cookieMap = qdbus_cast<QVariantMap>(arg);
+-        QVariantMap::const_iterator i;
+-        for (i = cookieMap.constBegin(); i != cookieMap.constEnd(); i++) {
+-            rawCookies.insert(i.key(), i.value().toString());
+-        }
+-    } else {
+-        rawCookies = qdbus_cast<RawCookies>(arg);
+-    }
+-
+-    QList<QNetworkCookie> cookies;
+-    RawCookies::const_iterator i;
+-    for (i = rawCookies.constBegin(); i != rawCookies.constEnd(); i++) {
+-        cookies.append(QNetworkCookie::parseCookies(i.value().toUtf8()));
++    TRACE() << "Page loading failed";
++    if (m_dialog) {
++        m_dialog->close();
+     }
+-
+-    TRACE() << "cookies:" << cookies;
+-    cookieJar->setCookies(cookies);
+-}
+-
+-void BrowserRequestPrivate::startProgress()
+-{
+-    m_animationLabel->start();
+-    m_webViewLayout->setCurrentIndex(1);
+-}
+-
+-void BrowserRequestPrivate::stopProgress()
+-{
+-    m_animationLabel->stop();
+-    m_webViewLayout->setCurrentIndex(0);
++    q->setResult(QVariantMap());
+ }
+
+-QWidget *BrowserRequestPrivate::buildWebViewPage(const QVariantMap &params)
++void BrowserRequestPrivate::onFinished()
+ {
+     Q_Q(BrowserRequest);
+
+-    QWidget *dialogPage = new QWidget;
+-    m_webViewLayout = new QStackedLayout(dialogPage);
+-
+-    m_webView = new WebView();
+-    WebPage *page = new WebPage(this);
+-    QObject::connect(page, SIGNAL(contentsChanged()),
+-                     this, SLOT(onContentsChanged()));
+-    QObject::connect(page->networkAccessManager(),
+-                     SIGNAL(sslErrors(QNetworkReply*,const QList<QSslError> &)),
+-                     this, SLOT(onSslErrors(QNetworkReply*,const QList<QSslError> &)));
+-    m_webView->setPage(page);
+-
+-    /* The following couple of lines serve to instruct the QWebPage not to load
+-     * the final URL, but to block it and emit the finalUrlReached() signal
+-     * instead.
+-     */
+-    page->setFinalUrl(finalUrl);
+-    QObject::connect(page, SIGNAL(finalUrlReached(const QUrl&)),
+-                     this, SLOT(onUrlChanged(const QUrl&)));
+-
+-    /* set a per-identity cookie jar on the page */
+-    uint identity = q->identity();
+-    CookieJarManager *cookieJarManager = CookieJarManager::instance();
+-    CookieJar *cookieJar = cookieJarManager->cookieJarForIdentity(identity);
+-    addBrowserCookies(cookieJar);
+-    page->networkAccessManager()->setCookieJar(cookieJar);
+-    /* NetworkAccessManager takes ownership of the cookieJar; we don't want
+-     * this */
+-    cookieJar->setParent(cookieJarManager);
+-
+-    const QVariantMap &clientData = q->clientData();
+-    if (clientData.contains(keyAllowedSchemes)) {
+-        page->setAllowedSchemes(clientData[keyAllowedSchemes].toStringList());
+-    } else {
+-        /* by default, allow only https */
+-        page->setAllowedSchemes(QStringList("https"));
+-    }
+-
+-    m_ignoreSslErrors = clientData.value(keyIgnoreSslErrors, false).toBool();
+-
+-    QUrl url(params.value(SSOUI_KEY_OPENURL).toString());
+-    setupViewForUrl(url);
+-    QObject::connect(m_webView, SIGNAL(urlChanged(const QUrl&)),
+-                     this, SLOT(onUrlChanged(const QUrl&)));
+-    QObject::connect(m_webView, SIGNAL(loadProgress(int)),
+-                     this, SLOT(onLoadProgress()));
+-    QObject::connect(m_webView, SIGNAL(loadFinished(bool)),
+-                     this, SLOT(onLoadFinished(bool)));
+-    QWidget *webViewContainer = new QWidget;
+-    QVBoxLayout *vLayout = new QVBoxLayout;
+-    vLayout->setSpacing(0);
+-    webViewContainer->setLayout(vLayout);
+-    vLayout->addWidget(m_webView);
+-
+-    m_httpWarning = new HttpWarning;
+-    m_httpWarning->setVisible(false);
+-    vLayout->addWidget(m_httpWarning);
+-
+-    m_webViewLayout->addWidget(webViewContainer);
+-
+-    m_animationLabel = new AnimationLabel(":/spinner-26.gif", 0);
+-    QObject::connect(m_webView, SIGNAL(loadStarted()),
+-                     this, SLOT(startProgress()));
+-    QObject::connect(m_webView, SIGNAL(loadFinished(bool)),
+-                     this, SLOT(stopProgress()));
+-    m_webViewLayout->addWidget(m_animationLabel);
+-    m_webView->setUrl(url);
+-
+-    return dialogPage;
+-}
+-
+-QWidget *BrowserRequestPrivate::buildSuccessPage()
+-{
+-    QWidget *dialogPage = new QWidget;
+-    dialogPage->setSizePolicy(QSizePolicy::Ignored,
+-                              QSizePolicy::MinimumExpanding);
+-    QVBoxLayout *layout = new QVBoxLayout(dialogPage);
+-
+-    QLabel *label = new QLabel(_("The authentication process is complete.\n"
+-                                 "You may now close this dialog "
+-                                 "and return to the application."));
+-    label->setAlignment(Qt::AlignCenter);
+-    layout->addWidget(label);
+-
+-    QPushButton *doneButton = new QPushButton(_("Done"));
+-    doneButton->setDefault(true);
+-    QObject::connect(doneButton, SIGNAL(clicked()),
+-                     m_dialog, SLOT(accept()));
+-    layout->addWidget(doneButton);
+-
+-    return dialogPage;
+-}
++    TRACE() << "Browser dialog closed";
++    QObject::disconnect(m_dialog, SIGNAL(finished(int)),
++                        this, SLOT(onFinished()));
+
+-QWidget *BrowserRequestPrivate::buildLoadFailurePage()
+-{
+-    QWidget *dialogPage = new QWidget;
+-    dialogPage->setSizePolicy(QSizePolicy::Ignored,
+-                              QSizePolicy::MinimumExpanding);
+-    QVBoxLayout *layout = new QVBoxLayout(dialogPage);
++    QVariantMap reply;
++    QUrl url = m_responseUrl.isEmpty() ? m_currentUrl : m_responseUrl;
++    reply[SSOUI_KEY_URLRESPONSE] = url.toString();
+
+-    QLabel *label = new QLabel(_("An error occurred while loading "
+-                                 "the authentication page."));
+-    label->setAlignment(Qt::AlignCenter);
+-    layout->addWidget(label);
++    m_dialog->close();
+
+-    return dialogPage;
++    q->setResult(reply);
+ }
+
+ void BrowserRequestPrivate::buildDialog(const QVariantMap &params)
+@@ -569,232 +251,15 @@
+         title = _("Web authentication");
+     }
+
+-    m_dialog->setWindowTitle(title);
+-
+-    m_dialogLayout = new QStackedLayout(m_dialog);
+-
+-    m_webViewPage = buildWebViewPage(params);
+-    m_dialogLayout->addWidget(m_webViewPage);
+-
+-    m_successPage = buildSuccessPage();
+-    m_dialogLayout->addWidget(m_successPage);
+-
+-    m_loadFailurePage = buildLoadFailurePage();
+-    m_dialogLayout->addWidget(m_loadFailurePage);
++    m_dialog->setTitle(title);
+
+     TRACE() << "Dialog was built";
+ }
+
+-void BrowserRequestPrivate::start()
+-{
+-    Q_Q(BrowserRequest);
+-
+-    finalUrl = QUrl(q->parameters().value(SSOUI_KEY_FINALURL).toString());
+-    buildDialog(q->parameters());
+-
+-    QObject::connect(m_dialog, SIGNAL(finished(int)),
+-                     this, SLOT(onFinished()));
+-
+-    if (q->embeddedUi()) {
+-        showDialog();
+-    }
+-}
+-
+-void BrowserRequestPrivate::onFinished()
+-{
+-    Q_Q(BrowserRequest);
+-
+-    TRACE() << "Browser dialog closed";
+-
+-    QObject::disconnect(m_webView, 0, this, 0);
+-
+-    QVariantMap reply;
+-    QUrl url = responseUrl.isEmpty() ? m_webView->url() : responseUrl;
+-    reply[SSOUI_KEY_URLRESPONSE] = url.toString();
+-
+-    if (!m_username.isEmpty())
+-        reply[SSOUI_KEY_USERNAME] = m_username;
+-    if (!m_password.isEmpty())
+-        reply[SSOUI_KEY_PASSWORD] = m_password;
+-
+-    q->setResult(reply);
+-}
+-
+-void BrowserRequestPrivate::onContentsChanged()
+-{
+-    /* See https://bugs.webkit.org/show_bug.cgi?id=32865 for the reason why
+-     * we are not simply calling m_usernameField.attribute("value")
+-     */
+-    if (!m_usernameField.isNull()) {
+-        m_username =
+-            m_usernameField.evaluateJavaScript("this.value").toString();
+-    }
+-    if (!m_passwordField.isNull()) {
+-        m_password =
+-            m_passwordField.evaluateJavaScript("this.value").toString();
+-    }
+-}
+-
+-void BrowserRequestPrivate::showDialog()
+-{
+-    Q_Q(BrowserRequest);
+-
+-    q->setWidget(m_dialog);
+-}
+-
+-static Qt::ScrollBarPolicy scrollPolicyFromValue(const QVariant &value)
+-{
+-    QString stringValue = value.toString();
+-    if (stringValue == valueAlwaysOn) {
+-        return Qt::ScrollBarAlwaysOn;
+-    } else if (stringValue == valueAlwaysOff) {
+-        return Qt::ScrollBarAlwaysOff;
+-    } else {
+-        return Qt::ScrollBarAsNeeded;
+-    }
+-}
+-
+-void BrowserRequestPrivate::setupViewForUrl(const QUrl &url)
+-{
+-    QString host = url.host();
+-    if (host == m_host) return;
+-
+-    m_host = host;
+-
+-    /* Load the host-specific configuration file */
+-    delete m_settings;
+-    m_settings = new QSettings("signon-ui/webkit-options.d/" + host, QString(), this);
+-
+-    WebPage *page = qobject_cast<WebPage *>(m_webView->page());
+-
+-    if (m_settings->contains(keyViewportWidth) &&
+-        m_settings->contains(keyViewportHeight)) {
+-        QSize viewportSize(m_settings->value(keyViewportWidth).toInt(),
+-                           m_settings->value(keyViewportHeight).toInt());
+-        m_webView->setPreferredSize(viewportSize);
+-    }
+-
+-    if (m_settings->contains(keyPreferredWidth)) {
+-        QSize preferredSize(m_settings->value(keyPreferredWidth).toInt(), 300);
+-        page->setPreferredContentsSize(preferredSize);
+-    }
+-
+-    if (m_settings->contains(keyTextSizeMultiplier)) {
+-        m_webView->setTextSizeMultiplier(m_settings->value(keyTextSizeMultiplier).
+-                                         toReal());
+-    }
+-
+-    if (m_settings->contains(keyUserAgent)) {
+-        page->setUserAgent(m_settings->value(keyUserAgent).toString());
+-    }
+-
+-    if (m_settings->contains(keyZoomFactor)) {
+-        m_webView->setZoomFactor(m_settings->value(keyZoomFactor).toReal());
+-    }
+-
+-    if (m_settings->contains(keyHorizontalScrollBar)) {
+-        Qt::ScrollBarPolicy policy =
+-            scrollPolicyFromValue(m_settings->value(keyHorizontalScrollBar));
+-        page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, policy);
+-    }
+-
+-    if (m_settings->contains(keyVerticalScrollBar)) {
+-        Qt::ScrollBarPolicy policy =
+-            scrollPolicyFromValue(m_settings->value(keyVerticalScrollBar));
+-        page->mainFrame()->setScrollBarPolicy(Qt::Vertical, policy);
+-    }
+-
+-    page->setExternalLinksPattern(m_settings->value(keyExternalLinksPattern).
+-                                  toString());
+-    page->setInternalLinksPattern(m_settings->value(keyInternalLinksPattern).
+-                                  toString());
+-    page->setAllowedUrls(m_settings->value(keyAllowedUrls).toString());
+-}
+-
+-void BrowserRequestPrivate::notifyAuthCompleted()
+-{
+-    /* Ignore any webview signals from now on.
+-     * This is needed because QWebView might still emit loadFinished(false)
+-     * (which we would interpret as an error) on the final URL, which we don't
+-     * care about anymore. */
+-    QObject::disconnect(m_webView, 0, this, 0);
+-
+-    m_dialogLayout->setCurrentWidget(m_successPage);
+-}
+-
+-void BrowserRequestPrivate::notifyLoadFailed()
+-{
+-    m_dialogLayout->setCurrentWidget(m_loadFailurePage);
+-    showDialog();
+-}
+-
+-QWebElement BrowserRequestPrivate::initializeField(const QString &settingsKey,
+-                                                   const QString &paramKey)
+-{
+-    Q_Q(BrowserRequest);
+-
+-    QWebElement element;
+-
+-    if (!m_settings->contains(settingsKey)) return element;
+-
+-    QString selector = m_settings->value(settingsKey).toString();
+-    if (selector.isEmpty()) return element;
+-
+-    QWebFrame *frame = m_webView->page()->mainFrame();
+-    element = frame->findFirstElement(selector);
+-    if (!element.isNull()) {
+-        const QVariantMap &params = q->parameters();
+-        if (!paramKey.isEmpty() && params.contains(paramKey)) {
+-            QString value = params.value(paramKey).toString();
+-            if (!value.isEmpty()) {
+-                element.setAttribute("value", value);
+-            }
+-        }
+-    } else {
+-        BLAME() << "Couldn't find element:" << selector;
+-    }
+-
+-    return element;
+-}
+-
+-void BrowserRequestPrivate::initializeFields()
+-{
+-    /* If the configuration file contains a "UsernameField" or a
+-     * "PasswordField" key whose value is set to a valid CSS selector, we get
+-     * the QWebElement to these fields.
+-     * Also, if the username or password are present in the input parameters,
+-     * we prefill the respective fields.
+-     */
+-    m_usernameField = initializeField(keyUsernameField, SSOUI_KEY_USERNAME);
+-    m_passwordField = initializeField(keyPasswordField, SSOUI_KEY_PASSWORD);
+-    m_loginButton = initializeField(keyLoginButton);
+-}
+-
+-bool BrowserRequestPrivate::tryAutoLogin()
+-{
+-    if (m_loginButton.isNull()) return false;
+-
+-    if (m_usernameField.isNull() ||
+-        m_usernameField.evaluateJavaScript("this.value").isNull())
+-        return false;
+-
+-    if (m_passwordField.isNull() ||
+-        m_passwordField.evaluateJavaScript("this.value").isNull())
+-        return false;
+-
+-    /* Avoid falling in a failed login loop */
+-    m_loginCount++;
+-    if (m_loginCount > 1)
+-        return false;
+-
+-    m_loginButton.evaluateJavaScript("this.click()");
+-    return true;
+-}
+-
+ BrowserRequest::BrowserRequest(const QDBusConnection &connection,
+-                             const QDBusMessage &message,
+-                             const QVariantMap &parameters,
+-                             QObject *parent):
++                               const QDBusMessage &message,
++                               const QVariantMap &parameters,
++                               QObject *parent):
+     Request(connection, message, parameters, parent),
+     d_ptr(new BrowserRequestPrivate(this))
+ {
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/browser-request.h" /tmp/src/signon-ui/src/browser-request.h
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/browser-request.h"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/browser-request.h	2023-10-04 11:35:19.905523296 +1000
+@@ -1,7 +1,7 @@
+ /*
+  * This file is part of signon-ui
+  *
+- * Copyright (C) 2011 Canonical Ltd.
++ * Copyright (C) 2014 Canonical Ltd.
+  *
+  * Contact: Alberto Mardegan <alberto.mardegan at canonical.com>
+  *
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/debug.cpp" /tmp/src/signon-ui/src/debug.cpp
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/debug.cpp"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/debug.cpp	2023-10-04 11:35:19.905523296 +1000
+@@ -20,10 +20,18 @@
+
+ #include "debug.h"
+
++Q_LOGGING_CATEGORY(DBG_SIGNON_UI, "signon", QtWarningMsg)
++
+ int appLoggingLevel = 1; // criticals
+
+ void setLoggingLevel(int level)
+ {
++    if (level >= 1) {
++        QLoggingCategory::setFilterRules("signon.warning=true");
++        if (level >= 2) {
++            QLoggingCategory::setFilterRules("signon.debug=true");
++        }
++    }
+     appLoggingLevel = level;
+ }
+
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/debug.h" /tmp/src/signon-ui/src/debug.h
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/debug.h"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/debug.h	2023-10-04 11:35:19.905523296 +1000
+@@ -20,21 +20,13 @@
+ #ifndef SIGNON_UI_DEBUG_H
+ #define SIGNON_UI_DEBUG_H
+
+-#include <QDebug>
++#include <QLoggingCategory>
++
++Q_DECLARE_LOGGING_CATEGORY(DBG_SIGNON_UI)
+
+ /* 0 - fatal, 1 - critical(default), 2 - info/debug */
+ extern int appLoggingLevel;
+
+-static inline bool debugEnabled()
+-{
+-    return appLoggingLevel >= 2;
+-}
+-
+-static inline bool criticalsEnabled()
+-{
+-    return appLoggingLevel >= 1;
+-}
+-
+ static inline int loggingLevel()
+ {
+     return appLoggingLevel;
+@@ -42,15 +34,10 @@
+
+ void setLoggingLevel(int level);
+
+-#ifdef DEBUG_ENABLED
+-    #define TRACE() \
+-        if (debugEnabled()) qDebug() << __FILE__ << __LINE__ << __func__
+-    #define BLAME() \
+-        if (criticalsEnabled()) qCritical() << __FILE__ << __LINE__ << __func__
+-#else
+-    #define TRACE() while (0) qDebug()
+-    #define BLAME() while (0) qDebug()
+-#endif
++#define TRACE() \
++    qCDebug(DBG_SIGNON_UI) << __FILE__ << __LINE__ << __func__
++#define BLAME() \
++    qCWarning(DBG_SIGNON_UI) << __FILE__ << __LINE__ << __func__
+
+ #endif // SIGNON_UI_DEBUG_H
+
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/main.cpp" /tmp/src/signon-ui/src/main.cpp
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/main.cpp"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/main.cpp	2023-10-04 11:35:19.905523296 +1000
+@@ -29,6 +29,7 @@
+ #include <QDBusConnection>
+ #include <QProcessEnvironment>
+ #include <QSettings>
++#include <QtWebEngine>
+
+ using namespace SignOnUi;
+
+@@ -39,6 +40,8 @@
+ int main(int argc, char **argv)
+ {
+     QApplication app(argc, argv);
++    QtWebEngine::initialize();
++
+     app.setApplicationName("signon-ui");
+     app.setQuitOnLastWindowClosed(false);
+
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/DefaultPage.qml" /tmp/src/signon-ui/src/qml/DefaultPage.qml
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/DefaultPage.qml"	2016-04-06 19:17:33.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/DefaultPage.qml	2023-10-04 11:35:19.905523296 +1000
+@@ -1,14 +1,11 @@
+ import QtQuick 2.0
+-import Ubuntu.Components 1.3
+
+-Page {
+-    Loader {
+-        id: loader
+-        anchors {
+-            fill: parent
+-            bottomMargin: osk.height
+-        }
+-        focus: true
+-        sourceComponent: browserComponent
++Loader {
++    id: loader
++    anchors {
++        fill: parent
++        bottomMargin: osk.height
+     }
++    focus: true
++    sourceComponent: browserComponent
+ }
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/MainWindow.qml" /tmp/src/signon-ui/src/qml/MainWindow.qml
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/MainWindow.qml"	2016-04-06 19:17:33.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/MainWindow.qml	2023-10-04 11:35:19.905523296 +1000
+@@ -1,10 +1,9 @@
+ import QtQuick 2.0
+-import Ubuntu.Components 1.3
+
+ Item {
+     id: root
+-    width: units.gu(60)
+-    height: units.gu(90)
++    width: 600
++    height: 400
+     property var signonRequest: request
+
+     Loader {
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/ProgressBar.qml" /tmp/src/signon-ui/src/qml/ProgressBar.qml
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/ProgressBar.qml"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/ProgressBar.qml	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,13 @@
++import QtQuick 2.0
++
++Item {
++    id: root
++
++    property real value: 0
++
++    Rectangle {
++        anchors { left: parent.left; top: parent.top; bottom: parent.bottom }
++        color: "red"
++        width: root.value * root.width
++    }
++}
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/UserAgent.qml" /tmp/src/signon-ui/src/qml/UserAgent.qml
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/UserAgent.qml"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/UserAgent.qml	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,90 @@
++/*
++ * Copyright 2013 Canonical Ltd.
++ *
++ * This file is part of webbrowser-app.
++ *
++ * webbrowser-app 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; version 3.
++ *
++ * webbrowser-app 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, see <http://www.gnu.org/licenses/>.
++ */
++
++import QtQuick 2.0
++import QtQuick.Window 2.0
++import Ubuntu.Components 0.1
++import "ua-overrides.js" as Overrides
++
++/*
++ * Useful documentation:
++ *   http://en.wikipedia.org/wiki/User_agent#Format
++ *   https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference
++ *   https://wiki.mozilla.org/B2G/User_Agent
++ *   https://github.com/mozilla-b2g/gaia/blob/master/build/ua-override-prefs.js
++ *   https://developers.google.com/chrome/mobile/docs/user-agent
++ */
++
++// This is an Item, not a QtObject, because it needs information about the Screen.
++Item {
++    // %1: form factor (Mobile, Tablet, Desktop)
++    // %2: WebKit version
++    readonly property string _template: "Mozilla/5.0 (Ubuntu; %1) WebKit/%2"
++
++    // See Source/WebCore/Configurations/Version.xcconfig in QtWebKit’s source tree
++    // TODO: determine this value at runtime
++    readonly property string _webkitVersion: "537.21"
++
++    // FIXME: this is a quick hack that will become increasingly unreliable
++    // as we support more devices, so we need a better solution for this
++    // FIXME: only handling phone and tablet for now, need to handle desktop too
++    readonly property string _formFactor: (Screen.width >= units.gu(60)) ? "Tablet" : "Mobile"
++
++    property string defaultUA: _template.arg(_formFactor).arg(_webkitVersion)
++
++    property var overrides: Overrides.overrides
++
++    function getDomain(url) {
++        var domain = url.toString()
++        var indexOfScheme = domain.indexOf("://")
++        if (indexOfScheme !== -1) {
++            domain = domain.slice(indexOfScheme + 3)
++        }
++        var indexOfPath = domain.indexOf("/")
++        if (indexOfPath !== -1) {
++            domain = domain.slice(0, indexOfPath)
++        }
++        return domain
++    }
++
++    function getDomains(domain) {
++        var components = domain.split(".")
++        var domains = []
++        for (var i = 0; i < components.length; i++) {
++            domains.push(components.slice(i).join("."))
++        }
++        return domains
++    }
++
++    function getUAString(url) {
++        var ua = defaultUA
++        var domains = getDomains(getDomain(url))
++        for (var i = 0; i < domains.length; i++) {
++            var domain = domains[i]
++            if (domain in overrides) {
++                var form = overrides[domain]
++                if (typeof form == "string") {
++                    return form
++                } else if (typeof form == "object") {
++                    return ua.replace(form[0], form[1])
++                }
++            }
++        }
++        return ua
++    }
++}
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/WebView.qml" /tmp/src/signon-ui/src/qml/WebView.qml
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/WebView.qml"	2016-04-06 19:17:33.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/WebView.qml	2023-10-04 11:35:19.905523296 +1000
+@@ -1,35 +1,37 @@
+ import QtQuick 2.0
+-import Ubuntu.Components 1.3
+-import Ubuntu.Web 0.2
++import QtWebEngine 1.1
+
+-WebView {
++WebEngineView {
+     id: root
+
++    property bool lastLoadFailed: false
++
+     Component.onCompleted: url = signonRequest.startUrl
+
+-    onLoadingStateChanged: {
++    onLoadingChanged: {
+         console.log("Loading changed")
+         if (loading && !lastLoadFailed) {
+             signonRequest.onLoadStarted()
+-        } else if (lastLoadSucceeded) {
++        } else if (loadRequest.status == WebEngineView.LoadSucceededStatus) {
++            lastLoadFailed = false
+             signonRequest.onLoadFinished(true)
+-        } else if (lastLoadFailed) {
++        } else if (loadRequest.status == WebEngineView.LoadFailedStatus) {
++            lastLoadFailed = true
+             signonRequest.onLoadFinished(false)
+         }
+     }
+     onUrlChanged: signonRequest.currentUrl = url
+
+-    context: WebContext {
+-        dataPath: rootDir
++    profile: WebEngineProfile {
++        cachePath: rootDir
++        persistentStoragePath: rootDir
+     }
+
+-    /* Taken from webbrowser-app */
+     ProgressBar {
+         anchors.top: parent.top
+         anchors.left: parent.left
+         anchors.right: parent.right
+-        height: units.dp(3)
+-        showProgressPercentage: false
++        height: 6
+         visible: root.loading
+         value: root.loadProgress / 100
+     }
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/browser-process.cpp" /tmp/src/signon-ui/src/qml/browser-process.cpp
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/browser-process.cpp"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/browser-process.cpp	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,291 @@
++/*
++ * This file is part of signon-ui
++ *
++ * Copyright (C) 2013 Canonical Ltd.
++ *
++ * Contact: Alberto Mardegan <alberto.mardegan at canonical.com>
++ *
++ * This program is free software: you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 3, as published
++ * by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranties of
++ * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "browser-process.h"
++
++#include "debug.h"
++#include "dialog.h"
++#include "i18n.h"
++#include "remote-request-interface.h"
++
++#include <QQmlContext>
++#include <SignOn/uisessiondata_priv.h>
++#include <stdio.h>
++#include <QDir>
++#include <QFile>
++#include <QTimer>
++
++using namespace SignOnUi;
++
++namespace SignOnUi {
++
++class BrowserProcessPrivate: public QObject
++{
++    Q_OBJECT
++    Q_DECLARE_PUBLIC(BrowserProcess)
++    Q_PROPERTY(QUrl pageComponentUrl READ pageComponentUrl CONSTANT)
++    Q_PROPERTY(QUrl currentUrl READ currentUrl WRITE setCurrentUrl)
++    Q_PROPERTY(QUrl startUrl READ startUrl CONSTANT)
++    Q_PROPERTY(QUrl finalUrl READ finalUrl CONSTANT)
++
++public:
++    BrowserProcessPrivate(BrowserProcess *request);
++    ~BrowserProcessPrivate();
++
++    void processClientRequest();
++
++    void setCurrentUrl(const QUrl &url);
++    QUrl pageComponentUrl() const;
++    QUrl currentUrl() const { return m_currentUrl; }
++    QUrl startUrl() const { return m_startUrl; }
++    QUrl finalUrl() const { return m_finalUrl; }
++    QUrl responseUrl() const { return m_responseUrl; }
++    WId windowId() const {
++        return m_clientData[SSOUI_KEY_WINDOWID].toUInt();
++    }
++    bool embeddedUi() const {
++        return m_clientData[SSOUI_KEY_EMBEDDED].toBool();
++    }
++
++
++public Q_SLOTS:
++    void onLoadStarted();
++    void onLoadFinished(bool ok);
++    void cancel();
++
++private Q_SLOTS:
++    void start(const QVariantMap &params);
++    void onFailTimer();
++    void onFinished();
++
++private:
++    void buildDialog(const QVariantMap &params);
++
++private:
++    Dialog *m_dialog;
++    QVariantMap m_clientData;
++    QUrl m_currentUrl;
++    QUrl m_startUrl;
++    QUrl m_finalUrl;
++    QUrl m_responseUrl;
++    QString m_host;
++    QFile m_input;
++    QFile m_output;
++    RemoteRequestServer m_server;
++    QTimer m_failTimer;
++    mutable BrowserProcess *q_ptr;
++};
++
++} // namespace
++
++BrowserProcessPrivate::BrowserProcessPrivate(BrowserProcess *process):
++    QObject(process),
++    m_dialog(0),
++    q_ptr(process)
++{
++    m_failTimer.setSingleShot(true);
++    m_failTimer.setInterval(3000);
++    QObject::connect(&m_failTimer, SIGNAL(timeout()),
++                     this, SLOT(onFailTimer()));
++}
++
++BrowserProcessPrivate::~BrowserProcessPrivate()
++{
++    delete m_dialog;
++}
++
++QUrl BrowserProcessPrivate::pageComponentUrl() const
++{
++    /* We define the X-PageComponent key to let the clients override the QML
++     * component to be used to build the authentication page.
++     * To prevent a malicious client to show it's own UI, we require that the
++     * file path begins with "/usr/share/signon-ui/" (where Ubuntu click
++     * packages cannot install files).
++     */
++    QUrl providedUrl = m_clientData.value("X-PageComponent").toString();
++    if (providedUrl.isValid() && providedUrl.isLocalFile() &&
++        providedUrl.path().startsWith("/usr/share/signon-ui/")) {
++        return providedUrl;
++    } else {
++        return QStringLiteral("DefaultPage.qml");
++    }
++}
++
++void BrowserProcessPrivate::processClientRequest()
++{
++    TRACE();
++    m_input.open(stdin, QIODevice::ReadOnly);
++    m_output.open(stdout, QIODevice::WriteOnly);
++
++    QObject::connect(&m_server, SIGNAL(started(const QVariantMap&)),
++                     this, SLOT(start(const QVariantMap&)));
++    QObject::connect(&m_server, SIGNAL(canceled()),
++                     this, SLOT(cancel()));
++
++    /* This effectively starts the communication with the client */
++    m_server.setChannels(&m_input, &m_output);
++}
++
++void BrowserProcessPrivate::setCurrentUrl(const QUrl &url)
++{
++    TRACE() << "Url changed:" << url;
++    m_failTimer.stop();
++
++    if (url.host() == m_finalUrl.host() &&
++        url.path() == m_finalUrl.path()) {
++        m_responseUrl = url;
++        if (!m_dialog->isVisible()) {
++            /* Do not show the notification page. */
++            m_dialog->accept();
++        } else {
++            /* Replace the web page with an information screen */
++            /* TODO */
++            m_dialog->accept();
++        }
++    }
++}
++
++void BrowserProcessPrivate::onLoadStarted()
++{
++    m_failTimer.stop();
++}
++
++void BrowserProcessPrivate::onLoadFinished(bool ok)
++{
++    TRACE() << "Load finished" << ok;
++
++    if (!ok) {
++        m_failTimer.start();
++        return;
++    }
++
++    if (!m_dialog->isVisible()) {
++        if (m_responseUrl.isEmpty()) {
++            Dialog::ShowMode mode = (windowId() == 0) ? Dialog::TopLevel :
++                embeddedUi() ? Dialog::Embedded : Dialog::Transient;
++            m_dialog->show(windowId(), mode);
++        } else {
++            onFinished();
++        }
++    }
++}
++
++void BrowserProcessPrivate::start(const QVariantMap &params)
++{
++    TRACE() << params;
++    if (params.contains(SSOUI_KEY_CLIENT_DATA)) {
++        m_clientData = params[SSOUI_KEY_CLIENT_DATA].toMap();
++    }
++    m_finalUrl = params.value(SSOUI_KEY_FINALURL).toString();
++    m_startUrl = params.value(SSOUI_KEY_OPENURL).toString();
++    buildDialog(params);
++
++    QObject::connect(m_dialog, SIGNAL(finished(int)),
++                     this, SLOT(onFinished()));
++
++    QUrl webview("qrc:/MainWindow.qml");
++    QDir qmlDir("/usr/share/signon-ui/qml");
++    if (qmlDir.exists())
++    {
++        QFileInfo qmlFile(qmlDir.absolutePath() + "/MainWindow.qml");
++        if (qmlFile.exists())
++            webview.setUrl(qmlFile.absoluteFilePath());
++    }
++
++    m_dialog->rootContext()->setContextProperty("request", this);
++    m_dialog->setSource(webview);
++}
++
++void BrowserProcessPrivate::cancel()
++{
++    Q_Q(BrowserProcess);
++
++    TRACE() << "Client requested to cancel";
++    m_server.setCanceled();
++    if (m_dialog) {
++        m_dialog->close();
++    }
++    Q_EMIT q->finished();
++}
++
++void BrowserProcessPrivate::onFailTimer()
++{
++    Q_Q(BrowserProcess);
++
++    TRACE() << "Page loading failed";
++    m_server.setResult(QVariantMap());
++    if (m_dialog) {
++        m_dialog->close();
++    }
++    Q_EMIT q->finished();
++}
++
++void BrowserProcessPrivate::onFinished()
++{
++    Q_Q(BrowserProcess);
++
++    TRACE() << "Browser dialog closed";
++
++    QVariantMap reply;
++    QUrl url = m_responseUrl.isEmpty() ? m_currentUrl : m_responseUrl;
++    reply[SSOUI_KEY_URLRESPONSE] = url.toString();
++
++    m_server.setResult(reply);
++    m_dialog->close();
++
++    Q_EMIT q->finished();
++}
++
++void BrowserProcessPrivate::buildDialog(const QVariantMap &params)
++{
++    m_dialog = new Dialog;
++
++    QString title;
++    if (params.contains(SSOUI_KEY_TITLE)) {
++        title = params[SSOUI_KEY_TITLE].toString();
++    } else if (params.contains(SSOUI_KEY_CAPTION)) {
++        title = _("Web authentication for %1").
++            arg(params[SSOUI_KEY_CAPTION].toString());
++    } else {
++        title = _("Web authentication");
++    }
++
++    m_dialog->setTitle(title);
++
++    TRACE() << "Dialog was built";
++}
++
++BrowserProcess::BrowserProcess(QObject *parent):
++    QObject(parent),
++    d_ptr(new BrowserProcessPrivate(this))
++{
++}
++
++BrowserProcess::~BrowserProcess()
++{
++}
++
++void BrowserProcess::processClientRequest()
++{
++    Q_D(BrowserProcess);
++    d->processClientRequest();
++}
++
++#include "browser-process.moc"
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/browser-process.h" /tmp/src/signon-ui/src/qml/browser-process.h
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/browser-process.h"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/browser-process.h	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,50 @@
++/*
++ * This file is part of signon-ui
++ *
++ * Copyright (C) 2013 Canonical Ltd.
++ *
++ * Contact: Alberto Mardegan <alberto.mardegan at canonical.com>
++ *
++ * This program is free software: you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 3, as published
++ * by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranties of
++ * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef SIGNON_UI_BROWSER_PROCESS_H
++#define SIGNON_UI_BROWSER_PROCESS_H
++
++#include <QObject>
++
++namespace SignOnUi {
++
++class BrowserProcessPrivate;
++class BrowserProcess: public QObject
++{
++    Q_OBJECT
++
++public:
++    BrowserProcess(QObject *parent = 0);
++    ~BrowserProcess();
++
++    void processClientRequest();
++
++Q_SIGNALS:
++    void finished();
++
++private:
++    BrowserProcessPrivate *d_ptr;
++    Q_DECLARE_PRIVATE(BrowserProcess)
++};
++
++} // namespace
++
++#endif // SIGNON_UI_BROWSER_PROCESS_H
++
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/browser-process.pro" /tmp/src/signon-ui/src/qml/browser-process.pro
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/browser-process.pro"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/browser-process.pro	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,64 @@
++include(../../common-project-config.pri)
++include($${TOP_SRC_DIR}/common-vars.pri)
++
++TEMPLATE = app
++TARGET = browser-process
++
++target.path = $${LIBEXECDIR}/signon-ui
++INSTALLS += target
++
++I18N_DOMAIN = signon-ui
++
++CONFIG += \
++    link_pkgconfig \
++    qt
++
++QT += \
++    core \
++    gui \
++    quick
++
++PKGCONFIG += \
++    signon-plugins-common
++
++INCLUDEPATH += ..
++
++HEADERS = \
++    browser-process.h \
++    debug.h \
++    dialog.h \
++    ../i18n.h \
++    ../remote-request-interface.h
++SOURCES = \
++    browser-process.cpp \
++    dialog.cpp \
++    main.cpp \
++    ../i18n.cpp \
++    ../remote-request-interface.cpp
++
++DEFINES += \
++    DEBUG_ENABLED \
++    I18N_DOMAIN=\\\"$${I18N_DOMAIN}\\\"
++
++CONFIG(force-foreign-qwindow) {
++    DEFINES += FORCE_FOREIGN_QWINDOW
++}
++
++OTHER_FILES += \
++    DefaultPage.qml \
++    KeyboardRectangle.qml \
++    MainWindow.qml \
++    StandardAnimation.qml \
++    UserAgent.qml \
++    WebView.qml \
++    ua-overrides.js
++
++RESOURCES += \
++    qml.qrc
++
++QMAKE_SUBSTITUTES += \
++    signon-ui-browser-process.desktop.in
++desktop.path = $${INSTALL_PREFIX}/share/applications
++desktop.files += signon-ui-browser-process.desktop
++INSTALLS += desktop
++
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/debug.h" /tmp/src/signon-ui/src/qml/debug.h
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/debug.h"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/debug.h	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,37 @@
++/*
++ * This file is part of signon-ui
++ *
++ * Copyright (C) 2011 Canonical Ltd.
++ *
++ * Contact: Alberto Mardegan <alberto.mardegan at canonical.com>
++ *
++ * This program is free software: you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 3, as published
++ * by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranties of
++ * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
++ */
++#ifndef SIGNON_UI_DEBUG_H
++#define SIGNON_UI_DEBUG_H
++
++#include <QDebug>
++
++
++#ifdef DEBUG_ENABLED
++    #define TRACE() \
++        qDebug() << __FILE__ << __LINE__ << __func__
++    #define BLAME() \
++        qCritical() << __FILE__ << __LINE__ << __func__
++#else
++    #define TRACE() while (0) qDebug()
++    #define BLAME() while (0) qDebug()
++#endif
++
++#endif // SIGNON_UI_DEBUG_H
++
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/main.cpp" /tmp/src/signon-ui/src/qml/main.cpp
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/main.cpp"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/main.cpp	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,68 @@
++/*
++ * This file is part of signon-ui
++ *
++ * Copyright (C) 2013 Canonical Ltd.
++ *
++ * Contact: Alberto Mardegan <alberto.mardegan at canonical.com>
++ *
++ * This program is free software: you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 3, as published
++ * by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranties of
++ * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "browser-process.h"
++
++#include "debug.h"
++
++#include <QGuiApplication>
++#include <fcntl.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++
++using namespace SignOnUi;
++
++void stderrMessage(QtMsgType type, const QMessageLogContext &context,
++                   const QString &msg)
++{
++    Q_UNUSED(context);
++    QByteArray localMsg = msg.toLocal8Bit();
++    switch (type) {
++    case QtDebugMsg:
++        fprintf(stderr, "Debug: %s\n", localMsg.constData());
++        break;
++    case QtWarningMsg:
++        fprintf(stderr, "Warning: %s\n", localMsg.constData());
++        break;
++    case QtCriticalMsg:
++        fprintf(stderr, "Critical: %s\n", localMsg.constData());
++        break;
++    case QtFatalMsg:
++        fprintf(stderr, "Fatal: %s\n", localMsg.constData());
++        abort();
++    }
++}
++
++int main(int argc, char **argv)
++{
++    qInstallMessageHandler(stderrMessage);
++    TRACE() << "started";
++    QGuiApplication app(argc, argv);
++    app.setQuitOnLastWindowClosed(false);
++    fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL, 0) | O_NONBLOCK);
++    BrowserProcess browserProcess;
++
++    QObject::connect(&browserProcess, SIGNAL(finished()),
++                     &app, SLOT(quit()));
++    browserProcess.processClientRequest();
++    return app.exec();
++}
++
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/qml.qrc" /tmp/src/signon-ui/src/qml/qml.qrc
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/qml.qrc"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/qml.qrc	2023-10-04 11:35:19.905523296 +1000
+@@ -3,6 +3,7 @@
+         <file>DefaultPage.qml</file>
+         <file>KeyboardRectangle.qml</file>
+         <file>MainWindow.qml</file>
++        <file>ProgressBar.qml</file>
+         <file>StandardAnimation.qml</file>
+         <file>WebView.qml</file>
+     </qresource>
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/signon-ui-browser-process.desktop.in" /tmp/src/signon-ui/src/qml/signon-ui-browser-process.desktop.in
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/signon-ui-browser-process.desktop.in"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/signon-ui-browser-process.desktop.in	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,11 @@
++[Desktop Entry]
++Encoding=UTF-8
++Version=1.0
++Name=Account authentication
++Comment=Login to online accounts
++Exec=$${target.path}/$$TARGET
++Icon=
++Type=Application
++Terminal=false
++NoDisplay=true
++X-Ubuntu-Gettext-Domain=signon-ui
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/ua-overrides.js" /tmp/src/signon-ui/src/qml/ua-overrides.js
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qml/ua-overrides.js"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/src/qml/ua-overrides.js	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,99 @@
++/*
++ * Copyright 2013 Canonical Ltd.
++ *
++ * This file is part of webbrowser-app.
++ *
++ * webbrowser-app 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; version 3.
++ *
++ * webbrowser-app 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, see <http://www.gnu.org/licenses/>.
++ */
++
++.pragma library
++
++// B2G’s list of overrides: https://github.com/mozilla-b2g/gaia/blob/master/build/ua-override-prefs.js
++
++// List of user agent string overrides in the form of an object.
++// Each key is a domain name for which the default user agent string doesn’t
++// work well enough. Values can either be a string (full override) or an array
++// containing two values that are passed to the String.replace method (the
++// first value may be either a string or a regular expression, the second value
++// must be a string).
++
++// Examples of valid entries:
++//     "example.org": "full override"
++//     "example.com": ["Ubuntu", "Ubuntu Edge"]
++//     "google.com": [/mobi/i, "b"]
++
++// The original list was initially built from the top 100 entries
++// at http://www.alexa.com/topsites (2013-08-16), using Chrome on
++// Android as a reference.
++
++var overrides = {
++    "mail.google.com": [/Mobile\) WebKit\/[.0-9]*/, "Android 4.3) AppleWebKit Mobile Safari"],
++    "google.com": ["Mobile", "Android; Mobile"],
++    "youtube.com": ["Mobile", "Android; Mobile"],
++    "yahoo.com": ["Mobile", "Android; Mobile"],
++    "baidu.com": ["Mobile", "Android; Mobile"],
++    "qq.com": [/WebKit\/[.0-9]*/, "Apple$& Mobile"],
++    "amazon.com": ["Mobile", "Android; Mobile"],
++    "linkedin.com": ["Mobile", "Android; Mobile"],
++    "blogspot.com": ["Mobile", "Android; Mobile"],
++    "taobao.com": ["Mobile", "Android; Mobile"],
++    "google.co.in": ["Mobile", "Android; Mobile"],
++    "bing.com": ["Mobile", "Android; Mobile"],
++    "yahoo.co.jp": ["Ubuntu", "Linux; Android 4; Galaxy Build/"],
++    "yandex.ru": ["Mobile", "Android; Mobile"],
++    "sina.com.cn": ["Mobile", "Android; Mobile"],
++    "ebay.com": ["Mobile", "Android; Mobile"],
++    "google.de": ["Mobile", "Android; Mobile"],
++    "tumblr.com": ["Mobile", "Android; Mobile"],
++    "google.co.uk": ["Mobile", "Android; Mobile"],
++    "msn.com": ["Mobile", "Android; Mobile"],
++    "google.fr": ["Mobile", "Android; Mobile"],
++    "mail.ru": ["Ubuntu", "Linux; Android 4; Galaxy Build/"],
++    "google.com.br": ["Mobile", "Android; Mobile"],
++    "google.co.jp": ["Mobile", "Android; Mobile"],
++    "hao123.com": ["Mobile", "Android; Mobile"],
++    "ask.com": ["Mobile", "Android; Mobile"],
++    "google.com.hk": ["Mobile", "Android; Mobile"],
++    "google.ru": ["Mobile", "Android; Mobile"],
++    "blogger.com": ["Mobile", "Android; Mobile"],
++    "imdb.com": ["Mobile", "Android; Mobile"],
++    "google.it": ["Mobile", "Android; Mobile"],
++    "google.es": ["Mobile", "Android; Mobile"],
++    "amazon.co.jp": ["Mobile", "Android; Mobile"],
++    "tmall.com": ["Mobile", "Android; Mobile"],
++    "fc2.com": ["Mobile", "Android; Mobile"],
++    "google.com.mx": ["Mobile", "Android; Mobile"],
++    "google.ca": ["Mobile", "Android; Mobile"],
++    "soso.com": ["Mobile", "Android; Mobile"],
++    "delta-search.com": ["Mobile", "Android; Mobile"],
++    "odnoklassniki.ru": ["Mobile", "Android; Mobile"],
++    "alibaba.com": ["Mobile", "Android; Mobile"],
++    "flickr.com": ["Mobile", "Android; Mobile"],
++    "amazon.de": ["Mobile", "Android; Mobile"],
++    "blogspot.in": ["Mobile", "Android; Mobile"],
++    "ifeng.com": ["Mobile", "Android; Mobile"],
++    "360.cn": ["Mobile", "Android; Mobile"],
++    "google.com.tr": ["Mobile", "Android; Mobile"],
++    "google.com.au": ["Mobile", "Android; Mobile"],
++    "youku.com": ["Mobile", "Android; Mobile"],
++    "ebay.de": ["Mobile", "Android; Mobile"],
++    "uol.com.br": ["Mobile", "Android; Mobile"],
++    "aol.com": ["Mobile", "Android; Mobile"],
++    "google.pl": ["Mobile", "Android; Mobile"],
++    "alipay.com": ["Mobile", "Android; Mobile"],
++    "dailymotion.com": ["Mobile", "Android; Mobile Safari"],
++    "amazon.co.uk": ["Mobile", "Android; Mobile"],
++    "ebay.co.uk": ["Mobile", "Android; Mobile"],
++    "facebook.com": [/WebKit\/[.0-9]*/, "Apple$& Firefox/18"],
++    "nytimes.com": ["Mobile", "Android; Mobile Safari"],
++};
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qquick-dialog.cpp" /tmp/src/signon-ui/src/qquick-dialog.cpp
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qquick-dialog.cpp"	2016-04-06 19:17:33.000000000 +1000
++++ /tmp/src/signon-ui/src/qquick-dialog.cpp	2023-10-04 11:35:19.905523296 +1000
+@@ -18,9 +18,6 @@
+  * with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+
+-#define HAS_FOREIGN_QWINDOW (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) || \
+-                             defined(FORCE_FOREIGN_QWINDOW))
+-
+ #include "qquick-dialog.h"
+
+ #include "debug.h"
+@@ -39,22 +36,6 @@
+ {
+ }
+
+-void Dialog::show(WId parent, ShowMode mode)
+-{
+-    create();
+-#if HAS_FOREIGN_QWINDOW
+-    if (mode != TopLevel) {
+-        QWindow *parentWindow = QWindow::fromWinId(parent);
+-        if (mode == Transient) {
+-            setTransientParent(parentWindow);
+-        } else if (mode == Embedded) {
+-            setParent(parentWindow);
+-        }
+-    }
+-#endif
+-    QQuickView::show();
+-}
+-
+ void Dialog::accept()
+ {
+     done(Dialog::Accepted);
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qquick-dialog.h" /tmp/src/signon-ui/src/qquick-dialog.h
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/qquick-dialog.h"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/qquick-dialog.h	2023-10-04 11:35:19.905523296 +1000
+@@ -45,8 +45,6 @@
+     explicit Dialog(QWindow *parent = 0);
+     ~Dialog();
+
+-    void show(WId parent, ShowMode mode);
+-
+ public Q_SLOTS:
+     void accept();
+     void reject();
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/request.cpp" /tmp/src/signon-ui/src/request.cpp
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/request.cpp"	2016-04-06 19:17:33.000000000 +1000
++++ /tmp/src/signon-ui/src/request.cpp	2023-10-04 11:35:19.905523296 +1000
+@@ -18,20 +18,13 @@
+  * with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+
+-#define HAS_XEMBED (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
+ #define HAS_FOREIGN_QWINDOW (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) || \
+                              defined(FORCE_FOREIGN_QWINDOW))
+ #include "request.h"
+
+-#ifdef USE_UBUNTU_WEB_VIEW
+-#include "ubuntu-browser-request.h"
+-#endif
+ #include "browser-request.h"
+ #include "debug.h"
+ #include "dialog-request.h"
+-#if HAS_XEMBED
+-#include "embed-manager.h"
+-#endif
+ #include "errors.h"
+ #include "indicator-service.h"
+ #ifndef UNIT_TESTS
+@@ -81,13 +74,10 @@
+     }
+
+ private Q_SLOTS:
+-#if HAS_XEMBED
+-    void onEmbedError();
+-#endif
+     void onIndicatorCallFinished(QDBusPendingCallWatcher *watcher);
+
+ private:
+-    void setWidget(QWidget *widget);
++    bool setWindow(QWindow *window);
+     Accounts::Account *findAccount();
+     bool dispatchToIndicator();
+     void onIndicatorCallSucceeded();
+@@ -100,7 +90,7 @@
+     QVariantMap m_clientData;
+     bool m_inProgress;
+     Accounts::Manager *m_accountManager;
+-    QPointer<QWidget> m_widget;
++    QPointer<QWindow> m_window;
+ };
+
+ } // namespace
+@@ -116,7 +106,7 @@
+     m_parameters(parameters),
+     m_inProgress(false),
+     m_accountManager(0),
+-    m_widget(0)
++    m_window(0)
+ {
+     if (parameters.contains(SSOUI_KEY_CLIENT_DATA)) {
+         QVariant variant = parameters[SSOUI_KEY_CLIENT_DATA];
+@@ -130,83 +120,43 @@
+ {
+ }
+
+-void RequestPrivate::setWidget(QWidget *widget)
++bool RequestPrivate::setWindow(QWindow *window)
+ {
+-    if (m_widget != 0) {
++    if (m_window != 0) {
+         BLAME() << "Widget already set";
+-        return;
++        return false;
+     }
+
+-    m_widget = widget;
++    m_window = window;
+
+-#if HAS_XEMBED
+-    if (embeddedUi() && windowId() != 0) {
+-        TRACE() << "Requesting widget embedding";
+-        QX11EmbedWidget *embed =
+-            EmbedManager::instance()->widgetFor(windowId());
+-        QObject::connect(embed, SIGNAL(error(QX11EmbedWidget::Error)),
+-                         this, SLOT(onEmbedError()),
+-                         Qt::UniqueConnection);
+-        QObject::connect(embed, SIGNAL(containerClosed()),
+-                         widget, SLOT(close()));
+-        QVBoxLayout *layout = new QVBoxLayout;
+-        layout->addWidget(widget);
+-        widget->show();
+-        /* Delete any previous layout */
+-        delete embed->layout();
+-        embed->setLayout(layout);
+-        embed->show();
+-        return;
+-    }
+-#endif
+ #if HAS_FOREIGN_QWINDOW
+     if (embeddedUi() && windowId() != 0) {
+         TRACE() << "Requesting window embedding";
+         QWindow *host = QWindow::fromWinId(windowId());
+-        widget->show();
+-        widget->windowHandle()->setParent(host);
+-        return;
++        window->show();
++        window->setParent(host);
++        return true;
+     }
+ #endif
+
+     /* If the window has no parent and the webcredentials indicator service is
+      * up, dispatch the request to it. */
+     if (windowId() == 0 && dispatchToIndicator()) {
+-        return;
++        return false;
+     }
+
+-    widget->setWindowModality(Qt::WindowModal);
+-    widget->show();
+-#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+-    if (windowId() != 0) {
+-        TRACE() << "Setting" << widget->effectiveWinId() << "transient for" << windowId();
+-        XSetTransientForHint(QX11Info::display(),
+-                             widget->effectiveWinId(),
+-                             windowId());
+-    }
+-#endif
++    window->setModality(Qt::WindowModal);
++    window->show();
+ #if HAS_FOREIGN_QWINDOW
+     if (windowId() != 0) {
+         TRACE() << "Requesting window reparenting";
+         QWindow *parent = QWindow::fromWinId(windowId());
+-        widget->windowHandle()->setTransientParent(parent);
++        window->setTransientParent(parent);
+     }
+ #endif
++    return true;
+ }
+
+-#if HAS_XEMBED
+-void RequestPrivate::onEmbedError()
+-{
+-    Q_Q(Request);
+-
+-    QX11EmbedWidget *embed = qobject_cast<QX11EmbedWidget*>(sender());
+-    TRACE() << "Embed error:" << embed->error();
+-
+-    q->fail(SIGNON_UI_ERROR_EMBEDDING_FAILED,
+-            QString("Embedding signon UI failed: %1").arg(embed->error()));
+-}
+-#endif
+-
+ Accounts::Account *RequestPrivate::findAccount()
+ {
+     if (!m_parameters.contains(SSOUI_KEY_IDENTITY))
+@@ -285,8 +235,8 @@
+     if (watcher->isError()) {
+         /* if the notification could not be delivered to the indicator, show
+          * the widget. */
+-        if (m_widget != 0)
+-            m_widget->show();
++        if (m_window != 0)
++            m_window->show();
+     } else {
+         onIndicatorCallSucceeded();
+     }
+@@ -310,16 +260,8 @@
+                              QObject *parent)
+ {
+     if (parameters.contains(SSOUI_KEY_OPENURL)) {
+-#ifdef USE_UBUNTU_WEB_VIEW
+-        TRACE() << "Platform:" << QGuiApplication::platformName();
+-        if (QGuiApplication::platformName().startsWith("ubuntu") ||
+-            qgetenv("XDG_CURRENT_DESKTOP") == QByteArray("Unity") ||
+-            qgetenv("SSOUI_USE_UBUNTU_WEB_VIEW") == QByteArray("1")) {
+-            return new UbuntuBrowserRequest(connection, message,
+-                                            parameters, parent);
+-        }
+-#endif
+-        return new BrowserRequest(connection, message, parameters, parent);
++        return new BrowserRequest(connection, message,
++                                  parameters, parent);
+     } else {
+         return new DialogRequest(connection, message, parameters, parent);
+     }
+@@ -352,7 +294,15 @@
+ void Request::setWidget(QWidget *widget)
+ {
+     Q_D(Request);
+-    d->setWidget(widget);
++    if (d->setWindow(widget->windowHandle())) {
++        widget->show();
++    }
++}
++
++void Request::setWindow(QWindow *window)
++{
++    Q_D(Request);
++    d->setWindow(window);
+ }
+
+ uint Request::identity() const
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/request.h" /tmp/src/signon-ui/src/request.h
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/request.h"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/request.h	2023-10-04 11:35:19.905523296 +1000
+@@ -70,6 +70,7 @@
+                      QObject *parent = 0);
+
+     void setWidget(QWidget *widget);
++    void setWindow(QWindow *window);
+
+ protected Q_SLOTS:
+     void fail(const QString &name, const QString &message);
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/signon-ui.pro" /tmp/src/signon-ui/src/signon-ui.pro
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/signon-ui.pro"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/signon-ui.pro	2023-10-04 11:35:19.905523296 +1000
+@@ -17,7 +17,7 @@
+     gui \
+     network \
+     quick \
+-    webkit
++    webengine
+
+ PKGCONFIG += \
+     signon-plugins-common \
+@@ -31,7 +31,6 @@
+         x11
+ } else {
+     QT += \
+-        webkitwidgets \
+         widgets
+     PKGCONFIG += \
+         accounts-qt5 \
+@@ -54,6 +53,7 @@
+     inactivity-timer.h \
+     indicator-service.h \
+     network-access-manager.h \
++    qquick-dialog.h \
+     reauthenticator.h \
+     request.h \
+     service.h \
+@@ -73,6 +73,7 @@
+     main.cpp \
+     my-network-proxy-factory.cpp \
+     network-access-manager.cpp \
++    qquick-dialog.cpp \
+     reauthenticator.cpp \
+     request.cpp \
+     service.cpp \
+@@ -83,33 +84,20 @@
+     SOURCES += embed-manager.cpp
+ }
+
+-COMMANDLINE = ""
+-
+-CONFIG(use-ubuntu-web-view) {
+-    DEFINES += USE_UBUNTU_WEB_VIEW
+-    HEADERS += \
+-        qquick-dialog.h \
+-        ubuntu-browser-request.h
+-    SOURCES += \
+-        qquick-dialog.cpp \
+-        ubuntu-browser-request.cpp
+-    OTHER_FILES += \
+-        qml/DefaultPage.qml \
+-        qml/KeyboardRectangle.qml \
+-        qml/MainWindow.qml \
+-        qml/StandardAnimation.qml \
+-        qml/WebView.qml
+-    RESOURCES += \
+-        qml/qml.qrc
+-
+-    QMAKE_SUBSTITUTES += \
+-        signon-ui.desktop.in
+-    desktop.path = $${INSTALL_PREFIX}/share/applications
+-    desktop.files += signon-ui.desktop
+-    INSTALLS += desktop
++OTHER_FILES += \
++    qml/DefaultPage.qml \
++    qml/KeyboardRectangle.qml \
++    qml/MainWindow.qml \
++    qml/StandardAnimation.qml \
++    qml/WebView.qml
++RESOURCES += \
++    qml/qml.qrc
+
+-    COMMANDLINE += " --desktop_file_hint=$${INSTALL_PREFIX}/share/applications/signon-ui.desktop"
+-}
++QMAKE_SUBSTITUTES += \
++    signon-ui.desktop.in
++desktop.path = $${INSTALL_PREFIX}/share/applications
++desktop.files += signon-ui.desktop
++INSTALLS += desktop
+
+ DEFINES += \
+     DEBUG_ENABLED \
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/ubuntu-browser-request.cpp" /tmp/src/signon-ui/src/ubuntu-browser-request.cpp
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/ubuntu-browser-request.cpp"	2016-04-06 19:17:33.000000000 +1000
++++ /tmp/src/signon-ui/src/ubuntu-browser-request.cpp	1970-01-01 10:00:00.000000000 +1000
+@@ -1,281 +0,0 @@
+-/*
+- * This file is part of signon-ui
+- *
+- * Copyright (C) 2013 Canonical Ltd.
+- *
+- * Contact: Alberto Mardegan <alberto.mardegan at canonical.com>
+- *
+- * This program is free software: you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License version 3, as published
+- * by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranties of
+- * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#include "ubuntu-browser-request.h"
+-
+-#include "debug.h"
+-#include "qquick-dialog.h"
+-#include "errors.h"
+-#include "i18n.h"
+-
+-#include <QDir>
+-#include <QQmlContext>
+-#include <QStandardPaths>
+-#include <QTimer>
+-#include <SignOn/uisessiondata_priv.h>
+-
+-using namespace SignOnUi;
+-using namespace SignOnUi::QQuick;
+-
+-namespace SignOnUi {
+-
+-class UbuntuBrowserRequestPrivate: public QObject
+-{
+-    Q_OBJECT
+-    Q_DECLARE_PUBLIC(UbuntuBrowserRequest)
+-    Q_PROPERTY(QUrl pageComponentUrl READ pageComponentUrl CONSTANT)
+-    Q_PROPERTY(QUrl currentUrl READ currentUrl WRITE setCurrentUrl)
+-    Q_PROPERTY(QUrl startUrl READ startUrl CONSTANT)
+-    Q_PROPERTY(QUrl finalUrl READ finalUrl CONSTANT)
+-
+-public:
+-    UbuntuBrowserRequestPrivate(UbuntuBrowserRequest *request);
+-    ~UbuntuBrowserRequestPrivate();
+-
+-    void start();
+-
+-    void setCurrentUrl(const QUrl &url);
+-    QUrl pageComponentUrl() const;
+-    QUrl currentUrl() const { return m_currentUrl; }
+-    QUrl startUrl() const { return m_startUrl; }
+-    QUrl finalUrl() const { return m_finalUrl; }
+-    QUrl responseUrl() const { return m_responseUrl; }
+-
+-public Q_SLOTS:
+-    void cancel();
+-    void onLoadStarted();
+-    void onLoadFinished(bool ok);
+-
+-private Q_SLOTS:
+-    void onFailTimer();
+-    void onFinished();
+-
+-private:
+-    void buildDialog(const QVariantMap &params);
+-
+-private:
+-    Dialog *m_dialog;
+-    QUrl m_currentUrl;
+-    QUrl m_startUrl;
+-    QUrl m_finalUrl;
+-    QUrl m_responseUrl;
+-    QTimer m_failTimer;
+-    mutable UbuntuBrowserRequest *q_ptr;
+-};
+-
+-} // namespace
+-
+-UbuntuBrowserRequestPrivate::UbuntuBrowserRequestPrivate(
+-    UbuntuBrowserRequest *request):
+-    QObject(request),
+-    m_dialog(0),
+-    q_ptr(request)
+-{
+-    m_failTimer.setSingleShot(true);
+-    m_failTimer.setInterval(3000);
+-    QObject::connect(&m_failTimer, SIGNAL(timeout()),
+-                     this, SLOT(onFailTimer()));
+-}
+-
+-UbuntuBrowserRequestPrivate::~UbuntuBrowserRequestPrivate()
+-{
+-    delete m_dialog;
+-}
+-
+-void UbuntuBrowserRequestPrivate::start()
+-{
+-    Q_Q(UbuntuBrowserRequest);
+-
+-    const QVariantMap &params = q->parameters();
+-    TRACE() << params;
+-
+-    QString cachePath =
+-        QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+-    QDir rootDir = cachePath + QString("/id-%1").arg(q->identity());
+-    if (!rootDir.exists()) {
+-        rootDir.mkpath(".");
+-    }
+-
+-    m_finalUrl = params.value(SSOUI_KEY_FINALURL).toString();
+-    m_startUrl = params.value(SSOUI_KEY_OPENURL).toString();
+-    buildDialog(params);
+-
+-    QObject::connect(m_dialog, SIGNAL(finished(int)),
+-                     this, SLOT(onFinished()));
+-
+-    QUrl webview("qrc:/MainWindow.qml");
+-    QDir qmlDir("/usr/share/signon-ui/qml");
+-    if (qmlDir.exists())
+-    {
+-        QFileInfo qmlFile(qmlDir.absolutePath() + "/MainWindow.qml");
+-        if (qmlFile.exists())
+-            webview.setUrl(qmlFile.absoluteFilePath());
+-    }
+-
+-    m_dialog->rootContext()->setContextProperty("request", this);
+-    m_dialog->rootContext()->setContextProperty("rootDir",
+-                                                QUrl::fromLocalFile(rootDir.absolutePath()));
+-    m_dialog->setSource(webview);
+-}
+-
+-QUrl UbuntuBrowserRequestPrivate::pageComponentUrl() const
+-{
+-    Q_Q(const UbuntuBrowserRequest);
+-    /* We define the X-PageComponent key to let the clients override the QML
+-     * component to be used to build the authentication page.
+-     * To prevent a malicious client to show it's own UI, we require that the
+-     * file path begins with "/usr/share/signon-ui/" (where Ubuntu click
+-     * packages cannot install files).
+-     */
+-    QUrl providedUrl = q->clientData().value("X-PageComponent").toString();
+-    if (providedUrl.isValid() && providedUrl.isLocalFile() &&
+-        providedUrl.path().startsWith("/usr/share/signon-ui/")) {
+-        return providedUrl;
+-    } else {
+-        return QStringLiteral("DefaultPage.qml");
+-    }
+-}
+-
+-void UbuntuBrowserRequestPrivate::setCurrentUrl(const QUrl &url)
+-{
+-    TRACE() << "Url changed:" << url;
+-    m_failTimer.stop();
+-
+-    if (url.host() == m_finalUrl.host() &&
+-        url.path() == m_finalUrl.path()) {
+-        m_responseUrl = url;
+-        if (!m_dialog->isVisible()) {
+-            /* Do not show the notification page. */
+-            m_dialog->accept();
+-        } else {
+-            /* Replace the web page with an information screen */
+-            /* TODO */
+-            m_dialog->accept();
+-        }
+-    }
+-}
+-
+-void UbuntuBrowserRequestPrivate::cancel()
+-{
+-    Q_Q(UbuntuBrowserRequest);
+-
+-    TRACE() << "Client requested to cancel";
+-    q->setCanceled();
+-    if (m_dialog) {
+-        m_dialog->close();
+-    }
+-}
+-
+-void UbuntuBrowserRequestPrivate::onLoadStarted()
+-{
+-    m_failTimer.stop();
+-}
+-
+-void UbuntuBrowserRequestPrivate::onLoadFinished(bool ok)
+-{
+-    Q_Q(const UbuntuBrowserRequest);
+-
+-    TRACE() << "Load finished" << ok;
+-
+-    if (!ok) {
+-        m_failTimer.start();
+-        return;
+-    }
+-
+-    if (!m_dialog->isVisible()) {
+-        if (m_responseUrl.isEmpty()) {
+-            Dialog::ShowMode mode = (q->windowId() == 0) ? Dialog::TopLevel :
+-                q->embeddedUi() ? Dialog::Embedded : Dialog::Transient;
+-            m_dialog->show(q->windowId(), mode);
+-        } else {
+-            onFinished();
+-        }
+-    }
+-}
+-
+-void UbuntuBrowserRequestPrivate::onFailTimer()
+-{
+-    Q_Q(UbuntuBrowserRequest);
+-
+-    TRACE() << "Page loading failed";
+-    if (m_dialog) {
+-        m_dialog->close();
+-    }
+-    q->setResult(QVariantMap());
+-}
+-
+-void UbuntuBrowserRequestPrivate::onFinished()
+-{
+-    Q_Q(UbuntuBrowserRequest);
+-
+-    TRACE() << "Browser dialog closed";
+-    QObject::disconnect(m_dialog, SIGNAL(finished(int)),
+-                        this, SLOT(onFinished()));
+-
+-    QVariantMap reply;
+-    QUrl url = m_responseUrl.isEmpty() ? m_currentUrl : m_responseUrl;
+-    reply[SSOUI_KEY_URLRESPONSE] = url.toString();
+-
+-    m_dialog->close();
+-
+-    q->setResult(reply);
+-}
+-
+-void UbuntuBrowserRequestPrivate::buildDialog(const QVariantMap &params)
+-{
+-    m_dialog = new Dialog;
+-
+-    QString title;
+-    if (params.contains(SSOUI_KEY_TITLE)) {
+-        title = params[SSOUI_KEY_TITLE].toString();
+-    } else if (params.contains(SSOUI_KEY_CAPTION)) {
+-        title = _("Web authentication for %1").
+-            arg(params[SSOUI_KEY_CAPTION].toString());
+-    } else {
+-        title = _("Web authentication");
+-    }
+-
+-    m_dialog->setTitle(title);
+-
+-    TRACE() << "Dialog was built";
+-}
+-
+-UbuntuBrowserRequest::UbuntuBrowserRequest(const QDBusConnection &connection,
+-                                           const QDBusMessage &message,
+-                                           const QVariantMap &parameters,
+-                                           QObject *parent):
+-    Request(connection, message, parameters, parent),
+-    d_ptr(new UbuntuBrowserRequestPrivate(this))
+-{
+-}
+-
+-UbuntuBrowserRequest::~UbuntuBrowserRequest()
+-{
+-}
+-
+-void UbuntuBrowserRequest::start()
+-{
+-    Q_D(UbuntuBrowserRequest);
+-
+-    Request::start();
+-    d->start();
+-}
+-
+-#include "ubuntu-browser-request.moc"
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/ubuntu-browser-request.h" /tmp/src/signon-ui/src/ubuntu-browser-request.h
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/src/ubuntu-browser-request.h"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/src/ubuntu-browser-request.h	1970-01-01 10:00:00.000000000 +1000
+@@ -1,54 +0,0 @@
+-/*
+- * This file is part of signon-ui
+- *
+- * Copyright (C) 2014 Canonical Ltd.
+- *
+- * Contact: Alberto Mardegan <alberto.mardegan at canonical.com>
+- *
+- * This program is free software: you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License version 3, as published
+- * by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranties of
+- * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#ifndef SIGNON_UI_UBUNTU_BROWSER_REQUEST_H
+-#define SIGNON_UI_UBUNTU_BROWSER_REQUEST_H
+-
+-#include "request.h"
+-
+-#include <QObject>
+-
+-namespace SignOnUi {
+-
+-class UbuntuBrowserRequestPrivate;
+-
+-class UbuntuBrowserRequest: public Request
+-{
+-    Q_OBJECT
+-
+-public:
+-    explicit UbuntuBrowserRequest(const QDBusConnection &connection,
+-                                  const QDBusMessage &message,
+-                                  const QVariantMap &parameters,
+-                                  QObject *parent = 0);
+-    ~UbuntuBrowserRequest();
+-
+-    // reimplemented virtual methods
+-    void start();
+-
+-private:
+-    UbuntuBrowserRequestPrivate *d_ptr;
+-    Q_DECLARE_PRIVATE(UbuntuBrowserRequest)
+-};
+-
+-} // namespace
+-
+-#endif // SIGNON_UI_UBUNTU_BROWSER_REQUEST_H
+-
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/tests/unit/.gitignore" /tmp/src/signon-ui/tests/unit/.gitignore
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/tests/unit/.gitignore"	1970-01-01 10:00:00.000000000 +1000
++++ /tmp/src/signon-ui/tests/unit/.gitignore	2023-10-04 11:35:19.905523296 +1000
+@@ -0,0 +1,2 @@
++signon-ui-unittest
++tst_inactivity_timer
+diff -U 3 -H -d -r -N -- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/tests/unit/tst_signon_ui.pro" /tmp/src/signon-ui/tests/unit/tst_signon_ui.pro
+--- "/tmp/src/signon-ui_0.17+18.04.20171027+really20160406.orig (1)/tests/unit/tst_signon_ui.pro"	2016-04-06 19:17:28.000000000 +1000
++++ /tmp/src/signon-ui/tests/unit/tst_signon_ui.pro	2023-10-04 11:35:19.905523296 +1000
+@@ -14,7 +14,8 @@
+     dbus \
+     gui \
+     network \
+-    webkit
++    quick \
++    webengine
+
+ PKGCONFIG += \
+     signon-plugins-common \
+@@ -48,6 +49,7 @@
+     $$TOP_SRC_DIR/src/i18n.cpp \
+     $$TOP_SRC_DIR/src/indicator-service.cpp \
+     $$TOP_SRC_DIR/src/network-access-manager.cpp \
++    $$TOP_SRC_DIR/src/qquick-dialog.cpp \
+     $$TOP_SRC_DIR/src/reauthenticator.cpp \
+     $$TOP_SRC_DIR/src/request.cpp \
+     $$TOP_SRC_DIR/src/webcredentials_adaptor.cpp
+@@ -64,6 +66,7 @@
+     $$TOP_SRC_DIR/src/http-warning.h \
+     $$TOP_SRC_DIR/src/indicator-service.h \
+     $$TOP_SRC_DIR/src/network-access-manager.h \
++    $$TOP_SRC_DIR/src/qquick-dialog.h \
+     $$TOP_SRC_DIR/src/reauthenticator.h \
+     $$TOP_SRC_DIR/src/request.h \
+     $$TOP_SRC_DIR/src/webcredentials_adaptor.h
diff --git a/debian/watch b/debian/watch
index 36553fb..53d2023 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,2 +1,2 @@
 version=4
-http://archive.ubuntu.com/ubuntu/pool/main/s/signon-ui/ signon-ui_(.+).orig.tar.(?:gz|xz|bz2)
+http://archive.ubuntu.com/ubuntu/pool/universe/s/signon-ui/ signon-ui_(.+).orig.tar.(?:gz|xz|bz2)


More information about the Neon-commits mailing list