IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Servlets/JSP Java Discussion :

Impossible de supprimer/fermer un fichier en cours d'utilisation par Java Platform SE binary


Sujet :

Servlets/JSP Java

  1. #1
    Nouveau membre du Club
    Femme Profil pro
    Analyste Concepteur SI
    Inscrit en
    Septembre 2011
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Analyste Concepteur SI
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 37
    Points : 37
    Points
    37
    Par défaut Impossible de supprimer/fermer un fichier en cours d'utilisation par Java Platform SE binary
    Plop !

    J'ai un genre de drive où je peux uploader/downloader/visualiser des fichiers en ligne.

    Mon problème survient lorsque que je tente de supprimer un fichier qui a déjà été visualisé sur mon site. Si je ne visualise pas le fichier je peux le supprimer.

    Dans le cas où la suppression ne fonctionne pas je reçoit une erreur:
    Unable to delete file: c:\Users\MyPC\chemindemonfichier\fichier.extension
    Etant donné que je stocke les fichiers dans un dossier dont j'ai l'accès j'ai essayé de le supprimer manuellement. Windows me donne l'erreur suivante (tant que mon servlet est lancé):
    Nom : scree.png
Affichages : 2187
Taille : 7,1 Ko

    On voit bien que le fichier est encore ouvert dans ma servlet. Le problème c'est que j'utilise que java.io.File et org.springframework.web.multipart.MultipartFile pour manipuler mes fichiers. Dans les deux cas on n'a pas besoin de fermer/ouvrir le fichier puisqu'on ne manipule qu'une "image" de celui-ci.

    org.springframework.web.multipart.MultipartFile


    A representation of an uploaded file received in a multipart request.

    The file contents are either stored in memory or temporarily on disk. In either case, the user is responsible for copying file contents to a session-level or persistent store as and if desired. The temporary storages will be cleared at the end of request processing.
    Le seul endroit ou j'ouvre un inputstream est dans le cas d'un chargement de fichier sur mon serveur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    	@RequestMapping(value="/downloadFile", method = RequestMethod.POST)
    	public void  handleDonwloadFile(HttpServletRequest request, HttpServletResponse response, RedirectAttributes redir)
    	{
    		Authentication 		auth = SecurityContextHolder.getContext().getAuthentication();
    		String 				name = auth.getName();
    		User 				user = service.getUsersFromLogins(name);
    		String				fileName = request.getParameter("dlfilename");
    		InputStream			inputStream = null;
     
    		try 
    		{
    	        String filePathToBeServed = user.getUsr_folderpath()+"/"+request.getParameter("dlfilename");
    	        File fileToDownload = new File(filePathToBeServed);
    	        inputStream = new FileInputStream(fileToDownload);
    	        response.setContentType("application/force-download");
    	        response.setHeader("Content-Disposition", "attachment; filename="+fileName); 
    	        IOUtils.copy(inputStream, response.getOutputStream());
    	        response.flushBuffer();
    	        inputStream.close();
    	    } 
    		catch (Exception e)
    		{System.out.println("[BillingController]:HandleDownloadFile: "
    				+ "Request could not be completed at this moment. Please try again.");}
    		finally 
    		{ 
    			if (inputStream != null)
    			{
    				try 
    				{ inputStream.close(); } 
    				catch (IOException e) 
    				{ System.out.println("[BillingController]:HandleDownloadFile: Failed to close streams"); }
    			}
    		}
    	}
    Le code de mon visualiseur de fichier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    							<c:choose>
    									<c:when test="${fileExtension == 'application/vnd.ms-excel'}">
    										<object data="rootfolder/<sec:authentication property="principal.username" />/${fileName}"
    											type="${fileExtension}" width="100%" style="height:50em">
    										</object>
    									</c:when>
    									<c:when test="${fileExtension == 'application/pdf'}">
    										<object data="rootfolder/<sec:authentication property="principal.username" />/${fileName}" 
    											type="${fileExtension}" width="100%" style="height:50em"> 
    										</object>
    									</c:when>
    									<c:when test="${(fileExtension == 'image/png') ||  (fileExtension == 'image/jpg')}">
    										<img src="rootfolder/<sec:authentication property="principal.username" />/${fileName}" width="100%" style="height:50em"/>
    									</c:when>
    									<c:otherwise>
    										<div class="alert alert-danger" role="alert">
    											<span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span>
    				                			<spring:message code="billing.message.error.notsupported"/>
    				            			</div>
    									</c:otherwise>
    								</c:choose>
    Le code de suppression:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    		Authentication 		auth = SecurityContextHolder.getContext().getAuthentication();
    		String 				name = auth.getName();
    		User 				user = service.getUsersFromLogins(name);
    		String				fileName = request.getParameter("deletefilename");
    		File 				folder;
     
     
        	File file = new File(user.getUsr_folderpath()+"/"+fileName);
        	try {
    			org.apache.commons.io.FileDeleteStrategy.FORCE.delete(file);
        		redir.addFlashAttribute("deleteSucced", message.getMessage("billing.message.success.delete", 
    					new String[]{file.getName()}, Locale.getDefault()));
    		} catch (IOException e) {
        		redir.addFlashAttribute("deleteFailed", message.getMessage("billing.message.error.delete", 
    			new String[]{file.getName()}, Locale.getDefault()));
        		System.out.println(e.getMessage());
    		}
    Après de longue recherche je ne vois pas bien où est-ce que je pourrais fermer le fichier...

    Merci de votre aide

  2. #2
    Membre confirmé
    Avatar de provirus
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2009
    Messages
    248
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2009
    Messages : 248
    Points : 580
    Points
    580
    Par défaut
    Bonjour,

    un point qui n'aidera pas, mais qui est important, dans le try, vous fermez le fichier et dans le finally, vous le refermez. Laissez la fermeture uniquement dans le finally puisqu'il est toujours appelé.

    Ensuite, quand vous recevez un fichier, il est dans un MultipartFile et vous le copiez dans un endroit non temporaire. Quel est votre code de la copie? Peut-être qu'il n'est pas bien fermé à cet endroit.

  3. #3
    Nouveau membre du Club
    Femme Profil pro
    Analyste Concepteur SI
    Inscrit en
    Septembre 2011
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Analyste Concepteur SI
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 37
    Points : 37
    Points
    37
    Par défaut
    Bonjour,

    Merci pour votre réponse .

    Citation Envoyé par provirus Voir le message
    un point qui n'aidera pas, mais qui est important, dans le try, vous fermez le fichier et dans le finally, vous le refermez. Laissez la fermeture uniquement dans le finally puisqu'il est toujours appelé.
    Effectivement lors de mes tests j'ai un peu tout essayé et j'ai laisser mon close dans le try et le finally.

    Citation Envoyé par provirus Voir le message
    Ensuite, quand vous recevez un fichier, il est dans un MultipartFile et vous le copiez dans un endroit non temporaire. Quel est votre code de la copie? Peut-être qu'il n'est pas bien fermé à cet endroit.
    Je suppose que vous faites allusion à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IOUtils.copy(inputStream, response.getOutputStream());
    IOutils.copy proviens de org.apache.commons.io.IOutils.copy

    EDIT:

    Après réflexion j'ai oublié de fermer mon l'outputStrem j'ai donc ajouter ce code dans le finally:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    try {IOUtils.closeQuietly(response.getOutputStream());} 
    catch (IOException e) 
    {System.out.println("[BillingController]: HandleDownloadFile: Failed to close IOutils");}
    Cependant cela ne résout pas mon problème. Lorsque je visualise les fichiers, la fonction de download n'est pas appelée et je ne peux quand même pas supprimer le fichier.

  4. #4
    Membre confirmé
    Avatar de provirus
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2009
    Messages
    248
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2009
    Messages : 248
    Points : 580
    Points
    580
    Par défaut
    Citation Envoyé par Fuzo13 Voir le message
    Je suppose que vous faites allusion à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IOUtils.copy(inputStream, response.getOutputStream());
    non, ça c'est la partie que vous envoyer un fichier ; pas la partie quand vous le recevez. (je parle de quand un utilisateur upload un fichier sur votre serveur et que vous utilisez le MultipartFile que vous avez décris dans votre message initial.

  5. #5
    Nouveau membre du Club
    Femme Profil pro
    Analyste Concepteur SI
    Inscrit en
    Septembre 2011
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Analyste Concepteur SI
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 37
    Points : 37
    Points
    37
    Par défaut
    l'Upload ce fait uniquement avec les l'objet File donc pas besoin de le fermer normalement. Peut être que je suis passée à côté de quelques chose...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public String handleFileUpload(@RequestParam("uploadfile") MultipartFile file, RedirectAttributes redir)
    	{
    		SmartFolderManager	folderManager = new SmartFolderManager();
    		SmartFileUpload 	fileManager = new SmartFileUpload();
    		Authentication 		auth = SecurityContextHolder.getContext().getAuthentication();
    		String 				name = auth.getName();
    	    User 				user = service.getUsersFromLogins(name);
    	    SmartFileUpload 	fileUpload = new SmartFileUpload();
    		File 				folder;
     
    	    fileUpload.setUPLOAD_FILE_PATH(user.getUsr_folderpath()+"/");
    		//Refreshing billing file-lsiting and viewer
    	    if(user.getUsr_folderpath() != null)
    		{
    			folder = new File(user.getUsr_folderpath());
    			folderManager.listFilesForFolder(folder);
    			redir.addFlashAttribute("fileName", folderManager.getFiles().get(0));
    			redir.addFlashAttribute("fileExtension", fileManager.getFileType(folderManager.getFiles().get(0)));
    			redir.addFlashAttribute("filesList", folderManager.getFiles());
    		}
    	    else
    	    	redir.addFlashAttribute("noFolder", message.getMessage("billing.message.error.nofolder", null, Locale.getDefault()));
    	    return "redirect:/welcome?facturation="+fileUpload.process(file);
    	}
    SmartFileUpload/process:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    	public String process(MultipartFile file) 
    	{
            if (!file.isEmpty()) 
            {
                String contentType = file.getContentType().toString().toLowerCase();
                if (isValidContentType(contentType)) 
                {
                    if (belowMaxFileSize(file.getSize())) 
                    {
                        String newFile = UPLOAD_FILE_PATH + file.getOriginalFilename();
                        try 
                        {
                            file.transferTo(new File(newFile));
                            return "uploaded";
                        } 
                        catch (IllegalStateException e) 
                        	{return "uploaderror";} 
                        catch (IOException e) 
                        	{return "uploaderror";}
                    } 
                    else
                    	return "size";
                } 
                else
                	return "syntax";
            } 
            else
                return "notfound";
        }
    SmartFolderManager:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    public class SmartFolderManager {
     
    	private ArrayList<String> files = new ArrayList<String>();
     
    	public void listFilesForFolder(final File folder) 
    	{
    	    for (final File fileEntry : folder.listFiles()) 
    	    {
    	        if (fileEntry.isDirectory())
    	            listFilesForFolder(fileEntry);
    	        else
    	        	files.add(fileEntry.getName());
    	    }
    	}
     
    	public List<String> getFiles() 
    	{
    		return files;
    	}
    }

  6. #6
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    C'est bien uniquement après un passage dans handleDonwloadFile que tu ne peux plus le supprimer? Et si tu réessaie quelques minutes plus tard tu peux l'effacer. InputStream.close() avait (je ne sais pas si c'est corrigé depuis) la réputation de ne pas cloturer immédiatement les stream mais d'attendre un garbage collect.

    Aussi, ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	        String filePathToBeServed = user.getUsr_folderpath()+"/"+request.getParameter("dlfilename");
    est dangereux, j'auras vite fais de tenter de télécharger "../../management-users.xml" ou autre joyeuseté assimilée

  7. #7
    Nouveau membre du Club
    Femme Profil pro
    Analyste Concepteur SI
    Inscrit en
    Septembre 2011
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Analyste Concepteur SI
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 37
    Points : 37
    Points
    37
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    C'est bien uniquement après un passage dans handleDonwloadFile que tu ne peux plus le supprimer? Et si tu réessaie quelques minutes plus tard tu peux l'effacer. InputStream.close() avait (je ne sais pas si c'est corrigé depuis) la réputation de ne pas cloturer immédiatement les stream mais d'attendre un garbage collect.
    C'est lorsque j'ai visualisé le fichier que je ne peux plus le supprimer sinon aucun problème de suppression.

    Citation Envoyé par tchize_ Voir le message
    Aussi, ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	        String filePathToBeServed = user.getUsr_folderpath()+"/"+request.getParameter("dlfilename");
    est dangereux, j'auras vite fais de tenter de télécharger "../../management-users.xml" ou autre joyeuseté assimilée
    Qu'est ce que vous suggérer pour ne pas avoir de problème de sécurité ?

    Peut être quelques chose comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
              File fileToDownload = new File(user.getUsr_folderpath()+"/"+request.getParameter("dlfilename"));
    pour ne pas avoir une variable contenant le chemin complet.

  8. #8
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par Fuzo13 Voir le message
    C'est lorsque j'ai visualisé le fichier que je ne peux plus le supprimer sinon aucun problème de suppression.
    Oui, mais concrètement la différence entre je peux supprimer et je ne peux pas supprimer est uniquement un passage par "handleDonwloadFile" ou il y a d'autres choses impliquée dans "visualiser le fichier" ? (filtres, process front end de sélection de fichier, que sais-je)


    Citation Envoyé par Fuzo13 Voir le message
    Qu'est ce que vous suggérer pour ne pas avoir de problème de sécurité ?
    En général, je stockerais le nom du fichier créé dans une db et je vérifierais que le fichier existe bien dans la db.

    Même problème avec ton smartfileupload accessoirement, il utilise aveuglément le filename fournis par le browser, et tu auras de belles surprises avec opera qui va dire "le nom de fichier c'est c:\Users\tom\Documents and Settings\My Documents\facturation123.pdf". Quand tu sauve un fichier uploadé, donne lui un nom que tu choisi, pas celui que le browser choisi.

    Citation Envoyé par Fuzo13 Voir le message
    Peut être quelques chose comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
              File fileToDownload = new File(user.getUsr_folderpath()+"/"+request.getParameter("dlfilename"));
    pour ne pas avoir une variable contenant le chemin complet.
    ca ne change strictement rien, je peux faire un new File("/chemin/vers/stockage/../../etc/passwd") ça marchera.

  9. #9
    Nouveau membre du Club
    Femme Profil pro
    Analyste Concepteur SI
    Inscrit en
    Septembre 2011
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Analyste Concepteur SI
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 37
    Points : 37
    Points
    37
    Par défaut
    Le handleDownloadFile comme sont nom l'indique n'est appelé que lorsqu'on essaye de télécharger un fichier pas dans le cas d'une visualisation.
    Le problème ici viens du fait qu'après une visualisation donc passage

    ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @RequestMapping(value="/viewFile", method = RequestMethod.POST)
    	public String handleViewFile(HttpServletRequest request, RedirectAttributes redir)
    	{
    		SmartFolderManager	folderManager = new SmartFolderManager();
    		SmartFileUpload 	fileManager = new SmartFileUpload();
    		Authentication 		auth = SecurityContextHolder.getContext().getAuthentication();
    		String 				name = auth.getName();
    		User 				user = service.getUsersFromLogins(name);
    		File 				folder;
    		String				fileName = request.getParameter("viewfilename");
     
    		//Refreshing billing file-lsiting and viewer
    		if(user.getUsr_folderpath() != null)
    		{
    			folder = new File(user.getUsr_folderpath());
    			folderManager.listFilesForFolder(folder);
    			redir.addFlashAttribute("filesList", folderManager.getFiles());
    			redir.addFlashAttribute("fileExtension", fileManager.getFileType(fileName));
    			redir.addFlashAttribute("fileName", fileName);
    		}
    		else
    		    redir.addFlashAttribute("noFolder", message.getMessage("billing.message.error.nofolder", null, Locale.getDefault()));
    		return "redirect:/welcome?facturation";
    	}
    et ici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    							<c:otherwise>
    								<c:choose>
    									<c:when test="${fileExtension == 'application/vnd.ms-excel'}">
    										<object data="rootfolder/<sec:authentication property="principal.username" />/${fileName}"
    											type="${fileExtension}" width="100%" style="height:50em">
    										</object>
    									</c:when>
    									<c:when test="${fileExtension == 'application/pdf'}">
    										<object data="rootfolder/<sec:authentication property="principal.username" />/${fileName}" 
    											type="${fileExtension}" width="100%" style="height:50em"> 
    										</object>
    									</c:when>
    									<c:when test="${(fileExtension == 'image/png') ||  (fileExtension == 'image/jpg')}">
    										<img src="rootfolder/<sec:authentication property="principal.username" />/${fileName}" width="100%" style="height:50em"/>
    									</c:when>
    									<c:otherwise>
    										<div class="alert alert-danger" role="alert">
    											<span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span>
    				                			<spring:message code="billing.message.error.notsupported"/>
    				            			</div>
    									</c:otherwise>
    								</c:choose>
    En général, je stockerais le nom du fichier créé dans une db et je vérifierais que le fichier existe bien dans la db.

    Même problème avec ton smartfileupload accessoirement, il utilise aveuglément le filename fournis par le browser, et tu auras de belles surprises avec opera qui va dire "le nom de fichier c'est c:\Users\tom\Documents and Settings\My Documents\facturation123.pdf". Quand tu sauve un fichier uploadé, donne lui un nom que tu choisi, pas celui que le browser choisi.
    Pour ce qui est du filename ce n'est pas le navigateur qui récupère le nom de mes fichiers. Ils sont listés sur mon site pour permettre à l'utilisateur de les sélectionner mais le chemin du dossier où ils sont enregistrés est dans ma base de donnée.

Discussions similaires

  1. [XL-2007] Fichier en cours d'utilisation par "un autre utilisateur"
    Par Kimy_Ire dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 10/04/2015, 21h20
  2. fichier en cours d'utilisation par autre processus
    Par ritavsky dans le forum VB.NET
    Réponses: 4
    Dernier message: 05/05/2010, 11h10
  3. Ouvrir un Fichier et fermer le fichier en cours
    Par jojo86 dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 18/01/2010, 16h59
  4. Réponses: 4
    Dernier message: 04/09/2008, 16h55
  5. [DOM] Fichier en cours d'utilisation - Suppression impossible
    Par schniouf dans le forum Format d'échange (XML, JSON...)
    Réponses: 2
    Dernier message: 15/12/2006, 13h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo