Compare commits

..
5 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
15 changed files with 26 additions and 1111 deletions
-428
View File
@@ -1,428 +0,0 @@
name: Windows MSI/MSIX Build
on:
push:
branches:
- master
- 'release/**'
pull_request:
branches:
- master
workflow_dispatch:
jobs:
windows_msi_build:
runs-on: windows-2022
permissions:
contents: read
id-token: write
attestations: write
artifact-metadata: write
strategy:
matrix:
platform: [x64]
arch: [x64]
fail-fast: false
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.14.3'
architecture: ${{ matrix.arch }}
- name: Install Dependencies
shell: pwsh
run: |
New-Item -Name "deps" -ItemType "Directory" -Force | Out-Null
python -m pip install --upgrade pip
python -m pip install cffi
python -m pip install zstandard
$ProgressPreference = 'SilentlyContinue'
function Download-WithRetry {
param(
[string]$Url,
[string]$OutFile,
[int]$MaxAttempts = 5,
[int]$InitialDelaySeconds = 2
)
for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {
try {
Invoke-WebRequest -Uri $Url -OutFile $OutFile -ErrorAction Stop
return
}
catch {
if ($attempt -eq $MaxAttempts) {
throw
}
Start-Sleep -Seconds ($InitialDelaySeconds * [math]::Pow(2, $attempt - 1))
}
}
}
# The existing solution includes installer.vcxproj, so Inno Setup is
# still required to build the unmodified solution. This workflow does
# not publish that EXE; it packages the same staged rel tree as MSI/MSIX.
Download-WithRetry -Url https://github.com/jrsoftware/issrc/releases/download/is-6_7_1/innosetup-6.7.1.exe -OutFile deps\innosetup-unicode.exe
& deps\innosetup-unicode.exe /VERYSILENT | Out-Null
# Use the same GTK runtime as the existing Windows EXE workflow.
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.20.0-alpha.1/GTK3_Gvsbuild_zoitechat-2.20.0-alpha.1_x64.zip -OutFile deps\gtk-${{ matrix.arch }}.zip
Expand-Archive -LiteralPath deps\gtk-${{ matrix.arch }}.zip -DestinationPath C:\gtk-build\gtk\x64\release -Force
# The GTK3 bundle does not contain librsvg. Restore the renderer,
# pixbuf loader, and license from the matching GTK4 bundle. Do not
# replace the rest of the GTK3 runtime with GTK4 libraries.
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.20.0-alpha.1/GTK4_Gvsbuild_zoitechat-2.20.0-alpha.1_x64.zip -OutFile deps\svg-runtime.zip
if ((Get-FileHash deps\svg-runtime.zip -Algorithm SHA256).Hash -ne 'fb657f9ebae3a6807defb15e66091d643a703ee66cb37488e3e11e5646f45adb') {
throw 'Unexpected SVG runtime archive checksum'
}
$svgArchive = [System.IO.Compression.ZipFile]::OpenRead((Resolve-Path deps\svg-runtime.zip))
try {
foreach ($name in @('bin/rsvg-2-2.dll', 'lib/gdk-pixbuf-2.0/2.10.0/loaders/pixbufloader_svg.dll', 'share/doc/librsvg/COPYING.LIB')) {
$entry = $svgArchive.GetEntry($name)
if ($null -eq $entry) { throw "Missing SVG runtime file: $name" }
$destination = Join-Path 'C:\gtk-build\gtk\x64\release' $name
New-Item -ItemType Directory -Path (Split-Path $destination) -Force | Out-Null
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $destination, $true)
}
}
finally { $svgArchive.Dispose() }
# Ensure SVG remains loadable before compiling or packaging.
& C:\gtk-build\gtk\x64\release\bin\gdk-pixbuf-query-loaders.exe --update-cache
if ($LASTEXITCODE -ne 0) { throw 'Could not generate the pixbuf loader cache' }
if (-not (Select-String -LiteralPath 'C:\gtk-build\gtk\x64\release\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache' -SimpleMatch '"svg"')) {
throw 'SVG loader could not be loaded with the GTK3 runtime'
}
Download-WithRetry -Url https://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-hicolor-icon-theme-0.18-1-any.pkg.tar.zst -OutFile deps\hicolor-icon-theme.pkg.tar.zst
python -c "import tarfile,zstandard,pathlib;archive=pathlib.Path(r'deps\\hicolor-icon-theme.pkg.tar.zst');target=pathlib.Path(r'C:\\gtk-build\\gtk\\x64\\release');dctx=zstandard.ZstdDecompressor();f=archive.open('rb');reader=dctx.stream_reader(f);tf=tarfile.open(fileobj=reader,mode='r|');[tf.extract(m,path=target) for m in tf if m.name.startswith('mingw64/share/icons/hicolor/')];tf.close();reader.close();f.close()"
Download-WithRetry -Url https://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-libarchive-3.8.6-1-any.pkg.tar.zst -OutFile deps\libarchive.pkg.tar.zst
python -c "import tarfile,zstandard,pathlib;archive=pathlib.Path(r'deps\\libarchive.pkg.tar.zst');target=pathlib.Path(r'C:\\gtk-build\\gtk\\x64\\release');dctx=zstandard.ZstdDecompressor();f=archive.open('rb');reader=dctx.stream_reader(f);tf=tarfile.open(fileobj=reader,mode='r|');[tf.extract(m,path=target) for m in tf if m.name.startswith(('mingw64/include/archive','mingw64/lib/libarchive','mingw64/bin/libarchive'))];tf.close();reader.close();f.close()"
if (Test-Path C:\gtk-build\gtk\x64\release\mingw64\share\icons\hicolor) {
New-Item -Path C:\gtk-build\gtk\x64\release\share\icons -ItemType Directory -Force | Out-Null
Copy-Item -Path C:\gtk-build\gtk\x64\release\mingw64\share\icons\hicolor -Destination C:\gtk-build\gtk\x64\release\share\icons\hicolor -Recurse -Force
}
if (Test-Path C:\gtk-build\gtk\x64\release\mingw64\include) {
New-Item -Path C:\gtk-build\gtk\x64\release\include -ItemType Directory -Force | Out-Null
Copy-Item -Path C:\gtk-build\gtk\x64\release\mingw64\include\archive* -Destination C:\gtk-build\gtk\x64\release\include -Recurse -Force
}
if (Test-Path C:\gtk-build\gtk\x64\release\mingw64\lib) {
New-Item -Path C:\gtk-build\gtk\x64\release\lib -ItemType Directory -Force | Out-Null
Copy-Item -Path C:\gtk-build\gtk\x64\release\mingw64\lib\libarchive* -Destination C:\gtk-build\gtk\x64\release\lib -Force
}
if (Test-Path C:\gtk-build\gtk\x64\release\mingw64\bin) {
New-Item -Path C:\gtk-build\gtk\x64\release\bin -ItemType Directory -Force | Out-Null
Copy-Item -Path C:\gtk-build\gtk\x64\release\mingw64\bin\libarchive*.dll -Destination C:\gtk-build\gtk\x64\release\bin -Force
}
if (Test-Path C:\gtk-build\gtk\x64\release\mingw64) {
Remove-Item -Path C:\gtk-build\gtk\x64\release\mingw64 -Recurse -Force
}
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.18.0-pre4/gendef20260315.7z -OutFile deps\gendef.7z
& 7z.exe x deps\gendef.7z -oC:\gtk-build
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.18.0-pre4/WinSparkle-20260315.7z -OutFile deps\WinSparkle.7z
& 7z.exe x deps\WinSparkle.7z -oC:\gtk-build\WinSparkle
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.18.0-pre4/perl-5.42.0.1-${{ matrix.arch }}.7z -OutFile deps\perl-${{ matrix.arch }}.7z
& 7z.exe x deps\perl-${{ matrix.arch }}.7z -oC:\gtk-build\perl-5.42.0.1\${{ matrix.platform }}
$pyRoot = $env:pythonLocation
if (-not $pyRoot) { $pyRoot = & python -c "import sys; print(sys.prefix)" }
foreach ($pyDir in @("C:\gtk-build\python-3.14.3", "C:\gtk-build\python-3.14")) {
New-Item -Path $pyDir -ItemType Directory -Force | Out-Null
$target = Join-Path $pyDir "${{ matrix.platform }}"
if (Test-Path $target) { Remove-Item $target -Recurse -Force }
New-Item -Path $pyDir -Name "${{ matrix.platform }}" -ItemType Junction -Value $pyRoot | Out-Null
}
- uses: actions/setup-python@v6
with:
python-version: '3.8.10'
architecture: ${{ matrix.arch }}
- name: Prepare Python 3.8
shell: pwsh
run: |
python -m pip install --upgrade pip
python -m pip install cffi
$pyRoot = $env:pythonLocation
if (-not $pyRoot) { $pyRoot = & python -c "import sys; print(sys.prefix)" }
foreach ($pyDir in @("C:\gtk-build\python-3.8.10", "C:\gtk-build\python-3.8")) {
New-Item -Path $pyDir -ItemType Directory -Force | Out-Null
$target = Join-Path $pyDir "${{ matrix.platform }}"
if (Test-Path $target) { Remove-Item $target -Recurse -Force }
New-Item -Path $pyDir -Name "${{ matrix.platform }}" -ItemType Junction -Value $pyRoot | Out-Null
}
- name: Build
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat"
set "PYTHON_DIR=C:\gtk-build\python-3.14.3\${{ matrix.platform }}"
if not exist "%PYTHON_DIR%\libs\python314.lib" (
echo Missing %PYTHON_DIR%\libs\python314.lib
dir "%PYTHON_DIR%\libs"
exit /b 1
)
set "PYTHON38_DIR=C:\gtk-build\python-3.8\${{ matrix.platform }}"
if not exist "%PYTHON38_DIR%\libs\python38.lib" (
echo Missing %PYTHON38_DIR%\libs\python38.lib
dir "%PYTHON38_DIR%\libs"
exit /b 1
)
if not exist "%PYTHON38_DIR%\Lib\site-packages\_cffi_backend.cp38*.pyd" (
echo Missing %PYTHON38_DIR%\Lib\site-packages\_cffi_backend.cp38*.pyd
exit /b 1
)
set "LIB=%PYTHON_DIR%\libs;%LIB%"
set "INCLUDE=%PYTHON_DIR%\include;%INCLUDE%"
powershell -NoProfile -ExecutionPolicy Bypass -Command "$archiveLib='C:\gtk-build\gtk\x64\release\lib\libarchive.lib'; if (-not (Test-Path $archiveLib)) { $archiveDll = Get-ChildItem 'C:\gtk-build\gtk\x64\release\bin\libarchive*.dll' | Select-Object -First 1; if ($archiveDll) { Push-Location 'C:\gtk-build\gtk\x64\release\lib'; & 'C:\gtk-build\gendef\gendef.exe' $archiveDll.FullName | Out-Null; $archiveDef = Get-ChildItem 'libarchive*.def' | Select-Object -First 1; if ($archiveDef) { & lib /def:$archiveDef.Name /machine:${{ matrix.platform }} /out:libarchive.lib | Out-Null }; Pop-Location } }"
msbuild win32\zoitechat.sln /m /verbosity:minimal /p:Configuration=Release /p:Platform=${{ matrix.platform }}
if errorlevel 1 exit /b 1
if not exist "..\zoitechat-build\${{ matrix.platform }}\rel\plugins\hcpython38.dll" (
echo hcpython38.dll was not built
exit /b 1
)
if not exist "..\zoitechat-build\${{ matrix.platform }}\rel\_cffi_backend.cp38*.pyd" (
echo _cffi_backend for Python 3.8 was not staged for the installer
exit /b 1
)
# Master added native emoji font staging and tests after the release
# branch split. Run these before packaging so MSI/MSIX use verified files.
- name: Test emoji catalog, font coverage and picker
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat"
set "PATH=%CD%\..\zoitechat-build\x64\rel;%PATH%"
set "GDK_PIXBUF_MODULE_FILE=%CD%\..\zoitechat-build\x64\rel\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache"
set "ZOITECHAT_EMOJI_FONT=%CD%\..\zoitechat-build\x64\rel\share\fonts\zoitechat\NotoColorEmoji.ttf"
fc /b data\fonts\NotoColorEmoji.ttf "%ZOITECHAT_EMOJI_FONT%"
if errorlevel 1 exit /b 1
for %%T in (data font ui) do (
msbuild win32\emoji-tests.vcxproj /m /verbosity:minimal /p:Configuration=Release /p:Platform=x64 /p:EmojiTestKind=%%T
if errorlevel 1 exit /b 1
..\zoitechat-build\x64\tests\emoji-%%T-tests.exe --tap
if errorlevel 1 exit /b 1
)
- name: Install WiX Toolset
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
# Keep this pinned. WiX v6 introduced OSMF terms and WiX v7 adds
# explicit EULA acceptance; do not silently accept new terms in CI.
dotnet tool install --tool-path .wix wix --version 5.0.2
if ($LASTEXITCODE -ne 0) { throw 'Failed to install WiX Toolset 5.0.2' }
& .\.wix\wix.exe --version
if ($LASTEXITCODE -ne 0) { throw 'WiX Toolset could not be executed' }
- name: Build MSI
id: build_msi
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$rawVersion = (Get-Content VERSION -Raw).Trim()
if ($rawVersion -notmatch '^(\d+)\.(\d+)\.(\d+)') {
throw "VERSION '$rawVersion' does not begin with an MSI-compatible major.minor.patch version"
}
# Keep the full development version in the filename, while MSI's
# ProductVersion is numeric (e.g. 2.20.0-dev -> 2.20.0).
$msiVersion = "$($Matches[1]).$($Matches[2]).$($Matches[3])"
$safeVersion = $rawVersion -replace '[^0-9A-Za-z._-]', '-'
$sourceDir = (Resolve-Path "..\zoitechat-build\${{ matrix.platform }}\rel").Path
$outputPath = Join-Path $PWD "ZoiteChat-${safeVersion}_${{ matrix.arch }}.msi"
if (-not (Test-Path (Join-Path $sourceDir 'zoitechat.exe'))) {
throw "Staged ZoiteChat executable is missing from $sourceDir"
}
& .\.wix\wix.exe build win32\wix\zoitechat.wxs `
-arch x64 `
-d "SourceDir=$sourceDir" `
-d "ProductVersion=$msiVersion" `
-out $outputPath
if ($LASTEXITCODE -ne 0) { throw 'WiX MSI build failed' }
if (-not (Test-Path $outputPath)) {
throw "Expected MSI was not created: $outputPath"
}
"path=$outputPath" >> $env:GITHUB_OUTPUT
"filename=$(Split-Path $outputPath -Leaf)" >> $env:GITHUB_OUTPUT
- name: Test MSI administrative extraction
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$msi = '${{ steps.build_msi.outputs.path }}'
$adminImage = Join-Path $PWD 'msi-admin-image'
New-Item -ItemType Directory -Path $adminImage -Force | Out-Null
$arguments = "/a `"$msi`" /qn TARGETDIR=`"$adminImage`""
$process = Start-Process -FilePath msiexec.exe -ArgumentList $arguments -Wait -PassThru
if ($process.ExitCode -ne 0) {
throw "MSI administrative extraction failed with exit code $($process.ExitCode)"
}
foreach ($requiredFile in @(
'zoitechat.exe',
'hclua.dll',
'hcupd.dll',
'WinSparkle.dll',
'hcchecksum.dll',
'hcexec.dll',
'hcfishlim.dll',
'hcsysinfo.dll',
'system.png',
'hcperl.dll',
'hcpython3.dll',
'hcpython38.dll',
'NotoColorEmoji.ttf',
'OFL.txt'
)) {
$match = Get-ChildItem -Path $adminImage -Filter $requiredFile -File -Recurse | Select-Object -First 1
if ($null -eq $match) {
throw "Administrative image does not contain required normal-install file: $requiredFile"
}
}
foreach ($requiredPattern in @('_cffi_backend.cp314*.pyd', '_cffi_backend.cp38*.pyd')) {
$match = Get-ChildItem -Path $adminImage -Filter $requiredPattern -File -Recurse | Select-Object -First 1
if ($null -eq $match) {
throw "Administrative image does not contain required Python support file: $requiredPattern"
}
}
foreach ($requiredPythonFile in @('zoitechat.py', '_zoitechat.py', 'hexchat.py', 'xchat.py')) {
$match = Get-ChildItem -Path $adminImage -Filter $requiredPythonFile -File -Recurse |
Where-Object { $_.Directory.Name -eq 'python' } |
Select-Object -First 1
if ($null -eq $match) {
throw "Administrative image does not contain required Python bridge file: $requiredPythonFile"
}
}
foreach ($excludedFile in @(
'portable-mode',
'zoitechat-text.exe'
)) {
$match = Get-ChildItem -Path $adminImage -Filter $excludedFile -File -Recurse | Select-Object -First 1
if ($null -ne $match) {
throw "MSI incorrectly contains Inno custom/portable-only file: $excludedFile"
}
}
- name: Build MSIX
id: build_msix
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$rawVersion = (Get-Content VERSION -Raw).Trim()
if ($rawVersion -notmatch '^(\d+)\.(\d+)\.(\d+)') {
throw "VERSION '$rawVersion' does not begin with a Store-compatible major.minor.build version"
}
$versionParts = @(
[int]$Matches[1],
[int]$Matches[2],
[int]$Matches[3]
)
if ($versionParts[0] -eq 0) {
throw 'The Microsoft Store requires a non-zero major package version.'
}
foreach ($part in $versionParts) {
if ($part -lt 0 -or $part -gt 65535) {
throw "MSIX version component '$part' is outside the Store-supported 0-65535 range."
}
}
# Partner Center reserves the fourth field as 0. A -dev version
# is packaged as a valid 2.20.0.0, without changing VERSION.
$packageVersion = "$($versionParts[0]).$($versionParts[1]).$($versionParts[2]).0"
$safeVersion = $rawVersion -replace '[^0-9A-Za-z._-]', '-'
$sourceDir = (Resolve-Path "..\zoitechat-build\${{ matrix.platform }}\rel").Path
$outputPath = Join-Path $PWD "ZoiteChat-${safeVersion}_${{ matrix.arch }}.msix"
# Reserved ZoiteChat identity from the release branch. Adjust only
# if the Product identity page in Partner Center changes.
$identityName = 'deependtilde.ZoiteChat'
$publisher = 'CN=6C7766BB-6AC6-488B-A09E-E3F8E68E63E4'
$publisherDisplayName = 'deepend_tilde'
$artifactName = 'MSIX Store Package ${{ matrix.arch }}'
Write-Host "Building Store MSIX for identity: $identityName"
& .\win32\msix\build-msix.ps1 `
-SourceDir $sourceDir `
-OutputPath $outputPath `
-PackageVersion $packageVersion `
-IdentityName $identityName `
-Publisher $publisher `
-PublisherDisplayName $publisherDisplayName `
-SelfSign
if ($LASTEXITCODE -ne 0) {
throw 'MSIX build script failed'
}
if (-not (Test-Path $outputPath)) {
throw "Expected MSIX was not created: $outputPath"
}
"path=$outputPath" >> $env:GITHUB_OUTPUT
"filename=$(Split-Path $outputPath -Leaf)" >> $env:GITHUB_OUTPUT
"package_version=$packageVersion" >> $env:GITHUB_OUTPUT
"store_ready=true" >> $env:GITHUB_OUTPUT
"artifact_name=$artifactName" >> $env:GITHUB_OUTPUT
- name: Upload MSI Installer
id: upload_msi
uses: actions/upload-artifact@v6
with:
name: MSI Installer ${{ matrix.arch }}
path: ${{ steps.build_msi.outputs.path }}
if-no-files-found: error
- name: Attest MSI Installer (Artifact Attestation)
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
uses: actions/attest-build-provenance@v3
with:
subject-name: MSI Installer ${{ matrix.arch }}
subject-digest: sha256:${{ steps.upload_msi.outputs.artifact-digest }}
- name: Upload MSIX Package
id: upload_msix
uses: actions/upload-artifact@v6
with:
name: ${{ steps.build_msix.outputs.artifact_name }}
path: ${{ steps.build_msix.outputs.path }}
if-no-files-found: error
- name: Attest MSIX Package (Artifact Attestation)
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
uses: actions/attest-build-provenance@v3
with:
subject-name: ${{ steps.build_msix.outputs.artifact_name }}
subject-digest: sha256:${{ steps.upload_msix.outputs.artifact-digest }}
+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++)
+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));
+1 -1
View File
@@ -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];
-82
View File
@@ -1,82 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap uap3 uap10 rescap">
<!--
Identity values are filled by build-msix.ps1. For Microsoft Store
submissions they must exactly match Product management > Product identity
in Partner Center.
-->
<Identity
Name="@IDENTITY_NAME@"
Publisher="@PUBLISHER@"
Version="@PACKAGE_VERSION@"
ProcessorArchitecture="x64" />
<Properties>
<DisplayName>ZoiteChat</DisplayName>
<PublisherDisplayName>@PUBLISHER_DISPLAY_NAME@</PublisherDisplayName>
<Description>ZoiteChat IRC client</Description>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Resources>
<Resource Language="en-us" />
</Resources>
<Dependencies>
<TargetDeviceFamily
Name="Windows.Desktop"
MinVersion="10.0.19041.0"
MaxVersionTested="10.0.26100.0" />
<PackageDependency
Name="Microsoft.VCLibs.140.00.UWPDesktop"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
MinVersion="14.0.30704.0" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
<Applications>
<Application
Id="ZoiteChat"
Executable="ZoiteChat\zoitechat.exe"
uap10:RuntimeBehavior="packagedClassicApp"
uap10:TrustLevel="mediumIL">
<uap:VisualElements
DisplayName="ZoiteChat"
Description="ZoiteChat IRC client"
BackgroundColor="transparent"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png" />
<Extensions>
<uap3:Extension Category="windows.protocol">
<uap3:Protocol
Name="irc"
Parameters="--url=&quot;%1&quot;" />
</uap3:Extension>
<uap3:Extension Category="windows.fileTypeAssociation">
<uap3:FileTypeAssociation
Name="zoitechattheme"
Parameters="&quot;%1&quot;">
<uap:DisplayName>ZoiteChat Theme</uap:DisplayName>
<uap:SupportedFileTypes>
<uap:FileType>.zct</uap:FileType>
<uap:FileType>.hct</uap:FileType>
</uap:SupportedFileTypes>
</uap3:FileTypeAssociation>
</uap3:Extension>
</Extensions>
</Application>
</Applications>
</Package>
-392
View File
@@ -1,392 +0,0 @@
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string] $SourceDir,
[Parameter(Mandatory = $true)]
[string] $OutputPath,
[Parameter(Mandatory = $true)]
[ValidatePattern('^\d+\.\d+\.\d+\.0$')]
[string] $PackageVersion,
[Parameter(Mandatory = $true)]
[string] $IdentityName,
[Parameter(Mandatory = $true)]
[string] $Publisher,
[Parameter(Mandatory = $true)]
[string] $PublisherDisplayName,
[switch] $SelfSign
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Drawing
function Find-WindowsSdkTool {
param(
[Parameter(Mandatory = $true)]
[string] $ToolName
)
$command = Get-Command $ToolName -ErrorAction SilentlyContinue
if ($command) {
return $command.Source
}
$kitsRoot = Join-Path ${env:ProgramFiles(x86)} 'Windows Kits\10\bin'
if (-not (Test-Path $kitsRoot)) {
throw "Windows SDK bin directory was not found: $kitsRoot"
}
$tool = Get-ChildItem -Path $kitsRoot -Filter $ToolName -File -Recurse |
Where-Object { $_.FullName -match '\\x64\\' } |
Sort-Object {
$versionDirectory = Split-Path (Split-Path $_.DirectoryName -Parent) -Leaf
try {
[version] $versionDirectory
}
catch {
[version] '0.0'
}
} -Descending |
Select-Object -First 1
if (-not $tool) {
throw "$ToolName was not found in the installed Windows SDK."
}
return $tool.FullName
}
function Escape-Xml {
param(
[Parameter(Mandatory = $true)]
[string] $Value
)
return [System.Security.SecurityElement]::Escape($Value)
}
function New-MsixAsset {
param(
[Parameter(Mandatory = $true)]
[System.Drawing.Image] $SourceImage,
[Parameter(Mandatory = $true)]
[int] $Width,
[Parameter(Mandatory = $true)]
[int] $Height,
[Parameter(Mandatory = $true)]
[string] $Path
)
$bitmap = [System.Drawing.Bitmap]::new($Width, $Height)
try {
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
try {
$graphics.Clear([System.Drawing.Color]::Transparent)
$graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
$graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
$graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
$scale = [Math]::Min($Width / $SourceImage.Width, $Height / $SourceImage.Height)
$drawWidth = [Math]::Max(1, [int][Math]::Round($SourceImage.Width * $scale))
$drawHeight = [Math]::Max(1, [int][Math]::Round($SourceImage.Height * $scale))
$x = [int](($Width - $drawWidth) / 2)
$y = [int](($Height - $drawHeight) / 2)
$graphics.DrawImage($SourceImage, $x, $y, $drawWidth, $drawHeight)
}
finally {
$graphics.Dispose()
}
$bitmap.Save($Path, [System.Drawing.Imaging.ImageFormat]::Png)
}
finally {
$bitmap.Dispose()
}
}
$source = (Resolve-Path $SourceDir).Path
if (-not (Test-Path (Join-Path $source 'zoitechat.exe'))) {
throw "Staged ZoiteChat executable is missing from $source"
}
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
$templatePath = Join-Path $PSScriptRoot 'AppxManifest.xml.in'
$iconPath = Join-Path $repoRoot 'data\icons\zoitechat.png'
if (-not (Test-Path $templatePath)) {
throw "MSIX manifest template is missing: $templatePath"
}
if (-not (Test-Path $iconPath)) {
throw "ZoiteChat PNG icon is missing: $iconPath"
}
if ([System.IO.Path]::IsPathRooted($OutputPath)) {
$output = [System.IO.Path]::GetFullPath($OutputPath)
}
else {
$output = [System.IO.Path]::GetFullPath((Join-Path $PWD $OutputPath))
}
$outputDirectory = Split-Path $output -Parent
New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null
$stagingRoot = Join-Path $env:RUNNER_TEMP 'zoitechat-msix'
$verifyRoot = Join-Path $env:RUNNER_TEMP 'zoitechat-msix-verify'
$pfxPath = Join-Path $env:RUNNER_TEMP 'zoitechat-msix-dev.pfx'
foreach ($path in @($stagingRoot, $verifyRoot)) {
if (Test-Path $path) {
Remove-Item -Path $path -Recurse -Force
}
}
if (Test-Path $pfxPath) {
Remove-Item -Path $pfxPath -Force
}
New-Item -ItemType Directory -Path $stagingRoot -Force | Out-Null
$appRoot = Join-Path $stagingRoot 'ZoiteChat'
New-Item -ItemType Directory -Path $appRoot -Force | Out-Null
Copy-Item -Path (Join-Path $source '*') -Destination $appRoot -Recurse -Force
# copy.vcxproj stages everything needed by every Inno component. The Store
# package keeps the useful bundled plugins and scripting bridges while letting
# the Microsoft Store own application updates. The WinSparkle updater is the
# only bundled plugin deliberately removed from the Store package.
$excludeFiles = @(
'portable-mode',
'zoitechat-text.exe',
'plugins\hcupd.dll',
'WinSparkle.dll',
'share\download.png'
)
foreach ($relativePath in $excludeFiles) {
$path = Join-Path $appRoot $relativePath
if (Test-Path $path) {
Remove-Item -Path $path -Force
}
}
foreach ($relativePath in @('share\doc\WinSparkle')) {
$path = Join-Path $appRoot $relativePath
if (Test-Path $path) {
Remove-Item -Path $path -Recurse -Force
}
}
foreach ($requiredPath in @(
'zoitechat.exe',
'plugins\hcnotifications-winrt.dll',
'plugins\hcchecksum.dll',
'plugins\hcexec.dll',
'plugins\hcfishlim.dll',
'plugins\hcsysinfo.dll',
'share\system.png',
'share\fonts\zoitechat\NotoColorEmoji.ttf',
'share\doc\zoitechat\fonts\OFL.txt',
'plugins\hclua.dll',
'plugins\hcperl.dll',
'plugins\hcpython3.dll',
'plugins\hcpython38.dll'
)) {
if (-not (Test-Path (Join-Path $appRoot $requiredPath))) {
throw "MSIX staging is missing required file: $requiredPath"
}
}
foreach ($requiredPattern in @('_cffi_backend.cp314*.pyd', '_cffi_backend.cp38*.pyd')) {
$match = Get-ChildItem -Path $appRoot -Filter $requiredPattern -File -ErrorAction SilentlyContinue |
Select-Object -First 1
if ($null -eq $match) {
throw "MSIX staging is missing required Python support file: $requiredPattern"
}
}
foreach ($requiredPythonFile in @('zoitechat.py', '_zoitechat.py', 'hexchat.py', 'xchat.py')) {
$path = Join-Path (Join-Path $appRoot 'python') $requiredPythonFile
if (-not (Test-Path $path)) {
throw "MSIX staging is missing required Python bridge file: $requiredPythonFile"
}
}
$assets = Join-Path $stagingRoot 'Assets'
New-Item -ItemType Directory -Path $assets -Force | Out-Null
$image = [System.Drawing.Image]::FromFile($iconPath)
try {
New-MsixAsset -SourceImage $image -Width 50 -Height 50 `
-Path (Join-Path $assets 'StoreLogo.png')
New-MsixAsset -SourceImage $image -Width 44 -Height 44 `
-Path (Join-Path $assets 'Square44x44Logo.png')
New-MsixAsset -SourceImage $image -Width 150 -Height 150 `
-Path (Join-Path $assets 'Square150x150Logo.png')
}
finally {
$image.Dispose()
}
$manifest = Get-Content $templatePath -Raw -Encoding UTF8
$manifest = $manifest.Replace('@IDENTITY_NAME@', (Escape-Xml $IdentityName))
$manifest = $manifest.Replace('@PUBLISHER@', (Escape-Xml $Publisher))
$manifest = $manifest.Replace('@PUBLISHER_DISPLAY_NAME@', (Escape-Xml $PublisherDisplayName))
$manifest = $manifest.Replace('@PACKAGE_VERSION@', (Escape-Xml $PackageVersion))
if ($manifest -match '@[A-Z0-9_]+@') {
throw "Unexpanded MSIX manifest placeholder: $($Matches[0])"
}
$manifestPath = Join-Path $stagingRoot 'AppxManifest.xml'
[System.IO.File]::WriteAllText(
$manifestPath,
$manifest,
[System.Text.UTF8Encoding]::new($false)
)
# Catch malformed XML before MakeAppx so CI reports a useful error.
[xml](Get-Content $manifestPath -Raw -Encoding UTF8) | Out-Null
$makeAppx = Find-WindowsSdkTool -ToolName 'MakeAppx.exe'
$signtool = Find-WindowsSdkTool -ToolName 'SignTool.exe'
if (Test-Path $output) {
Remove-Item -Path $output -Force
}
& $makeAppx pack /d $stagingRoot /p $output /o
if ($LASTEXITCODE -ne 0) {
throw "MakeAppx failed with exit code $LASTEXITCODE"
}
$certificate = $null
try {
if ($SelfSign) {
# Partner Center replaces this development signature with Microsoft's
# trusted Store signature. The certificate subject must exactly match
# the manifest Publisher for SignTool to accept the package.
$certificate = New-SelfSignedCertificate `
-Type Custom `
-KeyUsage DigitalSignature `
-Subject $Publisher `
-CertStoreLocation 'Cert:\CurrentUser\My' `
-HashAlgorithm SHA256 `
-TextExtension @(
'2.5.29.37={text}1.3.6.1.5.5.7.3.3',
'2.5.29.19={text}'
) `
-FriendlyName 'ZoiteChat MSIX CI signing certificate'
if ($certificate.Subject -cne $Publisher) {
throw "Generated certificate subject '$($certificate.Subject)' does not exactly match manifest Publisher '$Publisher'."
}
$passwordText = [Guid]::NewGuid().ToString('N')
$password = ConvertTo-SecureString -String $passwordText -AsPlainText -Force
Export-PfxCertificate -Cert $certificate -FilePath $pfxPath -Password $password | Out-Null
& $signtool sign /fd SHA256 /f $pfxPath /p $passwordText $output
if ($LASTEXITCODE -ne 0) {
throw "SignTool failed with exit code $LASTEXITCODE"
}
$signature = Get-AuthenticodeSignature -FilePath $output
if (-not $signature.SignerCertificate -or
$signature.SignerCertificate.Subject -cne $Publisher) {
throw 'MSIX signature does not match the manifest Publisher.'
}
}
New-Item -ItemType Directory -Path $verifyRoot -Force | Out-Null
& $makeAppx unpack /p $output /d $verifyRoot /o
if ($LASTEXITCODE -ne 0) {
throw "MakeAppx validation unpack failed with exit code $LASTEXITCODE"
}
[xml] $verifiedManifest = Get-Content (Join-Path $verifyRoot 'AppxManifest.xml') -Raw -Encoding UTF8
$ns = New-Object System.Xml.XmlNamespaceManager($verifiedManifest.NameTable)
$ns.AddNamespace('f', 'http://schemas.microsoft.com/appx/manifest/foundation/windows10')
$identity = $verifiedManifest.SelectSingleNode('/f:Package/f:Identity', $ns)
if (-not $identity) {
throw 'Validated MSIX does not contain a package Identity.'
}
if ($identity.Name -cne $IdentityName -or
$identity.Publisher -cne $Publisher -or
$identity.Version -cne $PackageVersion) {
throw 'Validated MSIX identity does not match the requested Store identity.'
}
foreach ($requiredPath in @(
'ZoiteChat\zoitechat.exe',
'ZoiteChat\plugins\hcnotifications-winrt.dll',
'ZoiteChat\plugins\hcchecksum.dll',
'ZoiteChat\plugins\hcexec.dll',
'ZoiteChat\plugins\hcfishlim.dll',
'ZoiteChat\plugins\hcsysinfo.dll',
'ZoiteChat\share\system.png',
'ZoiteChat\share\fonts\zoitechat\NotoColorEmoji.ttf',
'ZoiteChat\share\doc\zoitechat\fonts\OFL.txt',
'ZoiteChat\plugins\hclua.dll',
'ZoiteChat\plugins\hcperl.dll',
'ZoiteChat\plugins\hcpython3.dll',
'ZoiteChat\plugins\hcpython38.dll'
)) {
if (-not (Test-Path (Join-Path $verifyRoot $requiredPath))) {
throw "Validated MSIX is missing required file: $requiredPath"
}
}
foreach ($requiredPattern in @('_cffi_backend.cp314*.pyd', '_cffi_backend.cp38*.pyd')) {
$match = Get-ChildItem -Path (Join-Path $verifyRoot 'ZoiteChat') -Filter $requiredPattern -File -ErrorAction SilentlyContinue |
Select-Object -First 1
if ($null -eq $match) {
throw "Validated MSIX is missing required Python support file: $requiredPattern"
}
}
foreach ($requiredPythonFile in @('zoitechat.py', '_zoitechat.py', 'hexchat.py', 'xchat.py')) {
$path = Join-Path (Join-Path $verifyRoot 'ZoiteChat\python') $requiredPythonFile
if (-not (Test-Path $path)) {
throw "Validated MSIX is missing required Python bridge file: $requiredPythonFile"
}
}
foreach ($excludedPath in @(
'ZoiteChat\portable-mode',
'ZoiteChat\zoitechat-text.exe',
'ZoiteChat\plugins\hcupd.dll',
'ZoiteChat\WinSparkle.dll',
'ZoiteChat\share\download.png'
)) {
if (Test-Path (Join-Path $verifyRoot $excludedPath)) {
throw "MSIX incorrectly contains excluded file/directory: $excludedPath"
}
}
}
finally {
if ($certificate) {
Remove-Item -Path "Cert:\CurrentUser\My\$($certificate.Thumbprint)" -Force -ErrorAction SilentlyContinue
}
if (Test-Path $pfxPath) {
Remove-Item -Path $pfxPath -Force -ErrorAction SilentlyContinue
}
foreach ($path in @($stagingRoot, $verifyRoot)) {
if (Test-Path $path) {
Remove-Item -Path $path -Recurse -Force -ErrorAction SilentlyContinue
}
}
}
if (-not (Test-Path $output)) {
throw "Expected MSIX was not created: $output"
}
Write-Host "Created MSIX: $output"
-162
View File
@@ -1,162 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<!--
This MSI intentionally mirrors the staged portion of the normal Inno Setup
payload. Optional/custom-only files are excluded below. In particular,
portable-mode must never be harvested because copy.vcxproj always stages
that marker. Inno-only download-at-install components remain outside the MSI.
-->
<Package
Name="ZoiteChat"
Manufacturer="ZoiteChat"
Version="$(ProductVersion)"
UpgradeCode="{E9F09DF3-12FA-4BDF-A8AA-A6D62A327ED5}"
Scope="perMachine"
InstallerVersion="500"
Compressed="yes">
<MajorUpgrade
AllowSameVersionUpgrades="yes"
DowngradeErrorMessage="A newer version of ZoiteChat is already installed." />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<Icon Id="ZoiteChat.ico" SourceFile="$(sys.SOURCEFILEDIR)..\..\data\icons\zoitechat.ico" />
<Property Id="ARPPRODUCTICON" Value="ZoiteChat.ico" />
<Property Id="ARPHELPLINK" Value="https://github.com/ZoiteChat/zoitechat/issues" />
<Property Id="ARPURLINFOABOUT" Value="https://zoitechat.org/" />
<Property Id="ARPURLUPDATEINFO" Value="https://zoitechat.org/downloads.html" />
<Property Id="ARPNOMODIFY" Value="1" />
<!--
The Inno installer can bootstrap the VC++ runtime. A plain MSI should not
run an EXE prerequisite as an MSI custom action, so require the runtime.
Administrative extraction is allowed regardless of prerequisite state.
-->
<Property Id="VCREDIST_X64_INSTALLED">
<RegistrySearch
Id="FindVCRedistX64"
Root="HKLM"
Key="SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64"
Name="Installed"
Type="raw"
Bitness="always64" />
</Property>
<Launch
Condition="Installed OR ACTION = &quot;ADMIN&quot; OR VCREDIST_X64_INSTALLED = &quot;#1&quot;"
Message="Microsoft Visual C++ 2015-2022 x64 Redistributable is required before installing ZoiteChat." />
<Launch
Condition="Installed OR ACTION = &quot;ADMIN&quot; OR VersionNT64 &gt; 601 OR (VersionNT64 = 601 AND ServicePackLevel &gt;= 1)"
Message="ZoiteChat requires 64-bit Windows 7 SP1 or later." />
<StandardDirectory Id="ProgramFiles6432Folder">
<Directory Id="INSTALLFOLDER" Name="ZoiteChat" />
</StandardDirectory>
<StandardDirectory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="ZoiteChat" />
</StandardDirectory>
<Feature Id="MainFeature" Title="ZoiteChat" Level="1">
<ComponentGroupRef Id="ApplicationFiles" />
<ComponentRef Id="StartMenuShortcuts" />
<ComponentRef Id="ProtocolAndThemeAssociations" />
</Feature>
</Package>
<Fragment>
<ComponentGroup Id="ApplicationFiles">
<Files Directory="INSTALLFOLDER" Include="$(SourceDir)\**">
<!-- Created by copy.vcxproj for Inno's optional portable task only. -->
<Exclude Files="$(SourceDir)\portable-mode" />
<!-- Inno custom-only application component. -->
<Exclude Files="$(SourceDir)\zoitechat-text.exe" />
<!--
Keep the bundled utility and scripting plugins, including Python
3.14 and 3.8 support, available to non-Inno installations.
-->
</Files>
</ComponentGroup>
</Fragment>
<Fragment>
<Component Id="StartMenuShortcuts" Directory="ApplicationProgramsFolder" Guid="*">
<Shortcut
Id="ZoiteChatShortcut"
Name="ZoiteChat"
Description="ZoiteChat IRC client"
Target="[INSTALLFOLDER]zoitechat.exe"
WorkingDirectory="INSTALLFOLDER"
Icon="ZoiteChat.ico">
<ShortcutProperty Key="System.AppUserModel.ID" Value="ZoiteChat.Desktop.Notify" />
</Shortcut>
<Shortcut
Id="ZoiteChatSafeModeShortcut"
Name="ZoiteChat Safe Mode"
Description="Start ZoiteChat without auto-connect or plugins"
Target="[INSTALLFOLDER]zoitechat.exe"
Arguments="--no-auto --no-plugins"
WorkingDirectory="INSTALLFOLDER"
Icon="ZoiteChat.ico" />
<Shortcut
Id="ZoiteChatChangelogShortcut"
Name="ZoiteChat ChangeLog"
Target="[INSTALLFOLDER]changelog.url" />
<Shortcut
Id="ZoiteChatReadmeShortcut"
Name="ZoiteChat ReadMe"
Target="[INSTALLFOLDER]readme.url" />
<Shortcut
Id="ZoiteChatUninstallShortcut"
Name="Uninstall ZoiteChat"
Target="[System64Folder]msiexec.exe"
Arguments="/x [ProductCode]" />
<RemoveFolder Id="RemoveApplicationProgramsFolder" On="uninstall" />
<RegistryValue
Root="HKLM"
Key="Software\ZoiteChat\Installer"
Name="StartMenuShortcuts"
Type="integer"
Value="1"
KeyPath="yes" />
</Component>
</Fragment>
<Fragment>
<Component Id="ProtocolAndThemeAssociations" Directory="INSTALLFOLDER" Guid="*">
<RegistryValue
Root="HKCR"
Key="irc"
Type="string"
Value="URL:IRC Protocol"
KeyPath="yes" />
<RegistryValue Root="HKCR" Key="irc" Name="URL Protocol" Type="string" Value="" />
<RegistryValue Root="HKCR" Key="irc\DefaultIcon" Type="string" Value="[INSTALLFOLDER]zoitechat.exe,0" />
<RegistryValue Root="HKCR" Key="irc\shell" Type="string" Value="open" />
<RegistryValue
Root="HKCR"
Key="irc\shell\open\command"
Type="string"
Value="&quot;[INSTALLFOLDER]zoitechat.exe&quot; --url=&quot;%1&quot;" />
<RegistryValue Root="HKCR" Key=".zct" Type="string" Value="ZoiteChat.Theme" />
<RegistryValue Root="HKCR" Key=".hct" Type="string" Value="ZoiteChat.Theme" />
<RegistryValue Root="HKCR" Key="ZoiteChat.Theme" Type="string" Value="ZoiteChat Theme" />
<RegistryValue
Root="HKCR"
Key="ZoiteChat.Theme\DefaultIcon"
Type="string"
Value="[INSTALLFOLDER]zoitechat.exe,0" />
<RegistryValue
Root="HKCR"
Key="ZoiteChat.Theme\shell\open\command"
Type="string"
Value="&quot;[INSTALLFOLDER]zoitechat.exe&quot; &quot;%1&quot;" />
</Component>
</Fragment>
</Wix>