Skip to content

Commit

Permalink
Merge pull request #2 from tim-elmer/cscore
Browse files Browse the repository at this point in the history
Ringtones, documentation, cleanup
  • Loading branch information
tim-elmer authored Oct 9, 2020
2 parents 4d973d5 + 52652a5 commit 89aefe3
Show file tree
Hide file tree
Showing 32 changed files with 1,531 additions and 295 deletions.
18 changes: 3 additions & 15 deletions LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,8 @@ MIT License

Copyright (c) 2020 Timothy Elmer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51 changes: 35 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
# VoIPainter

## Description
VoIPainter is a simple Windows utility designed to change the background on a user's Cisco VoIP phone, without requiring access to the CUCM administrative backend.

VoIPainter is a simple Windows utility designed to change the background on a user's Cisco VoIP phone, without requiring access to the CUCM backend.
## Requirements / Caveats
- The phone must be _owned by_ the executing user in CUCM.
- _Personalization must be enabled_ on the phone in CUCM.
- _Web access must be enabled_ on the phone in CUCM (the commands are sent via HTTP).
- The executing user must have _local administrative privileges_; VoIPainter will open a socket on TCP port 80, which requires administrative rights.
- _caveat:_ Key Expansion Modules / Sidecars are currently not supported. They are listed in the specification, but it's not trivially obvious how to specify deployment of a KEM over the phone's wallpaper itself, if possible at all, and I don't have one to test with.

## **Requirements**
## Use
> Note that you may apply a background image, a ringtone, or both simultaneously.
- The phone must be owned by the executing user in CUCM.
- Personalization must be enabled on the phone in CUCM.
- The phone must have web access enabled in CUCM (the commands are sent to it via HTTP).
- The executing user must have *at least* local administrative privileges; VoIPainter will open a socket on TCP port 80, which requires administrative rights.
### Applying a Background Image
> Note that uncluttered, lower contrast images work best.
1. Click the "Browse Image" button to select an image.
1. Enter [required settings](#required-settings)
1. Click "Apply"

## Use
1. Open VoIPainter.
1. Use the "Browse For Image" button to navigate to and select the desired image. Keep in mind that uncluttered, lower contrast images work best.
1. Find your phone's IP address.[^1] Enter the address in the "Phone IP" field.
[^1]: This can typically be acquired from the phone's settings menu under "Phone Information", "Status", or similar. It should be in the form `0.0.0.0`.
1. Enter your domain username (e.g. Timothy Elmer -> telmer) in the "Username" field.
1. Enter your domain password in the "Password" field.
1. Select your phone model from the "Phone Model" dropdown. If you are unsure, the model is typically labeled on the back/bottom of the phone.
1. Click "Apply".
### Applying a Ringtone
> Note that the chosen media file will automatically be trimmed to the first 20 seconds (2 seconds on older phones). If you wish to use a specific part of a longer file, you can first cut it down using an audio editor such as [Audacity](https://www.audacityteam.org/).
1. Click the "Browse Ringtone" button to select an audio file.
1. Enter [required settings](#required-settings)
1. Click "Apply"

### Required Settings
| Setting | Explanation |
| ---: | --- |
| Phone IP | The IP address of your phone. This can typically be acquired from the phone's settings menu under "Phone Information", "Status", or similar. It should be in the form `0.0.0.0`. This can be acquired from the phone's settings menu under "Phone Information", "Status", or similar. |
| Username | Your domain username |
| Password | Your domain password |
| Phone Model | The model of your phone. If you are unsure, the model is typically labeled on the back/bottom of the device. |

## Settings
| Setting | Explanation |
| ---: | --- |
| Resize Mode | How under/oversized images will be treated: Stretch: The image will be stretched to fit the screen; **Crop (recommended)**: The largest dimension will be cropped on the center of the image to fit the screen; Center: The image will be scaled to fit, and centered on the screen.|
| Target Contrast | The maximum contrast that images should have. **The default value of `0.6` is recommended.** |
| Automatically Duck Contrast | If images with excessive contrast should have their contrast lowered.
| Ringtone Fade Out | How long the ringtone will fade out at the end. To not fade out, set to `0`. Must be between `0` and `20` seconds. |
21 changes: 21 additions & 0 deletions VoIPainter/ABOUT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
VoIPainter developed by Timothy Elmer under the MIT License:

Copyright (c) 2020 Timothy Elmer

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

For convenience, the licenses for associated works are linked below. They are also listed, in order of inclusion on this page, in the NOTICES.md file distributed with this Software.

VoIPainter uses code based on the work of Gareth Palmer; [how to request CGI execution on a Cisco VoIP phone](https://usecallmanager.nz/cgi-execute-xml.html), [specifications for Cisco VoIP phone background image requirements](https://usecallmanager.nz/image-list-xml.html), and [specifications for Cisco VoIP phone ringtone requirements](https://usecallmanager.nz/ring-list-xml.html). These works are unlicensed, but have been used for reference rather than reproduction.

VoIPainter uses the [ImageSharp](https://github.com/SixLabors/ImageSharp) library for image manipulation. ImageSharp licensed under the [Apache License 2.0](https://github.com/SixLabors/ImageSharp/blob/master/LICENSE).

VoIPainter uses the [NAudio](https://github.com/naudio/NAudio) library for audio manipulation. NAudio is licensed under the [MS-PL](https://github.com/naudio/NAudio/blob/master/license.txt).

VoIPainter uses the [Markdig](https://github.com/lunet-io/markdig) and [Neo.Markdig.Xaml](https://github.com/neolithos/NeoMarkdigXaml) libraries for Markdown rendering. These libraries are licensed under the [BSD 2-Clause](https://github.com/lunet-io/markdig/blob/master/license.txt) and [Apache-2.0](https://github.com/neolithos/NeoMarkdigXaml/blob/master/LICENSE.md) respectively.

VoIPainter is written in [.NET core](https://github.com/dotnet/core). .NET core is licensed under the [MIT license](https://github.com/dotnet/core/blob/master/LICENSE.TXT).
24 changes: 22 additions & 2 deletions VoIPainter/App.xaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Application x:Class="VoIPainter.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:VoIPainter.View">
<Application.Resources>
<Thickness x:Key="StandardMargin"
Left="2.5"
Expand All @@ -16,9 +17,14 @@
<Setter Property="Margin"
Value="{StaticResource StandardMargin}"/>
</Style>
<Style TargetType="TextBox">
<Style TargetType="TextBox"
x:Key="TextBoxStyle">
<Setter Property="Margin"
Value="{StaticResource StandardMargin}"/>
<Setter Property="TextWrapping"
Value="NoWrap"/>
<Setter Property="MaxLines"
Value="1"/>
</Style>
<Style TargetType="PasswordBox">
<Setter Property="Margin"
Expand All @@ -36,5 +42,19 @@
<Setter Property="Margin"
Value="{StaticResource StandardMargin}"/>
</Style>

<Style x:Key="textBoxInvalidated"
TargetType="TextBox"
BasedOn="{StaticResource TextBoxStyle}">
<Style.Triggers>
<Trigger Property="Validation.HasError"
Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>

<view:IsStringNotNullOrWhitespaceConverter x:Key="IsStringNotNullOrWhitespaceConverter"/>
</Application.Resources>
</Application>
12 changes: 11 additions & 1 deletion VoIPainter/Control/ImageReformatController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,26 @@ public class ImageReformatController : INotifyPropertyChanged
private readonly LogController _logController;
private Image _original;


/// <summary>
/// The path to the image
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "General exceptions caught for display to user")]
public string Path
{
get => _path;
set
{
_path = value;
_original = Image.Load(Path);
try
{
_original = Image.Load(Path);
}
catch (Exception e)
{
_logController.Log(new Entry(LogSeverity.Error, e.Message));
return;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Path)));
Format();
}
Expand Down
124 changes: 0 additions & 124 deletions VoIPainter/Control/ImageServerController.cs

This file was deleted.

31 changes: 29 additions & 2 deletions VoIPainter/Control/LogController.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,51 @@
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using VoIPainter.Model.Logging;

namespace VoIPainter.Control
{
/// <summary>
/// Handles logging
/// </summary>
public class LogController
public class LogController : IDisposable
{
private readonly StreamWriter _logStreamWriter;

/// <summary>
/// Entries in the log
/// </summary>
public ObservableCollection<Entry> LogEntries { get; private set; } = new ObservableCollection<Entry>();

public LogController()
{
_logStreamWriter = new StreamWriter(File.OpenWrite(".\\VoIPainter.log"));
}

/// <summary>
/// Log an entry
/// </summary>
/// <param name="entry">The entry</param>
public void Log(Entry entry)
{
if (entry is null)
throw new ArgumentNullException(nameof(entry));

System.Windows.Application.Current.Dispatcher.Invoke(() => LogEntries.Add(entry));
System.IO.File.AppendAllText(".\\VoIPainter.log", string.Format(CultureInfo.InvariantCulture, $"{Strings.LogFormat}\r\n", entry.Time, entry.Severity, entry.Message));
_logStreamWriter.WriteLine(string.Format(CultureInfo.InvariantCulture, $"{Strings.LogFormat}\r\n", entry.Time, entry.Severity, entry.Message));
}

protected virtual void Dispose(bool disposeManaged)
{
if (disposeManaged)
_logStreamWriter.Dispose();
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
10 changes: 7 additions & 3 deletions VoIPainter/Control/MainController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ public class MainController
private static MainController _instance;

public SettingsController SettingsController { get; }

public LogController LogController { get; } = new LogController();
public ImageServerController ImageServerController { get; }
public ServerController ImageServerController { get; }
public RequestController RequestController { get; }
public UpdateCheckController UpdateCheckController { get; }
public ImageReformatController ImageReformatController { get; }
public RingtoneReformatController RingtoneReformatController { get; }
public View.MainWindow MainWindow { get; }

public MainController()
Expand All @@ -24,12 +24,16 @@ public MainController()
throw new InvalidOperationException();
_instance = this;

#region Initialize
SettingsController = new SettingsController(LogController);
ImageReformatController = new ImageReformatController(this);
ImageServerController = new ImageServerController(this);
RingtoneReformatController = new RingtoneReformatController(this);
ImageServerController = new ServerController(this);
RequestController = new RequestController(this);
UpdateCheckController = new UpdateCheckController(LogController);
MainWindow = new View.MainWindow(this);
#endregion Initialize

MainWindow.Show();
}
}
Expand Down
Loading

0 comments on commit 89aefe3

Please sign in to comment.