Compare commits

...
Author SHA1 Message Date
deepend 1ae2d41378 fix menu.c build warnings 2026-10-14 05:32:13 -06:00
deepend-tildeclub 070603b0fe Merge pull request #421 from botovq/push-nsqmxvzmntnz
Fix clang -Wstrict-prototypes warnings
2026-10-13 18:16:48 -07:00
deepend-tildeclub 8f47b5cedf Merge pull request #418 from botovq/push-vzwkspvpmqvu
challengeauth_response (): move digest to stack
2026-10-13 18:13:15 -07:00
Theo Buehler 646ad029f0 Fix clang -Wstrict-prototypes warnings
This trivial diff gets rid of noisy warnings such as
```
./src/common/ignore.c:274:13: warning: a function declaration without a prototype is deprecated in all versions of C [-Wstrict-prototypes]
  274 | ignore_load ()
      |             ^
      |              void
```
when building with modern clang. This is cosmetic since these functions
are actually prototyped in a header, so if the header is in scope it's
not possible to call them with an arbitrary number of arguments.
2026-10-13 09:46:10 +02:00
Theo Buehler d47963247d challengeauth_response (): move digest to stack
Using HMAC ()'s facility of returning the digest in a static array is
not thread safe (this can't be fixed) and it is not portable to the
OpenSSL forks: BoringSSL removed support for this a decade ago (so
aws-lc doesn't support it either) and LibreSSL followed a few years
back.

There is no downside to having a 32-byte array on the stack and it would
make zoitechat safe to use from other forks without the need of patching
it.

Add an error check for the HMAC () call and handle the error in the
caller.
2026-10-13 09:25:22 +02:00
deepend 4f7add046c match theme better 2026-10-12 19:05:31 -06:00
deepend-tildeclub 61ec9af5e3 Merge pull request #420 from ZoiteChat/docs-theme-update
update theme to match new site
2026-10-12 17:11:27 -07:00
deepend 412dc92b10 update theme to match new site 2026-10-12 18:04:49 -06:00
deepend-tildeclub 04dab3dcd6 Merge pull request #412 from TehPeGaSuS/wrap-align-no-indent
Add option to align wrapped lines under the nick or message
2026-10-12 15:28:33 -07:00
ThePeGaSuS c51f885253 add option to align wrapped lines under the nick or message
When nick indentation is off, lines after the first wrap back to the
left edge, under the timestamp. Add a text_wrap_align preference
(start of line, prefix, message) so they can line up under the nick or
the message text instead. It is applied at wrap time, so existing
scrollback is re-wrapped when the setting changes, and the menu is
greyed out while nick indentation is on.
2026-10-12 17:43:09 +02:00
26 changed files with 1572 additions and 2342 deletions
+48 -5
View File
@@ -33,10 +33,53 @@ Example:
that is not visually indented
```
## Read the Docs theme skin
## HTML theme
The HTML output keeps the existing `basicstrap` Sphinx theme, then applies the
ZoiteChat main-site skin from `_static/css/zoitechat-docs.css`.
The `zoitechat` theme inherits Sphinx's built-in `basic` theme. It uses the
same compact layout, blue navigation, and system fonts as zoitechat.org.
Appearance starts in System mode on each page. Light and Dark are available
for the current page; no cookies or browser storage are used.
Brand navigation links are set in `conf.py` through `html_context`, and the
header logo uses `_static/zoitechat-logo.svg`.
The theme's templates are in `_theme/zoitechat/`. Its readable CSS and
JavaScript are in `_static/css/zoitechat-docs.css` and
`_static/js/zoitechat-docs.js`. No minification, JavaScript package manager,
external fonts, or CDN assets are required.
Navigation URLs, including `zoite_atlas_url`, are configured through
`html_context` in `conf.py`. The logo
is `_static/zoitechat-logo.svg`. Standard Sphinx search, indexes, source
links, anchors, translations, and previous/next links remain available.
The HTML output also works as locally installed documentation; project-site
links only access the network when clicked.
Build from the repository root:
```sh
sphinx-build -b html docs docs/_build/html
```
Use a clean output directory when switching themes, so stale Basicstrap
assets from an earlier build are not included in a package.
## Debian packaging
The active theme does not use the bundled Basicstrap, Bootstrap, jQuery,
jQuery Cookie, Font Awesome, or icon fonts. Its font stack includes DejaVu
Sans and DejaVu Sans Mono; no font files are bundled by the theme.
Packagers may exclude `docs/_theme/basicstrap/` from the source package.
The default theme continues to build without that directory. No pre-minified
third-party assets need to be added or rebuilt for this theme.
Build with the distribution's `python3-sphinx`. After installing the HTML
into the package staging directory, use `dh_sphinxdoc` (or `dh --with
sphinxdoc`) to replace Sphinx's standard JavaScript files with system
symlinks. Include `${sphinxdoc:Depends}` in the package dependencies and
`${sphinxdoc:Built-Using}` where required for generated assets. The custom
`zoitechat-docs.js` remains a small, readable project source file.
A built-in theme is still selectable with `-D html_theme=classic` if a
packager needs a different layout. The old RST content has existing build
diagnostics; changing the theme does not suppress or alter them.
Shared website chrome is in `_static/css/zoitechat-site.css`, copied from the main site. Keep that readable stylesheet in sync when changing the shared header, navigation, typography, or colours.
+694 -2281
View File
File diff suppressed because it is too large Load Diff
+526
View File
@@ -0,0 +1,526 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Shared chrome copied from ZoiteChat/site assets/css/site.css (1df996a). */
:root {
color-scheme: light;
--bg: #fff;
--surface: #fff;
--chrome: #f1f2f3;
--chrome2: #e3e5e7;
--text: #25282c;
--muted: #58616b;
--line: #bdc3c9;
--soft-line: #dce0e4;
--blue: #215a9e;
--link: #174f92;
--selection: #e6effa;
--success: #236741;
--code: #f2f4f6;
--shadow: none;
--mono: Consolas,"Liberation Mono",monospace;
}
html[data-theme=dark] {
color-scheme: dark;
--bg: #111416;
--surface: #191c1f;
--chrome: #25292d;
--chrome2: #30353a;
--text: #eef0f2;
--muted: #b2bbc4;
--line: #50575e;
--soft-line: #353c43;
--blue: #2865a8;
--link: #8dc0ff;
--selection: #233951;
--success: #92d5ab;
--code: #111518;
--shadow: none;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
background: var(--bg);
color: var(--text);
font: 15px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif;
}
a {
color: var(--link);
text-underline-offset: 3px;
}
a:hover {
text-decoration: underline;
}
button, input, select {
font: inherit;
}
button, summary {
cursor: pointer;
}
img {
display: block;
max-width: 100%;
height: auto;
}
button, a, input, select, summary {
touch-action: manipulation;
}
:focus-visible {
outline: 3px solid var(--link);
outline-offset: 3px;
}
[hidden] {
display: none!important;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.skip-link {
position: absolute;
left: 12px;
top: -100px;
z-index: 10;
padding: 10px;
background: var(--surface);
}
.skip-link:focus {
top: 12px;
}
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
padding: 0 0 16px;
background: var(--surface);
border-bottom: 1px solid var(--line);
border: 0;
}
.brand {
display: flex;
gap: 12px;
align-items: center;
color: var(--text);
text-decoration: none;
}
.brand img {
width: 38px;
height: 42px;
}
.brand strong {
font-size: 28px;
letter-spacing: -.8px;
font-weight: 650;
}
.brand small {
display: block;
font-size: 12px;
color: var(--muted);
line-height: 1.2;
}
.appearance {
display: flex;
align-items: center;
gap: 10px;
font-size: 11px;
color: var(--muted);
}
select {
border: 1px solid var(--line);
border-radius: 3px;
padding: 5px 8px;
background: var(--surface);
color: var(--text);
}
.navigation {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 12px;
background: var(--chrome);
border-bottom: 1px solid var(--line);
padding: 0;
border: 1px solid var(--line);
border-radius: 0;
}
.nav-links {
display: flex;
align-items: stretch;
flex-wrap: wrap;
gap: 0;
}
.nav-links>a, .nav-menu summary {
display: flex;
align-items: center;
min-height: 36px;
padding: 6px 15px;
color: var(--text);
font-size: 13px;
text-decoration: none;
border-bottom: 0;
}
.nav-links>a[aria-current=page] {
color: #fff;
border-bottom-color: var(--blue);
font-weight: 500;
background: var(--blue);
}
.nav-links>a:hover, .nav-menu summary:hover {
background: var(--selection);
}
.nav-menu {
position: relative;
}
.nav-menu summary {
list-style: none;
}
.nav-menu summary::after {
content: "⌄";
margin-left: 9px;
}
.nav-menu summary::-webkit-details-marker {
display: none;
}
.nav-menu-panel {
position: absolute;
right: 0;
top: 100%;
z-index: 5;
min-width: 280px;
background: var(--surface);
border: 1px solid var(--line);
box-shadow: var(--shadow);
padding: 5px;
}
.nav-menu-panel a {
display: block;
padding: 10px 12px;
text-decoration: none;
}
.nav-menu-panel a:hover {
background: var(--selection);
}
.nav-menu-panel span {
display: block;
font-size: 12px;
color: var(--muted);
}
.site-main {
min-height: 0;
}
h1, h2, h3, p {
margin-top: 0;
}
h1 {
font-size: clamp(30px,3.9vw,46px);
line-height: 1.16;
letter-spacing: -1.5px;
font-weight: 650;
margin-bottom: 20px;
}
h2 {
font-size: 20px;
line-height: 1.3;
letter-spacing: 0;
margin-bottom: 12px;
}
h3 {
font-size: 16px;
line-height: 1.4;
}
p {
color: var(--text);
font-size: 14px;
line-height: 1.7;
margin-bottom: 15px;
}
.site-footer {
padding: 17px 0;
background: var(--surface);
border-top: 1px solid var(--line);
}
.footer-grid {
display: flex;
align-items: start;
justify-content: space-between;
gap: 20px;
}
.footer-copy {
font-size: 11px;
max-width: 62ch;
margin: 0;
color: var(--muted);
}
.footer-links {
display: flex;
flex-wrap: wrap;
gap: 5px 14px;
max-width: 400px;
font-size: 11px;
}
@media (max-width:1000px) {
.navigation {
padding: 0 15px;
}
.nav-links>a, .nav-menu summary {
padding: 8px 10px;
}
}
@media (max-width:650px) {
.topbar {
padding: 13px 16px;
gap: 8px;
}
.brand strong {
font-size: 20px;
}
.brand small {
font-size: 10px;
}
.brand img {
width: 28px;
height: 31px;
}
.appearance {
gap: 5px;
}
.appearance>span {
display: none;
}
.appearance select {
font-size: 12px;
max-width: 98px;
}
.navigation {
padding: 0 6px;
}
.nav-links {
gap: 0;
}
.nav-links>a, .nav-menu summary {
min-height: 44px;
padding: 8px;
font-size: 12px;
}
h1 {
font-size: 34px;
letter-spacing: -1px;
}
.footer-grid {
display: grid;
gap: 20px;
}
.site-footer {
padding: 20px 17px;
}
.nav-menu-panel {
position: fixed;
right: 10px;
left: 10px;
top: auto;
min-width: 0;
}
}
@media (prefers-reduced-motion:reduce) {
* {
scroll-behavior: auto!important;
}
}
.appearance select {
font-size: 12px;
padding: 3px 7px;
}
.nav-links>a:hover {
background: var(--selection);
color: var(--link);
}
h1 {
font-size: 28px;
font-weight: 600;
letter-spacing: -.5px;
line-height: 1.3;
margin: 0 0 16px;
max-width: none;
}
@media (max-width:1100px) {
.navigation {
padding: 0;
}
}
@media (max-width:800px) {
.nav-links>a, .nav-menu summary {
padding: 6px 10px;
}
}
@media (max-width:600px) {
.topbar {
padding: 0 0 14px;
}
.brand strong {
font-size: 25px;
}
.brand img {
width: 32px;
height: 36px;
}
.nav-links>a, .nav-menu summary {
padding: 7px 9px;
min-height: 38px;
font-size: 12px;
}
.footer-grid {
display: block;
}
.footer-links {
margin-top: 10px;
max-width: none;
}
.site-footer {
padding: 14px 0;
}
h1 {
font-size: 26px;
}
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) {
color-scheme: dark;
--bg: #111416;
--surface: #191c1f;
--chrome: #25292d;
--chrome2: #30353a;
--text: #eef0f2;
--muted: #b2bbc4;
--line: #50575e;
--soft-line: #353c43;
--blue: #2865a8;
--link: #8dc0ff;
--selection: #233951;
--success: #92d5ab;
--code: #111518;
--shadow: none;
}
}
.site-header, .site-main, .site-footer {
width: min(1040px, calc(100% - 48px));
margin-inline: auto;
}
.site-header {
margin-top: 32px;
}
.site-main {
padding-block: 28px 20px;
}
.site-header .topbar {
padding: 0 0 16px;
}
.site-header .navigation {
padding: 0;
}
@media (max-width: 600px) {
.site-header, .site-main, .site-footer {
width: calc(100% - 30px);
}
.site-header {
margin-top: 18px;
}
.site-main {
padding-top: 23px;
}
}
/* Match the browser's heading defaults used by the main site. */
h2, h3 { font-weight: bold; }
h2 { margin-top: .83em; }
h3 { margin-block: 1em; }
+44
View File
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
(() => {
'use strict';
const initialise = () => {
const picker = document.getElementById('theme-picker');
const preference = window.matchMedia('(prefers-color-scheme: dark)');
if (picker instanceof HTMLSelectElement) {
const applyTheme = () => {
const dark = picker.value === 'dark'
|| (picker.value === 'system' && preference.matches);
document.documentElement.dataset.theme = dark ? 'dark' : 'light';
document.querySelectorAll('meta[name="theme-color"]').forEach((meta) => {
meta.setAttribute('content', dark ? '#111416' : '#ffffff');
});
};
// Follow the OS on every visit, including browser back/forward navigation.
const resetTheme = () => {
picker.value = 'system';
applyTheme();
};
picker.addEventListener('change', applyTheme);
preference.addEventListener('change', applyTheme);
window.addEventListener('pageshow', resetTheme);
resetTheme();
}
const navigation = document.getElementById('docs-navigation');
const compact = window.matchMedia('(max-width: 760px)');
if (navigation instanceof HTMLDetailsElement) {
const fitNavigation = () => { navigation.open = !compact.matches; };
compact.addEventListener('change', fitNavigation);
fitNavigation();
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialise, { once: true });
} else {
initialise();
}
})();
+5
View File
@@ -0,0 +1,5 @@
{# SPDX-License-Identifier: GPL-2.0-or-later #}
<nav class="global-toc" aria-label="{{ _('Documentation contents') }}">
<h2>{{ _('Contents') }}</h2>
{{ toctree(maxdepth=2, collapse=true, includehidden=true, titles_only=true) }}
</nav>
+108
View File
@@ -0,0 +1,108 @@
{# SPDX-License-Identifier: GPL-2.0-or-later #}
{% extends "basic/layout.html" %}
{% set docs_root = root_doc|default(master_doc) %}
{% block extrahead %}
{{ super() }}
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#111416" media="(prefers-color-scheme: dark)">
{% endblock %}
{% block body_tag %}<body id="top">{% endblock %}
{% block header %}
<a class="skip-link" href="#main-content">{{ _('Skip to content') }}</a>
<header class="site-header">
<div class="topbar">
<a class="brand" href="{{ pathto(docs_root)|e }}">
<img src="{{ logo_url|default(pathto('_static/zoitechat-logo.svg', 1), true)|e }}" alt="" width="38" height="42">
<strong>{{ project|e }}</strong>
</a>
<label class="appearance" for="theme-picker">
<span>{{ _('Appearance') }}</span>
<select id="theme-picker" aria-label="{{ _('Documentation appearance') }}">
<option value="system" selected>{{ _('System') }}</option>
<option value="light">{{ _('Light') }}</option>
<option value="dark">{{ _('Dark') }}</option>
</select>
</label>
</div>
<div class="navigation">
<nav class="nav-links" aria-label="{{ _('Primary') }}">
<a href="{{ zoite_site_url|e }}">{{ _('Home') }}</a>
<a href="{{ zoite_download_url|e }}">{{ _('Downloads') }}</a>
<a href="{{ zoite_addons_url|e }}">{{ _('Addons') }}</a>
<a href="{{ zoite_announcements_url|e }}">{{ _('Announcements') }}</a>
<a href="{{ pathto(docs_root)|e }}" aria-current="page">{{ _('Documentation') }}</a>
<a href="{{ zoite_atlas_url|e }}">{{ _('Atlas') }}</a>
<a href="{{ zoite_github_url|e }}" target="_blank" rel="noopener">{{ _('GitHub') }}</a>
<details class="nav-menu">
<summary>{{ _('IRC support') }}</summary>
<div class="nav-menu-panel" aria-label="{{ _('IRC support channels') }}">
<a href="{{ zoite_irc_url|e }}" target="_blank" rel="noopener"><strong>{{ _('Zoite IRC') }}</strong><span>{{ _('Official support') }} · #zoitechat</span></a>
<a href="{{ libera_irc_url|e }}" target="_blank" rel="noopener"><strong>{{ _('Libera.Chat') }}</strong><span>{{ _('Secondary support') }} · #zoitechat</span></a>
</div>
</details>
</nav>
</div>
</header>
{% endblock %}
{% block relbar1 %}{% endblock %}
{% block relbar2 %}{% endblock %}
{% block content %}
<div class="docs-layout{% if not render_sidebar %} no-sidebar{% endif %}">
{% if render_sidebar %}
<aside class="docs-sidebar" aria-label="{{ _('Documentation navigation') }}">
<details class="docs-navigation" id="docs-navigation" open>
<summary>{{ _('Documentation') }}</summary>
<div class="sidebar-content">
{% for sidebartemplate in sidebars %}
{% include sidebartemplate %}
{% endfor %}
</div>
</details>
</aside>
{% endif %}
<main class="docs-content" id="main-content" tabindex="-1">
<div class="docs-location">
<nav aria-label="{{ _('Breadcrumbs') }}">
<a href="{{ pathto(docs_root)|e }}">{{ _('Documentation') }}</a>
{% for parent in parents %}
<span aria-hidden="true">/</span> <a href="{{ parent.link|e }}">{{ parent.title }}</a>
{% endfor %}
{% if pagename != docs_root %}<span aria-hidden="true">/</span> <span>{{ title|striptags|e }}</span>{% endif %}
</nav>
<span class="docs-version">{{ release|e }}</span>
</div>
{% block body %}{% endblock %}
{% if prev or next %}
<nav class="page-relations" aria-label="{{ _('Related pages') }}">
<div>
{% if prev %}<small>{{ _('Previous') }}</small><a href="{{ prev.link|e }}" rel="prev">{{ prev.title }}</a>{% endif %}
</div>
<div>
{% if next %}<small>{{ _('Next') }}</small><a href="{{ next.link|e }}" rel="next">{{ next.title }}</a>{% endif %}
</div>
</nav>
{% endif %}
</main>
</div>
{% endblock %}
{% block footer %}
<footer class="site-footer">
<div class="footer-grid">
<p class="footer-copy">{{ project|e }} {{ _('documentation') }} · {{ release|e }}</p>
<nav class="footer-links" aria-label="{{ _('Footer navigation') }}">
<a href="{{ pathto(docs_root)|e }}">{{ _('Contents') }}</a>
<a href="{{ zoite_atlas_url|e }}">{{ _('Atlas') }}</a>
{% if hasdoc('search') %}<a href="{{ pathto('search')|e }}">{{ _('Search') }}</a>{% endif %}
{% if hasdoc('genindex') %}<a href="{{ pathto('genindex')|e }}">{{ _('Index') }}</a>{% endif %}
<a href="#top">{{ _('Back to top') }}</a>
</nav>
</div>
</footer>
{% endblock %}
+7
View File
@@ -0,0 +1,7 @@
{# SPDX-License-Identifier: GPL-2.0-or-later #}
{% if display_toc %}
<nav class="local-toc" aria-label="{{ _('On this page') }}">
<h2>{{ _('On this page') }}</h2>
{{ toc }}
</nav>
{% endif %}
+10
View File
@@ -0,0 +1,10 @@
{# SPDX-License-Identifier: GPL-2.0-or-later #}
{% if pagename != "search" %}
<form class="docs-search" action="{{ pathto('search')|e }}" method="get" role="search">
<label for="docs-search-input">{{ _('Search documentation') }}</label>
<div class="search-inputs">
<input id="docs-search-input" type="search" name="q" placeholder="{{ _('Search documentation') }}" autocomplete="off" spellcheck="false">
<button type="submit">{{ _('Search') }}</button>
</div>
</form>
{% endif %}
+7
View File
@@ -0,0 +1,7 @@
[theme]
inherit = basic
stylesheet = basic.css
pygments_style = sphinx
sidebars = searchbox.html, globaltoc.html, localtoc.html, sourcelink.html
[options]
+8 -4
View File
@@ -99,7 +99,7 @@ trim_footnote_reference_space = True
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'basicstrap'
html_theme = 'zoitechat'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -127,13 +127,16 @@ html_context = {
'zoite_site_url': 'https://zoitechat.org/',
'zoite_download_url': 'https://zoitechat.org/download.php',
'zoite_addons_url': 'https://zoitechat.org/addons.php',
'zoite_announcements_url': 'https://zoitechat.org/announcements.php',
'zoite_github_url': 'https://github.com/ZoiteChat/zoitechat',
'zoite_atlas_url': 'https://atlas.zoitechat.org/',
'zoite_irc_url': 'https://zoite.net/webchat/?join=%23zoitechat',
'libera_irc_url': 'https://web.libera.chat/#zoitechat',
}
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = 'zoitechat-logo.svg'
html_logo = '_static/zoitechat-logo.svg'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
@@ -145,8 +148,9 @@ html_favicon = '_static/favicon.ico'
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Main-site visual skin for Read the Docs/Sphinx HTML output.
html_css_files = ['css/zoitechat-docs.css']
# Local, readable assets shared by hosted and offline HTML documentation.
html_css_files = ['css/zoitechat-docs.css', 'css/zoitechat-site.css']
html_js_files = ['js/zoitechat-docs.js']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
+2
View File
@@ -590,6 +590,7 @@ const struct prefs vars[] =
{"gui_gtk3_theme", P_OFFSET (hex_gui_gtk3_theme), TYPE_STR},
{"text_indent", P_OFFINT (hex_text_indent), TYPE_BOOL},
{"text_max_indent", P_OFFINT (hex_text_max_indent), TYPE_INT},
{"text_wrap_align", P_OFFINT (hex_text_wrap_align), TYPE_INT},
{"text_max_lines", P_OFFINT (hex_text_max_lines), TYPE_INT},
{"text_replay", P_OFFINT (hex_text_replay), TYPE_BOOL},
{"text_search_case_match", P_OFFINT (hex_text_search_case_match), TYPE_BOOL},
@@ -881,6 +882,7 @@ load_default_config(void)
prefs.hex_net_reconnect_delay = 10;
prefs.hex_notify_timeout = 15;
prefs.hex_text_max_indent = 256;
prefs.hex_text_wrap_align = 0;
prefs.hex_text_max_lines = 5000;
prefs.hex_url_grabber_limit = 100; /* 0 means unlimited */
+2 -2
View File
@@ -271,7 +271,7 @@ ignore_read_next_entry (char *my_cfg, struct ignore *ignore)
}
void
ignore_load ()
ignore_load (void)
{
struct ignore *ignore;
struct stat st;
@@ -302,7 +302,7 @@ ignore_load ()
}
void
ignore_save ()
ignore_save (void)
{
char buf[1024];
int fh;
+1 -1
View File
@@ -662,7 +662,7 @@ notify_isnotify (struct session *sess, char *name)
}
void
notify_cleanup ()
notify_cleanup (void)
{
GSList *list = notify_list;
GSList *nslist, *srvlist;
+5
View File
@@ -1288,6 +1288,11 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
char *user = net && net->user ? net->user : prefs.hex_irc_user_name;
response = challengeauth_response (user, serv->password, word[5]);
if (response == NULL)
{
PrintTextf (serv->server_session, _("Error building CHALLENGEAUTH for %s"), user);
return;
}
tcp_sendf (serv, "PRIVMSG %s :CHALLENGEAUTH %s %s %s\r\n",
CHALLENGEAUTH_NICK,
+3 -3
View File
@@ -1808,7 +1808,7 @@ pevent_check_all_loaded (void)
}
void
load_text_events ()
load_text_events (void)
{
memset (&pntevts_text, 0, sizeof (char *) * (NUM_XP));
memset (&pntevts, 0, sizeof (char *) * (NUM_XP));
@@ -2488,7 +2488,7 @@ sound_load_event (char *evt, char *file)
}
void
sound_load ()
sound_load (void)
{
int fd;
char buf[512];
@@ -2521,7 +2521,7 @@ sound_load ()
}
void
sound_save ()
sound_save (void)
{
int fd, i;
char buf[512];
+7 -2
View File
@@ -1453,7 +1453,7 @@ challengeauth_response (const char *username, const char *password, const char *
char *passhash;
char *key;
char *keyhash;
unsigned char *digest;
unsigned char digest[SHA256_DIGEST_LENGTH];
GString *buf = g_string_new_len (NULL, SHA256_DIGEST_LENGTH * 2);
user = rfc_strlower (username); /* convert username to lowercase as per the RFC */
@@ -1469,7 +1469,12 @@ challengeauth_response (const char *username, const char *password, const char *
keyhash = str_sha256hash (key);
g_free (key);
digest = HMAC (EVP_sha256 (), keyhash, strlen (keyhash), (unsigned char *) challenge, strlen (challenge), NULL, NULL);
if (HMAC (EVP_sha256 (), keyhash, strlen (keyhash), (unsigned char *) challenge, strlen (challenge), digest, NULL) == NULL)
{
g_free (keyhash);
g_string_free (buf, TRUE);
return NULL;
}
g_free (keyhash);
for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+1
View File
@@ -306,6 +306,7 @@ struct zoitechatprefs
int hex_net_reconnect_delay;
int hex_notify_timeout;
int hex_text_max_indent;
int hex_text_wrap_align;
int hex_text_max_lines;
int hex_url_grabber_limit;
+2 -2
View File
@@ -426,7 +426,7 @@ key_binding_is_builtin (struct key_binding *kb)
}
void
key_init ()
key_init (void)
{
if (key_load_kbs () == 1)
{
@@ -1219,7 +1219,7 @@ key_dialog_load (GtkListStore *store)
}
void
key_dialog_show ()
key_dialog_show (void)
{
GtkWidget *vbox, *box, *pane, *scroll;
GtkWidget *view, *xtext, *delete_button;
+1 -1
View File
@@ -336,7 +336,7 @@ ignore_stats_entry (GtkWidget * box, char *label, int value)
}
void
ignore_gui_open ()
ignore_gui_open (void)
{
GtkWidget *vbox, *box, *stat_box, *frame;
GtkWidget *view;
-34
View File
@@ -297,40 +297,6 @@ mg_color_component_to_pango (double value)
return (guint16)(value * 65535.0 + 0.5);
}
static void
mg_apply_font_css (GtkWidget *widget, const PangoFontDescription *desc,
const char *class_name, const char *provider_key)
{
GtkStyleContext *context;
GtkCssProvider *provider;
GString *css;
if (!widget || !desc)
return;
context = gtk_widget_get_style_context (widget);
if (!context)
return;
provider = g_object_get_data (G_OBJECT (widget), provider_key);
if (!provider)
{
provider = gtk_css_provider_new ();
g_object_set_data_full (G_OBJECT (widget), provider_key, provider, g_object_unref);
}
css = g_string_new (".");
g_string_append (css, class_name);
g_string_append (css, " {");
gtkutil_append_font_css (css, desc);
g_string_append (css, " }");
gtk_css_provider_load_from_data (provider, css->str, -1, NULL);
g_string_free (css, TRUE);
gtk_style_context_add_class (context, class_name);
theme_css_apply_widget_provider (widget, GTK_STYLE_PROVIDER (provider));
}
static void
mg_set_label_alignment_start (GtkWidget *widget)
{
+3
View File
@@ -1962,7 +1962,10 @@ menu_about (GtkWidget *wid, gpointer sess)
gtk_about_dialog_set_logo (dialog, pix_zoitechat);
gtk_about_dialog_set_copyright (dialog, "\302\251 1998-2010 Peter \305\275elezn\303\275\n\302\251 2009-2014 Berke Viktor\n\302\251 2015-2025 Patrick Griffis\n\302\251 2026 deepend");
gtk_about_dialog_set_comments (dialog, comment);
/* Preserve the About dialog's existing action-area button layout. */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
actions = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
G_GNUC_END_IGNORE_DEPRECATIONS
children = gtk_container_get_children (GTK_CONTAINER (actions));
for (child = children; child; child = child->next)
gtk_widget_destroy (GTK_WIDGET (child->data));
+38
View File
@@ -59,6 +59,8 @@ static struct zoitechatprefs setup_prefs;
static GtkWidget *cancel_button;
static GtkWidget *font_dialog = NULL;
static GtkWidget *setup_topicbar_multiline_toggle = NULL;
static GtkWidget *setup_wrap_align_label = NULL;
static GtkWidget *setup_wrap_align_combo = NULL;
enum
{
@@ -157,6 +159,14 @@ static const char *const langsmenu[] =
};
#endif
static const char *const wrapalignmenu[] =
{
N_("Start of line (default)"),
N_("Prefix (nick name)"),
N_("Message"),
NULL
};
static const setting appearance_settings[] =
{
{ST_HEADER, N_("General"),0,0,0},
@@ -172,6 +182,7 @@ static const setting appearance_settings[] =
{ST_TOGGLR, N_("Indent nick names"), P_OFFINTNL(hex_text_indent), N_("Make nick names right-justified"),0,0},
{ST_TOGGLE, N_ ("Show marker line"), P_OFFINTNL (hex_text_show_marker), N_ ("Insert a red line after the last read text."), 0, 0},
{ST_TOGGLE, N_("Keep search position when closing"), P_OFFINTNL(hex_text_search_keep_position), 0, 0, 0},
{ST_MENU, N_("Align wrapped lines under:"), P_OFFINTNL(hex_text_wrap_align), N_("Where wrapped lines start when nick names are not indented"), wrapalignmenu, 0},
{ST_HEADER, N_("Timestamps"),0,0,0},
{ST_TOGGLE, N_("Enable timestamps"), P_OFFINTNL(hex_stamp_text),0,0,1},
@@ -857,6 +868,20 @@ setup_topicbar_inline_toggled_cb (GtkToggleButton *but, gpointer userdata)
!gtk_toggle_button_get_active (but));
}
static void
setup_text_indent_toggled_cb (GtkToggleButton *but, gpointer userdata)
{
gboolean sens = !gtk_toggle_button_get_active (but);
(void) userdata;
/* wrapped line alignment only applies without nick indentation */
if (setup_wrap_align_label)
gtk_widget_set_sensitive (setup_wrap_align_label, sens);
if (setup_wrap_align_combo)
gtk_widget_set_sensitive (setup_wrap_align_combo, sens);
}
static void
setup_create_toggleR (GtkWidget *tab, int row, const setting *set)
{
@@ -867,6 +892,9 @@ setup_create_toggleR (GtkWidget *tab, int row, const setting *set)
setup_get_int (&setup_prefs, set));
g_signal_connect (G_OBJECT (wid), "toggled",
G_CALLBACK (setup_toggle_cb), (gpointer)set);
if (set->offset == STRUCT_OFFSET_INT (struct zoitechatprefs, hex_text_indent))
g_signal_connect (G_OBJECT (wid), "toggled",
G_CALLBACK (setup_text_indent_toggled_cb), NULL);
if (set->tooltip)
gtk_widget_set_tooltip_text (wid, _(set->tooltip));
setup_table_attach (tab, wid, 4, 5, row, row + 1, TRUE, FALSE,
@@ -1279,6 +1307,16 @@ setup_create_menu (GtkWidget *table, int row, const setting *set)
setup_table_attach (table, cbox, 3, 6, row, row + 1, TRUE, FALSE,
SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0);
if (set->offset == STRUCT_OFFSET_INT (struct zoitechatprefs, hex_text_wrap_align))
{
setup_wrap_align_label = wid;
setup_wrap_align_combo = cbox;
g_object_add_weak_pointer (G_OBJECT (wid), (gpointer *)&setup_wrap_align_label);
g_object_add_weak_pointer (G_OBJECT (cbox), (gpointer *)&setup_wrap_align_combo);
gtk_widget_set_sensitive (wid, !setup_prefs.hex_text_indent);
gtk_widget_set_sensitive (cbox, !setup_prefs.hex_text_indent);
}
}
static void
+2 -2
View File
@@ -92,7 +92,7 @@ PrintTextLine (xtext_buffer *xtbuf, unsigned char *text, int len, int indent, ti
memcpy (new_text, stamp, stamp_size);
g_free (stamp);
memcpy (new_text + stamp_size, text, len);
gtk_xtext_append (xtbuf, new_text, len + stamp_size, timet);
gtk_xtext_append_wrap (xtbuf, new_text, len + stamp_size, timet, stamp_size);
g_free (new_text);
} else
gtk_xtext_append (xtbuf, text, len, timet);
@@ -486,7 +486,7 @@ pevent_hlist_treeview_new (GtkWidget *box)
}
void
pevent_dialog_show ()
pevent_dialog_show (void)
{
GtkWidget *vbox, *hbox, *wid, *pane, *preview_pane;
XTextColor xtext_palette[XTEXT_COLS];
+1 -1
View File
@@ -187,7 +187,7 @@ populate_cb (char *urltext, gpointer userdata)
}
void
url_opengui ()
url_opengui (void)
{
GtkWidget *vbox, *hbox, *view;
char buf[128];
+46 -4
View File
@@ -81,6 +81,7 @@ struct textentry
gint16 mark_end;
int indent;
gint16 left_len;
gint16 stamp_len; /* bytes of str taken by the timestamp (no-indent mode) */
GSList *slp;
GArray *sublines; /* byte offsets at the end of each screen row */
int subline_count;
@@ -296,6 +297,7 @@ static void gtk_xtext_get_property (GObject *object, guint prop_id,
static void gtk_xtext_render_ents (GtkXText * xtext, textentry *, textentry *);
static void gtk_xtext_recalc_widths (xtext_buffer *buf, int);
static void gtk_xtext_fix_indent (xtext_buffer *buf);
static int gtk_xtext_text_width (GtkXText *xtext, unsigned char *text, int len);
static int gtk_xtext_find_subline (GtkXText *xtext, textentry *ent, int line);
/* For use by gtk_xtext_strip_color() and its callers -- */
struct offlen_s {
@@ -1322,6 +1324,36 @@ gtk_xtext_selection_clear (xtext_buffer *buf)
return ret;
}
/* x position that the lines after the first of 'ent' start at */
static int
gtk_xtext_cont_indent (xtext_buffer *buf, textentry *ent)
{
int w, off;
if (ent->left_len != -1 || prefs.hex_text_wrap_align < 1)
return buf->indent;
/* 1 = under the prefix (nick), 2 = under the message */
off = ent->stamp_len;
if (prefs.hex_text_wrap_align >= 2)
{
/* the nick (or "*") is the first word after the timestamp */
while (off < ent->str_len && ent->str[off] != ' ')
off++;
while (off < ent->str_len && ent->str[off] == ' ')
off++;
}
if (off <= 0 || off >= ent->str_len)
return buf->indent;
w = ent->indent + gtk_xtext_text_width (buf->xtext, ent->str, off);
/* leave room for the text, or just wrap normally */
if (w > (buf->window_width - MARGIN) / 2)
return buf->indent;
return w;
}
static int
find_x (GtkXText *xtext, textentry *ent, int x, int subline, int indent)
{
@@ -1414,7 +1446,7 @@ gtk_xtext_find_x (GtkXText * xtext, int x, textentry * ent, int subline,
if (subline < 1)
indent = ent->indent;
else
indent = xtext->buffer->indent;
indent = gtk_xtext_cont_indent (xtext->buffer, ent);
if (line > gtk_adjustment_get_page_size (xtext->adj) || line < 0)
{
@@ -4035,7 +4067,7 @@ gtk_xtext_render_line (GtkXText * xtext, textentry * ent, int line,
taken--;
}
indent = xtext->buffer->indent;
indent = gtk_xtext_cont_indent (xtext->buffer, ent);
line++;
taken++;
str += len;
@@ -4296,7 +4328,7 @@ gtk_xtext_lines_taken (xtext_buffer *buf, textentry *ent)
str += len;
end = str - ent->str;
g_array_append_val (ent->sublines, end);
indent = buf->indent;
indent = gtk_xtext_cont_indent (buf, ent);
}
while (str < ent->str + ent->str_len);
}
@@ -5376,6 +5408,7 @@ gtk_xtext_append_indent (xtext_buffer *buf,
prefix_width = gtk_xtext_text_width (buf->xtext, str, left_len + 1);
ent->left_len = left_len;
ent->stamp_len = 0;
ent->str = str;
ent->str_len = left_len + 1 + right_len;
ent->indent = buf->indent - prefix_width;
@@ -5421,6 +5454,14 @@ gtk_xtext_append_indent (xtext_buffer *buf,
void
gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len, time_t stamp)
{
gtk_xtext_append_wrap (buf, text, len, stamp, 0);
}
/* stamp_len: how many bytes at the start of text are the timestamp */
void
gtk_xtext_append_wrap (xtext_buffer *buf, unsigned char *text, int len, time_t stamp, int stamp_len)
{
textentry *ent;
@@ -5438,6 +5479,7 @@ gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len, time_t stamp)
memcpy (ent->str, text, len);
ent->indent = 0;
ent->left_len = -1;
ent->stamp_len = (stamp_len > 0 && stamp_len < ent->str_len) ? stamp_len : 0;
gtk_xtext_append_entry (buf, ent, stamp);
}
@@ -5474,7 +5516,7 @@ gtk_xtext_lastlog (xtext_buffer *out, xtext_buffer *search_area)
}
else
{
gtk_xtext_append (out, ent->str, ent->str_len, 0);
gtk_xtext_append_wrap (out, ent->str, ent->str_len, 0, ent->stamp_len);
}
if (out->text_last)
+1
View File
@@ -281,6 +281,7 @@ struct _GtkXTextClass
GtkWidget *gtk_xtext_new (const XTextColor *palette, int separator);
void gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len, time_t stamp);
void gtk_xtext_append_wrap (xtext_buffer *buf, unsigned char *text, int len, time_t stamp, int stamp_len);
void gtk_xtext_append_indent (xtext_buffer *buf,
unsigned char *left_text, int left_len,
unsigned char *right_text, int right_len,